mruby-maxminddb という mgem を作った話
このブログは mruby Advent Calendar 2016 の 21 日めの記事です。
最近,と言っても少し前ですが,mgem を作りました.
作った mgem の名前は mruby-maxminddb って言います.
GioIP の DB である maxminddb を読み書きする Gem です.
MaxMindDbDat = "/tmp/GeoLite2-City.mmdb" IPAddr = '8.8.8.8' maxminddb = MaxMindDB.new MaxMindDbDat maxminddb.lookup_string IPAddr maxminddb.country_code #=> US maxminddb.region #=> CA maxminddb.region_name #=> California maxminddb.city #=> Mountain View maxminddb.postal_code #=> 94035 maxminddb.latitude #=> 37.386 maxminddb.longitude.round(4) #=> -122.0838 maxminddb.metro_code #=> 807 maxminddb.time_zone #=> America/Los_Angeles
などのように利用します。
例えば,Webサーバーやメールサーバーのスパム対策に利用できるかと思います。
幸いにも maxminddb を利用するための C 言語のライブラリがあったので,こちらをラップする形で実装していきました。 libmaxmind と言います。
libmaxmind はドキュメントが充実しており,それらを参考に実装していきました。
また, maxminddb をダンプするための mmdblookup というツールも同梱されており,そちらのコードはとても参考になりました。 ほぼ,このツールの動作を模倣する形で実装を進めていきました。
static mrb_value mrb_maxminddb_lookup_string(mrb_state *mrb, mrb_value self) { mrb_maxminddb_data *data = DATA_PTR(self); char *ipaddr = NULL; mrb_get_args(mrb, "z", &ipaddr); data->host = ipaddr; data->lookup_result_s = MMDB_lookup_string(&(data->mmdb), data->host, &(data->gai_error), &(data->mmdb_lookup_error)); if (0 != data->gai_error) { mrb_raise(mrb, E_RUNTIME_ERROR, gai_strerror(data->gai_error)); } if (MMDB_SUCCESS != data->mmdb_lookup_error) { mrb_raise(mrb, E_RUNTIME_ERROR, "Lookup Error"); } return self; }
例えば,上記のようなコードは, mmdblookup.c の似た関数を模倣して実装しています。
mgem として実装するので,エラーが発生したときに mrb_raise を返すところや, 構造体に MMDB_lookup_string の戻り値を格納しているところが違うぐらいです。
その構造体は mruby で C 言語の構造体をラップしたオブジェクトを作る正しい方法 を参考にして mruby のオブジェクトとしてラップしています。
mruby-maxminddb は初めて C 言語で mgem を作るには手頃なお題でした。 libmaxminddb というライブラリもあり,ドキュメントも充実しており,参考にできるコードも同梱されていました。
mgem を作るにあたって参考になるブログもありました。
来年も,幾つか mgem を開発していきたいと思います。
以上です。