2009/08/17


ずいぶん前からXMLRPCをC++で扱うのに小さいライブラリないかなーと思ってました。


書いたといっても結構前からあったのですが、いらん所を削ぎ落として簡素なXMLRPCライブラリとして仕立て上げました。
簡素とは言えど、一般的な物ならば色々動きます。
例えば、ブログに一気に、しかも機械的にポストしたい場合とか

おれは今すぐXMLRPCしたいんだ!そしてどうしてもC++でXMLRPCしたいんだー!

って事ないですか?MovablebTypeをインストールしたけど、XMLRPCするのにC++コンパイラは入ってるけど、PerlやRubyやPythonは入ってない...とか悲しすぎます。
今回紹介する"tinyxmlrpc"はそんな、小さい様で大きな問題を解決出来るかもしれないライブラリです。
mattn's tinyxmlrpc at master - GitHub

tiny xmlrpc library written in C++

http://github.com/mattn/tinyxmlrpc/tree/master
今githubが不調でpushが反映されていません。リポジトリからのcloneは出来る様です。
ソースはC++で書いてます。WindowsとUNIX(Linuxでだけ動作確認)で動作します。

機能としては、STLのvectorとかmapとかに親和性高くなる様になっています。内部ではlibxmlでパースしていてcurlで通信しています。
小ささをウリにしていますが、libxmlとcurlのリンクは必須です。
サンプルコードを以下に示します。
#include "tinyxmlrpc.h"
#include <iostream>

class vargs {
private:
    tinyxmlrpc::value::Array args_;
public:
    vargs& operator <<(tinyxmlrpc::value arg) {
        args_.push_back(arg);
        return *this;
    }
    tinyxmlrpc::value::Array& list() {
        return this->args_;
    }
    vargs& first() {
        this->args_.clear();
        return *this;
    }
};

int main(int argc, char* argv[]) {
#ifdef _WIN32
    WSAData wsadata;
    WSAStartup(MAKEWORD(2,0), &wsadata);
#endif

    if (argc != 4) return -1;

    std::string endpoint = argv[1];
    std::string user = argv[2];
    std::string pass = argv[3];

    try {
        tinyxmlrpc::value::Array req;
        tinyxmlrpc::value res;
        tinyxmlrpc::value::Struct entry;
        vargs args;

        res = tinyxmlrpc::call(endpoint,
                "metaWeblog.getRecentPosts",
                (args.first() << "1" << user << pass << 3 << true).list());
        if (!tinyxmlrpc::failed(res)) {
            for(int n = 0; n < res.size(); n++) {
                std::vector<std::string> members = res[n].listMembers();
                std::vector<std::string>::const_iterator it;
                std::cout << "{" << std::endl;
                for(it = members.begin(); it != members.end(); it++) {
                    std::string val = res[n][*it].to_str();
                    std::cout << "  " << it->c_str() << "=" << val.c_str() << std::endl;
                }
                std::cout << "}" << std::endl;
            }
        } else {
            std::cerr << res << std::endl;
        }

        entry["title"] = "hasegawaにいじめられた";
        entry["description"] = "今日は、wassrでhasegawaにいじめられた。悲しかった。";
        entry["dateCreated"] = "";
        res = tinyxmlrpc::call(
                endpoint,
                "metaWeblog.newPost",
                (args.first() << "1" << user << pass << entry << 1).list());
        if (!tinyxmlrpc::failed(res)) {
            std::cout << "result:" << res << std::endl;
        } else 
            std::cerr << res << std::endl;
    } catch(tinyxmlrpc::value::Exception& e) {
        std::cerr << e.message << std::endl;
    }

    return 0;
}

これを使ってコマンドラインから引数として、MetaWeblogをサポートしているブログのエンドポイントURLユーザパスワードを指定すると、「hasegawaにいじめられた」というエントリがポストされます。
タイトルや本文に、特に意味はありません。すごいですね!


ライセンスはまだ決めてませんが、今のところBSDを予定しています。使ってみて下さい。
コードはgithubにあるので、patchウェルカムです。
今後は、この記事の為だけに仕上げた疑いのある汚いコードを綺麗にしていくつもりです。

参考文献:C++で軽量Webサーバ書いた。
Posted at by




ReverseHttp面白いですね。
ReverseHttp

Tunnel HTTP over HTTP, in a structured, controllable, securable way. Let programs claim part of URL space, and serve HTTP, all by using an ordinary HTTP client library.

http://www.reversehttp.net/
ただ勘違いされやすいのが「何がReverseなの」という部分。通常ブラウザからリクエストが送信され、それに対する応答がサーバから返されます。ReverseHttpはサーバで何かアクションが起きた場合に、ブラウザ側がその通知を受信する...なんて事が出来るプロトコルです。仕組みはcometというlong pollに似た仕組みで、サイトのdemoを観るとなんなく理解出来るかと思います。
例えば何が出来るのか...

ローカルPC内で動作するファイアウォール内のwebアプリを外部に公開する

rubyにhookoutというライブラリがあり、これを使用するとrackアプリがさも外部に公開されているかの様に振舞う事が出来ます。
paulj's hookout at master - GitHub

Expose Ruby applications to the web via ReverseHTTP

http://github.com/paulj/hookout/tree/master
グローバルIPが無くても、webアプリを公開出来るなんて素晴らしい!
なお、ReverseHttpはプロトコルですのでhookout以外にも同様のソフトウェアはあります。例えばmiyagawaさんが書いたAnyEvent::ReverseHttpに含まれるeg/proxy.plを使うとローカルPC内のwebアプリを外部に公開する事が出来ます。

外部で起きたアクションをローカルPCに通知させる

例えば、はてなブックマークで自分のサイトがブックマークされた瞬間にデスクトップPCが反応したらどうしますか?
スターを付けに行きませんか(笑)?ReverseHttpを使えば出来るのです。


今日はこの「はてなブックマーク通知」をやってみたいと思います。
使う材料は以下の通り。
  • hookout : 上記で紹介したrackアプリを公開するライブラリ
  • sinatra : ruby製webアプリケーションフレームワーク
  • ruby_gntp : snakaさん作のruby用Growl For Windowsインタフェース
こんだけ。
上記のサイトからhookoutを取得してインストールし、以下のsinatraアプリケーションを作成します。
my-hatebu-growler.rb
require 'rubygems'
require 'sinatra'
require 'ruby_gntp'
  
growl = GNTP.new
growl.register({
  :app_name => "はてブ",
  :notifies => [{
   :name     => "hatenabookmark",
    :enabled  => true,
  }]
})

post '/' do
  return "ng" if params[:status] !~ /add|update/
  user = params[:username]
  text = "#{params[:comment]}\r\r#{params[:title]}\r#{params[:url]}"
  icon = "http://www.hatena.ne.jp/users/#{user[0,2]}/#{user}/profile.gif"
  p params[:status]
  growl.notify({
    :name  => "hatenabookmark",
    :title => user,
    :text  => text,
    :icon  => icon,
  })
  'ok'
end
config.ru
require 'my-hatebu-growler'
set :run, false
run Sinatra::Application
これを以下の様に起動します。
hookout -a http:/www.reversehttp.net/reversehttp -n my-hatebu-growler-application -R config.ru start

my-hatebu-growler-applicationの部分は適当な物に変えて下さい。

起動すると以下の様に出力されます。
Bound to location http://my-hatebu-growler-application.www.reversehttp.net/
このURLを、はてなブックマークにwebhook登録します。
hatebu-webhook
あとは、じっとブクマされるのを待ちます。










hatebu-growler
デタ━━━゚(∀)゚━━━!!

秋の夜長に、こんなツールお一つどうでしょうか。


追記1
HTTP::Engine::Interface::ReverseHTTPもあるよとmiyagwawaさんに教えてもらいました。
hookout for HTTP::Engineらしいです。

追記2
例では分かり易くする為にwebhook APIのキー認証を省いていますが、本当はちゃんと判定する必要があります。

追記3
PerlでHTTP::Engine::Interface::ReverseHTTPを使ってみた。ネットワークGrowlにはアイコンが使える仕組みがないのが残念。
Posted at by



2009/08/16


furyu-teiさんの記事でXSLTの場合はendpointを変えないといけない事が分かった。
AmazonのProduct Advertising API認証プロキシ(REST版・GAE用)ソース

XSLTを使用する場合(Styleオプション指定時)、http://webservices.amazon.co.jp/onca/xmlやhttp://ecs.amazonaws.jp/onca/xmlで指定すると認証エラーに。専用のエンドポイント(http://xml-jp.amznxslt.com/onca/xml)の指定が必要らしい。

http://d.hatena.ne.jp/furyu-tei/20090703/paproxy
お陰様で動くようになりました。
XSLとjQuery/HTMLだけで作る、amazon最速検索
Posted at by