月別アーカイブ: 2015年1月

Web APIのリトライ処理実装

Web系のAPIをたたいていると、たまにエラーが発生することがあります。要因はサーバー側がたまたまおかしかったり、proxyだったりと様々です。

エラー時にはリトライしつつAPIをたたく方法はいろいろ考えられますが、C#でのスマートな実例がStackOverflowで紹介されていました。リトライ専用のクラスとstaticメソッドを実装して、呼出にはデリゲート、ラムダ式を用いるという手法です。

Rubyでも同様の処理を行うコードを考えてみました。

class Retry
  @count = 10
  @wait = 60
  def self.do(func)
    ret = nil
    ex = nil
    for i in 1..@count do
      begin
        ret = func.call
        sleep(1)
        return ret
      rescue => e
        ret = nil
        ex = e
        sleep(@wait)
      end
    end
    if (!ex.nil?)
      ex = Exception.new
    end
    throw ex
  end
end

CVE-2008-0166の爪痕

偶然にも500万個のSSH公開鍵を手に入れた俺たちはという資料が公開されました。GitHubから公開鍵を大量に集めて調査してみたという内容なのですが、なかなか衝撃的だったので英語blogで内容をかいつまんで紹介してみました。

500万個のssh公開鍵のうち、Debian/Ubuntuで作成されたブラックリスト入りの鍵が208件あったそうです。割合として考えてみればそれほど多くはないのですが、まだ爪痕が残っていることを実感します。

ELECOM UCAM-C0220Fを使う

ふと思うところがあって、安価なUSBカメラを購入しました。エレコムの200万画素で安価(1000円程度)なモデルです。

最終的な目的の用途とは異なるのですが、とりあえず自宅の様子をストリーミングさせてみました。かつてはgstreamerを使っていろいろと余計な苦労をする羽目になったのですが(Google Slideの資料9ページ目参照)、いまどきはffmpeg/libavを使ってVorbis/TheoraやWebMにエンコードし、icecastに配送させるのが簡単だと思います。

このデバイスは映像入力をUVCクラス、音声(マイク)入力をAudioクラスとした複合デバイスに見えます。

 % lsusb
Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 002: ID 8564:1000
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 004: ID 056e:7016 Elecom Co., Ltd
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
 % arecord -L
null
    Discard all samples (playback) or generate zero samples (capture)
default:CARD=UCAMC0220F
    UCAM-C0220F, USB Audio
    Default Audio Device
sysdefault:CARD=UCAMC0220F
    UCAM-C0220F, USB Audio
    Default Audio Device
front:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    Front speakers
surround40:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    4.0 Surround output to Front and Rear speakers
surround41:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    4.1 Surround output to Front, Rear and Subwoofer speakers
surround50:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    5.0 Surround output to Front, Center and Rear speakers
surround51:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    5.1 Surround output to Front, Center, Rear and Subwoofer speakers
surround71:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
iec958:CARD=UCAMC0220F,DEV=0
    UCAM-C0220F, USB Audio
    IEC958 (S/PDIF) Digital Audio Output

ffmpegでalsaデバイスとしてこのオーディオデバイスを使うと、定期的に”[alsa @ 0x15fcc00] ALSA buffer xrun.”というエラーが出ます。どうもUSB audioとしての動作が何かおかしいようです。この状態でoggfwdを続けていると、icecast側から接続を切られてしまいます。まあ自分の主目的は映像をとることなのでその用途には十分使えそうです。

Webアプリを立てて外部から作業しやすくする

WX310K、いわゆる京ポン2を持って以降、出先でのWeb閲覧がお手軽にできるようになってからNexus5を持つ現在へと至っていますが、スマホ・タブレット時代になって相当リッチなWebアプリも動かせるようになりました。昔から現在に至るまで利用しているWebアプリケーションについて書いてみようと思います。

ソースコード閲覧

GNU Global

このソフトはctagsの強化版といった感じのソフトウェアですが、ハイパーリンクでのクロスリファレンスを実現した静的HTMLも出力することができます。JavaScriptなどを使わないシンプルな出力なので、非力なWX310Kでもそれなりに利用できていました。今でも使っています。

gonzui

主にRubyで書かれたソースコード特化型検索エンジンです。残念ながら2005年を最後に更新がありません。かつては利用していました。

milkode

同じくRubyで書かれたソースコード検索エンジンです。開発は活発で、対応している言語もgonzuiより多いので、現在はこちらを使っています。gonzuiが独自データベースであったのに対し、milkodeはバックエンドにGroongaを使っています。

Pootle(翻訳)

Pythonで書かれたWebアプリとして動作する翻訳ツールです。かなりモダンな造りでJavaScriptをガッツリ使っています。スタンダードなpo形式も扱えるので、役に立っています。

ownCloud(オンラインストレージ)

PHPで書かれたオンラインストレージです。Linux, Windows, Android, iOS等のクライアントが用意されていますが、WebDAVとしても動作します。Webアプリとしても動きます。

サーバーサイドでAESを使った暗号化ができたり、サードパーティWebアプリがいろいろとあったりします。RSSリーダーもあるので、もしFeedlyがなくなってしまったらそれを使ってみようと考えています。

その他

gitlabやredmineも用意したのですが、これらはいまいち活用できていません。以前はWebでIMAPを扱えるIrohaMailも入れていたのですが、使い勝手がいまいちで消してしまいました。今時であればスマートフォンのIMAPクライアントで十分でしょう。

積みハード2014

昨年かっただけで触っていないハードウェアやデジタルガジェットがいくつもあるので、反省とともに記録しておきます。

Cloud Flash

PQI Air Cardと同じような製品で、本体はmicroSDカードスロットとWiFi APを持ったSDカードです。デジカメに差して、ワイヤレスで画像などが転送できるというものですが、中身はarmベースのLinuxが入っています。

ちょっといじればtelnetできるようになったり、さらにはPQIのファームウェアを書きこんでPQI Air Cardと全く同じものにすることも可能だそうです(Linux搭載無線LAN内蔵SDカードアダプタCloudFlashが値下げで1,980円!めちゃくちゃ魅力的だし間違った使い方も可能)。

Leap Motion

両手の10本指をトラッキング可能なデバイスです。Linux, Windows, Macのデバイスドライバがあります。インターフェースとしてwebsocketサーバと提供しており、アクセスすれば情報がjsonで取得できるので、割と簡単にアプリケーションが書けます。SDKも各種用意されています。

一応こいつは新年にようやく開封して、Windows上ではある程度使えるようにはしました。Blenderのプラグインをいれることによって、3DモデリングがLeap Motionである程度行えるという、なかなか未来感のあるデバイスです。

Leap MotionとBlenderについては改めて記事にしようと思っています。

USB BB弾ランチャー

かつてUSBミサイルランチャーというものが流行ったことがあるのですが、こちらはBB弾を発射できるものです。上海問屋で安売り(1980円)していた時に買いました。しかし箱から出してすらいません…

多分http://www.donya.jp/item/25694.htmlこれと同じものじゃないかと思うのですが、カメラはついてたかどうかも定かでないです。

他にもあるような気がするのですが、思い出すか見つけ出すかしたらちゃんと触ろうと思います。

Google::API::OAuth2::Clientのトークン情報をシリアライズする

先日書いた「Google::API::Clientを使う(perl)」の続きです。前回示したコードでは毎回認証してアクセスコードを入力しなければいけないので、それを回避するためにjsonで保存するためのコード例を示してみます。

トークンの保存

# $authには既に認証済みのGoogle::API::OAuth2::Clientであるとする

my ($file, $jsonstr);
open($file, "> token.json");
print $file, $auth->{"json_parser"}->encode($auth->token_obj);

 トークンの読み込み

my $auth = Google::API::OAuth2::Client->new({
    auth_uri => "https://accounts.google.com/o/oauth2/auth",
    token_uri => "https://accounts.google.com/o/oauth2/token",
    client_id => "your-id",
    client_secret => "your-secrets",
    redirect_uri => "urn:ietf:wg:oauth:2.0:oob",
    auth_doc => {
        oauth2 => {
            scopes => {
                "https://www.googleapis.com/auth/gmail.readonly"
                    => "gmail read"
            }
        }
    });

my ($file, $jsonstr);
open($file, "< token.json");
$jsonstr = "";
while (<$file>) {
    $jsonstr .= $_;
}
close($f);
$auth->token_obj($auth->{"json_parser"}->decode($jsonstr));

Data::SerializerでGoogle::API::OAuth2::Clientを丸ごとシリアライズしてみる、ということもやってみたのですが、不完全のようでシリアライズ時に警告が出たり、デシリアライズしたオブジェクトを使った際、最後にsegfaultを起こしたりします。

あとは、new_from_client_secretsというメソッドでjsonファイル上に記録されたauth_uri, token_uri, client_id, client_secretを読み込んで新しいオブジェクトを作成するものも用意されていますが、token_objについては考慮されていません。ファイル外部にclient_id等を記録しておける点が良い、ぐらいのものです。

もうちょっと永続化に関する手続きも簡略化されているとうれしいところです。

Internet ArchiveとDMCA改定

主にWebのアーカイブ(wayback machine)で有名なInternet Archiveが、MS-DOS用のゲームをブラウザ上でプレイできるよう公開した、というニュースがありました。

ねとらぼの記事(MS-DOSのゲーム約2400本がブラウザでプレイ可能に 海外サイト「InternetArchive」が公開)ではフェアユースの扱いという解説がありましたが、事態はもう少し複雑のようです。

Internet Archive、DMCAの改正を歓迎という記事で、Internet Archiveの行っていたソフトウェア、ビデオゲームのアーカイブが合法になったことについて触れています。

本家の声明Internet Archive Helps Secure Exemption To The Digital Millennium Copyright Act によると、「図書館のような公的機関に限って、もはや動作させることが困難な古い記録メディアや再生機器が必要な場合には、コピープロテクトなどを解除してアーカイブすることがゆるされる」という改正がなされたように読めます。Internet Archiveはアメリカの非営利公益法人であり、この対象となります。形体としては「インターネット図書館」と呼べるものです。

提供手段はWebブラウザ上での再生で、JSMESSというJavaScript実装のエミュレーターを利用しています。つまり誰でもゲームがプレイできる状態にあるわけですが、この点について法的にどうなのかという疑問を後藤さんがされていました。

単純にコピーを配布する、という話であれば確かに問題があると思います。とはいえ、DMCAは先頭のDがデジタルであり、YouTubeのようなWeb上での配付に当たらない公開についての取り決めであったとなんとなく記憶していたので、改めて原文を確認してみました。

原文(pdf)には”webcasting”という表現がありました。Wikipediaの解説によると”Webcasting is the distribution of media files through the internet.”ということで、”distribution”の定義が問題になりそうです。訳としては配布もありますが、頒布と訳されることもあります。 個人的な見解としては、Webブラウザ上に限定して再生できる状況はYouTubeと形体としては近いものだと思います。日本の法解釈であればビデオゲームは映画と同じ分類(cf.パックマン訴訟)でもあります。 とはいえ、ブラウザに送信されたゲームのデータをキャプチャして第三者に配布するなどといったことは当然禁止されることでしょう。Internet Archiveが非営利法人であったからこそできたことでもあると思います。

こちらの後藤さんツイートはねとらぼの記事を読んだ直後のものなので誤解もあると思うのですが、さすがにそういう意図をInternet Archiveはしていないと思います。Internet ArchiveはかつてはWebの収集しかしていませんでしたが、今では動画音声画像電子書籍などといったものも広く収集、公開しています。Amazon S3 互換APIも用意されており、第三者からの提供も受け付けています。

Google::API::Clientを使う(perl)

ここのところいろいろな言語でGoogle APIをたたいてみています。PerlのGoogle::API::Clientを使ってみたのですが、ドキュメントがいまいち整備されていなかったので、実際にGmail APIをたたくサンプルを書いてみました。大まかな作りはruby, pythonのライブラリとあまり変わりありません。

OAuth2認証部分

#!/usr/bin/perl
use Data::Dumper;
use Google::API::Client;
use Google::API::OAuth2::Client;
my $auth = Google::API::OAuth2::Client->new({
    auth_uri => "https://accounts.google.com/o/oauth2/auth",
    token_uri => "https://accounts.google.com/o/oauth2/token",
    client_id => "your-id",
    client_secret => "your-secrets",
    redirect_uri => "urn:ietf:wg:oauth:2.0:oob",
    auth_doc => {
        oauth2 => {
            scopes => {
                "https://www.googleapis.com/auth/gmail.readonly"
                    => "gmail read"
            }
        }
    });

print $auth->authorize_uri, "\n";
my $code = <STDIN>;
$auth->exchange($code);

$auth->authrorize_uriはresponce_type=codeなURLを生成します。上記コードで画面上に表示されたURLに接続・承認を行い、ブラウザ上に表示されたアクセスコードをexchangeメソッドの引数に渡します。これで認証は完了します。

client_secrets.jsonファイルからオブジェクトを生成するnew_from_client_secretsメソッドもありますが、jsonファイルにシリアライズするメソッドは用意されていないようです。

サービスの構築とメソッドの実行

my $client = Google::API::Client->new;
my $service = $client->build('gmail', 'v1');
my $body = {
    'userId' => 'your-email-address@example.jp'
};
my $res = $service->users->messages->list(body => $body)->execute({
    "auth_driver" => $auth});
print Dumper($res->{"messages"});

ポイントは以下です。

  • client->buildでAPIとバージョンを指定
  • bodyは連想配列で記述(jsonにマッピングされる)
  • 認証情報はexecuteの引数auth_driverに指定する
    • リフレッシュはGoogle::API::Methods側でよしなにしてくれる
  • 得られる結果もjsonを連想配列化したものになる

ブラウザでAPIs Explorerを試しながらあれこれ試してみればすぐに理解できると思います。

cgroupsのnamespace手動削除

自宅のPCルーターは10年以上前に構築したDebian環境をもとに、HDDだけ移しながらupgradeを長年重ねて積み上げたもので、.emacsが結構な腐臭を放っているとか自作init scriptをmake styleにいい加減に修正したものがあったりとか、いろいろガタはあるものの今でも元気に動いています。

時代が時代なので当然アーキテクチャはi386なのですが、いまどきはDebian側でi386向けのamd64 kernelパッケージを提供しているので、現在はそれを使っています。メインメモリも8GB積んでいます。

kernelがamd64なので、debootstrapでamd64のuserlandを構築することも可能です(–arch amd64)。最近、これをベースにLXCコンテナ化しました。やることは単純で/var/lib/lxc/$name/rootfsにシンボリックリンクを張って、設定ファイルを適当にコピペででっちあげるだけです。

ただ、この作業の過程の中で、lxc-startを-KILLシグナルで殺してしまい、cgroupsのnamespaceが残ってしまうという問題が発生しました。これをどうやったら削除できるか調べてみた結果、rmdir /sys/fs/cgroups/lxc/$name で削除できることを覚えました(kernel documentのcgroups.txt)。最初 rm -rfで消そうとして消せない、と苦労していたのですが、ディレクトリだけを削除すれば良いようです。逆にmkdirするとblkioとかcpusetとか必要なものがごそっと生えてきます。

というわけで、何かしらの不手際でcgroupsのnamespaceが残ってしまった場合には、ディレクトリだけをrmdirしましょう。

ついでにわかったこととして、LXC 1.0.6ではこういった「同じ名前のnamespaceが既にある」状況では$name-1といった名前で重複しないように作るような動きをするようです。

DebianパッケージでBuild.PLをポリシーに合うように扱う

ちょっと手間取ったので記録に残しておきます。

かつてのPerlはExtUtils::MakeMakerという標準モジュールを使い、Makefile.PLを用意しておくというのが一般的でしたが、最近はそれ以外にもModule::Build, Module::Build::Tinyというパッケージを使い、Build.PLというファイルを用意して処理することもあるようです。dh-make-perlはModule::Buildにも対応しているような感じでしたが、Module::Build::Tinyには対応していないようです(dh-make-perl 0.84-1で確認)。

dhのoverrideを使って、以下のようなコードをdebian/rulesに追加することで望みどおりの動作をするようになりました。

override_dh_auto_install:
        ./Build install --destdir=$$(pwd)/debian/$pkgname --installdirs=vendor

追記

同じ内容の記事を英語blogの方にも書いたところ、debhelperの問題という指摘を受けました。この問題が発生するのはwheezyのdebhelperに限定されます。sidではこのような対応は不要です。