Opera Next 16.0

Opera Next 16.0 が公開されていた。それほど目新しい新機能が追加されているわけではない(開発中のものは opera://flags から幾つか試すことができる)。

Presto Opera ユーザーが納得する出来に到達するには、Opera 18、いや 20 くらいまでは待つ必要があるだろう。

15、16、17 と…… Opera の人生暗かった。

wasavi 0.5.342 released

リリースした。Google Drive への対応と ex コマンド入力時の各種補完がメインになっている。

ファイルをアップロードするために Google Drive が提供する API を呼び出す際、Exponential Backoff なる方式にするといいよ、と google 先生は言う。

なにやら難しい専門用語である。exponential とは指数のことだ。しかし内容はわりと明快で、ファイルをアップロードした際に何らかのエラーが発生した場合のリトライの待機時間をべき乗則にするといいんじゃね? ということである。

wasavi ではこれは実装していない。書き込みが失敗したらエラーだよ♪ と表示されてそれだけだ。ファイルへの書き込みはユーザーが明示的に指定するので、エラーが発生したらユーザーが再度指定すればいいのである(このインターフェースには異論はあるかもしれない)。

upgrade VirtualBox

Windows Vista から導入された UAC というものがある。それにともない、Administrator 権限を持っているユーザーであっても通常は制限された権限、必要なときは権限のエスカレーションを行う、といった *nix 的な作法に慣れていると無駄に複雑だなーと思える機構が導入された。同じユーザでもコンテキストによって権限が行ったり来たりするのである。

一方で Administrator 権限を持つアカウント、一般ユーザー権限のアカウントをそれぞれ作り、通常は一般ユーザーでログオン・作業し、必要なときは Administrator 権限を持つアカウントのユーザーのパスワードを入力する、という運用もできる。コマンドプロンプト上でのシンボリックリンクの作成が、こちらの運用方法じゃないと機能しないので、うちではそうしている。

さて数日前 VirtualBox の新しいバージョンが公開されたというので、一般ユーザーでログオンしている状態でダウンロードし、インストーラを実行させた。すると、インストール自体には成功して GUI のフロントエンドは起動するのだが、VM を立ち上げようとすると Kernel Driver が云々といったエラーで実行されなくなってしまった。また、extension pack を更新しようとしても、何やら権限が足りません的なエラーが出る。

これはおそらく前述の、一般ユーザーでログオン + インストーラ実行時に Administrator 権限のユーザーに仮想的にスイッチ、という環境特有のものなのだと思う。おそらくインストーラが複数のプロセスで構成されていて、子プロセスに正しく権限が継承されないまま実行されてしまっているのではないか? と考えて、Administrator 権限を持つユーザーでログオンしなおし、VirtualBox のインストーラを再度立ち上げ、修復インストールした。すると、一般ユーザーでログオンした状態でも正しく起動するようになった。

Google Drive #6

ex コマンド filesystem を実装した。最短は files。最初の引数がコマンドであり、以下の種類がある:

  • default: ドライブ名を省略した場合に使用されるデフォルトファイルシステムを取得・設定する。
    取得
    :filesystem default
    設定の例
    :filesystem default gdrive
  • status: 現在使用できるファイルシステムの一覧を表示する。
    :filesystem status
    *** available file systems ***
    * dropbox /
    gdrive /foo/
  • reset: 指定のファイルシステムのアクセストークンを破棄する

また、ex コマンド pwd、chdir、cd も実装した。機能は読んで字の通り。

Google Drive #5

dropbox、google drive と、wasavi から複数のオンラインストレージを読み書きできるようになる。その場合、ストレージの種別を区別させる必要が出てくる。そのため、wasavi 上でのファイルパスは接頭辞を付けることができる。[cci]dropbox:/path/to/file[/cci] とか [cci]gdrive:/path/to/file[/cci] というような感じだ。

このようにファイルパスを操作するとき、ストレージ・プリフィクスは省略可能である。ということは省略したときはよきに計らってくれるデフォルト値が必要ということであり、すでに内部ではそれを持っている。ただし今のところ dropbox 固定であり、変更する手段がない。どういう変更手段を設けるべきか?

ex コマンドを新設し、[cci]:filesystem default dropbox[/cci] などと指定できるようにするか? あるいは、そうではなく、単にオプションを増やして、[cci]:set filesystem=dropbox[/cci] とさせるか。

うーん、後者が自然かな。ただし一方で、デフォルトのファイルシステムの指定、のようなメタな設定は他に

  • 取得したアクセストークンの破棄
  • 現在有効なアクセストークンに関連付けられたアカウントの情報の表示

のような機能はいずれ必要になる。そうすると、「ファイルシステムのメタデータを管理する ex コマンド」に一本化したほうが長い目で見ればいいのか?

省略可能といえば、パス自体も常に絶対パスで指定しなければならないわけではない。つまり仮想的なカレントディレクトリもまた内部に持っておき、相対パスが入力されたらカレントディレクトリと結合する必要がある。というわけで、カレントディレクトリも内部で持っているのだが、これもまた wasavi 上から変更する手段がまだない。どうするか?

vim であれば、vim 上のカレントディレクトリを参照するには [cci]:pwd[/cci]、変更するには [cci]:chdir path[/cci] である。

こちらは、素直に ex コマンド新設コースかもしれない。pwd とか cd コマンドがあまりにもポピュラーすぎてそこから一線を画す理由がない。[cci]:set cwd=/[/cci] なんてなんだか奇妙だ。特に、相対パスでカレントディレクトリを変更する場合の [cci]:set cwd=../foo[/cci] のようなものは実際の動作とも食い違う(cwd が代入した値そのものになるわけではない)ので奇妙以上におかしい。

Google Drive #4

  • 前回の記事で Google Drive 上のファイルを読み出すために 3 回のアクセスが必要と書いたが、パスの構築時に basename も含めることでこれを 2 回に抑えることができた。
  • あるファイルがその親ディレクトリを複数持てるというのは、そのままの通りの意味のようだ。ハードリンクみたいな感じか。ちょっとこれは面倒なのでちゃんと対応するのは後回し。現状では、パスの構築時は親は 1 つだけの前提にしている。
  • ファイルの実体を読み出す際、ファイルのメタデータに含まれる downloadUrl が指すアドレス(たいてい https://*.googleuserconent.com/*)を参照することになる。一方で、OAuth 2.0 による承認を行う際、スコープと呼ばれる識別子を送る。[cci]https://www.googleapis.com/auth/drive[/cci] が最も強い権限、[cci]~/drive.file[/cci] がファイルの操作、[cci]~/drive.readonly.metadata[/cci] がメタデータの読み込み、みたいな。

    このうち最も強い権限を持つ drive スコープはほんとうに必要な場合のみ使ってね! とドキュメントにも明示してあるのだが、どうも downloadUrl からの読み込みは drive スコープじゃないと行えないような。drive.file だと 404 が帰ってくる。これは……バグじゃないのかな。というわけで drive スコープを使わざるを得ない。そんなような問いと答えが stackoverflow にもあった。

残るのはファイルの書き込み。

Google Drive #3

Google Drive 上の、あるファイルへのパスが与えられたときそれを読み込む手順は以下のとおりとした:

  • パスを dirname と basename に分割する
  • dirname をディレクトリ名ごとに分割し、各フラグメントを [cci]title=’ディレクトリ名'[/cci] に変換し、[cci]or[/cci] で結合してクエリ文字列を得る。[cci]/foo/bar[/cci] は [cci]title=’foo’ or title=’bar'[/cci] となる
  • File:list API を呼び出す。このとき q パラメータは上のクエリ文字列を与える
  • API の結果から、目的のパスに合致するメタデータの並びを得る。上の例で言うと、まずディレクトリ bar があり、その親 ID を持ち、かつタイトルが foo であるものを抜き出す。その処理をルートに向かって再帰的に行い、ルートに達した(分割したディレクトリの個数 == 抜き出したメタデータの個数となった)らパスが決定する
  • File:list API を呼び出す。このとき q パラメータは dirname の最後のフラグメントの fileID を親に持つファイル、とする。つまり [cci]’fileID’ in parents[/cci] とする。これは Children:list API でもよい気がするが、Children:list は指定のファイルの子供の ID しか返さない。
  • API の結果から、basename に一致するものがあれば、その downloadUrl を用いてファイルの内容を読み込む。なければ新しいファイルの編集とみなし、空文字列を wasavi へ返す

つまり 1 つのファイルを読み込むのに 3 回のリクエストが必要になる……それにしてもイケてないなー! もっとうまい方法はないのかしら。

あと、ひとつ気になる点がある。あるファイルのメタデータ内に、その親ファイルの ID が格納されているのだが、名前が parents で、型は配列なのである。あるファイルが複数の親を持つことができる? どうやって?

Google Drive #2

そんなわけで、OAuth 2.0 で認証したりする Google Drive 対応部を書いている。だいたいここここを見ればすべきことは書いてある。

ところで API のリファレンスを眺めてみると、なんか任意のファイルへアクセスするのにパス形式の文字列を使用する機能がないような? つまり、My Drive -> folder A -> folder B -> folder C -> foo.txt みたいな位置にあるファイルを読み書きするためには、dropbox の API であれば
GET /1/files/dropbox/folder_a/folder_b/folder_c/foo.txt
みたいなリクエストを素直に投げればいいのだが、Google Drive だとルートフォルダから 1 階層ごとに
GET /drive/v2/files/root/children/
みたいなリクエストを投げて、フォルダの中身のメタデータを見て掘り進んでいくようなことをしなければいけない。当然、パス階層が深ければその分リクエストの回数も多くなる。

えー……? 天下の Google 様がそんなアホみたいな仕様にしてるなんて嘘でしょ? なんか方法があるんでしょ? と思ったけど特にないようだ。

どういうことなの。なにか見落としてるんだろうか。

* * *

Files:list において、q パラメータに対して title=’folder A’ OR title=’folder B’ OR title=’folder C’ OR title=’foo.txt’ みたいな物を与えて、帰ってきたデータを元にルートから目的のファイルまでのパスを自前で構築し、目的のファイルの ID を特定すれば、とりあえず読む分においては、リクエスト回数は常にパス情報の取得 + 読み込みの 2 回で済むことに気がついた。

なんかイケてないなー。

Google Drive

0.5.320 をリリースした

ところで wasavi が対応しているオンラインストレージは今のところ dropbox だけであるが、Google Drive と Microsoft Skydrive に対応する気がないこともない。対応しないままずるずる来ているのは、つまり 1 年ほど前、これらのサイトは試験的に、認証・承認に OAuth 2.0 を使っていたわけなのだが、その当時は OAuth 2.0 はまだ仕様が流動的だったのだ。

現在、OAuth 2.0 自体の規格はまだ正式に固まっているわけではないみたいだけど、google drive、skydrive ともに OAuth 2.0 での認証・承認が普通に行われるようになって久しいようなので、ぼちぼち対応し始めてもいい頃合いかもしれない。

OAuth 1.0 では、jsOAuth というライブラリを使わせていただいたのだが、2.0 はもうちょっとシンプルな仕様になっている。そこで、もっと薄いライブラリを自前で用意するか、あるいは極端に言えば、直接 xhr をいじる方向でもいけるような気がする。

ちなみに dropbox はいつ OAuth 2.0 に対応するのだろうか。1 年前から「将来は 2.0 に対応するかも!」みたいなアナウンスはあったけど未だに実際の行動がなされていないまま今に至っているような。

completion #4

ファイル名の補完もできるようにした。ファイル名は dropbox へのネットワークアクセスが発生するため、「間」が発生するのは避けられない。補完が非同期になる場合はこんな感じで「補完してますよー」的なものが出る:
completion1
補完が完了すると何項目のうちの何番目ですよ的なものが出る:
completion2