Access local files from wasavi #2

結論から書くと、できそうな感じがする。

Chrome apps から使える filesystem API が提供するメソッドを眺めてみると、

  • getDisplayPath
  • getWritableEntry
  • isWritableEntry
  • chooseEntry
  • restoreEntry
  • isRestorable
  • retainEntry
  • requestFileSystem
  • getVolumeList

という感じ。ところでこれらの API はいわゆる HTML5 のそれを拡張したものなのだが、ふつー filesystem (HTML5) では [cci]requestFileSystem()[/cci] で filesystem オブジェクトのインスタンスを得て [cci]getFile()[/cci] で fileEntry オブジェクトのインスタンスを得て [cci]file()[/cci] で file オブジェクトのインスタンスを得て…それを FileReader や FileWriter で読み書きという感じなのだけど、filesystem (Chrome apps) での [cci]requestFileSystem()[/cci] はキオスクモードという非常に限定されたモードでしか使えない。

どうするかというと、[cci]chooseEntry()[/cci] を呼ぶことでファイル選択ダイアログが開き、その結果 fileEntry オブジェクトインスタンスを得られる。

要するに、ユーザーとのインタラクティブな処理が必ず挟まる。これじゃ、ファイル操作系の ex コマンドと組み合わせられないじゃん! ということだ。

そんなわけで、ダメなのかな? と思いつつ他のメソッドを見てみると、[cci]restoreEntry()[/cci] と [cci]retainEntry()[/cci] というものがある。これは、fileEntry を間接的にキャッシュする。[cci]retainEntry(fileEntry)[/cci] すると何やら独自形式のハッシュ文字列が返ると同時に、Chrome 内部にそれが記憶される。で、[cci]restoreEntry(entryCache)[/cci] すると fileEntry が再生されて得られる。このときはインタラクティブな動作は必要ない。間接的、と書いたのはハッシュ文字列の保存と復帰はアプリケーション側に任されているからだ。

また、[cci]chooseEntry()[/cci] はオプションによってファイルではなくディレクトリを選択させることができる。その場合得られるのは fileEntry を継承した directoryEntry で、これは [cci]getFile()[/cci] メソッドを持っている。

というわけでこれらを組み合わせることでうまく行く。

まず Chrome apps 側のウィンドウに

LFO

こんな感じのシンプルな UI を設けて、ディレクトリを選択させる。これが wasavi 側の仮想的なルートディレクトリになる。

ディレクトリを得たら、[cci]retainEntry()[/cci] を通して得たハッシュ文字列を [cci]chrome.storage.local.set()[/cci] で憶えておく。

次に、background.js で [cci]chrome.runtime.onMessageExternal[/cci] イベントをリスンする。リスナー内で [cci]chrome.storage.local.get()[/cci] でハッシュ文字列を得て、[cci]restoreEntry()[/cci] で再生して、それに対して読み書きを行い、結果を呼び出し元に返す。

呼び出し側では、

chrome.runtime.postMessage('[Chrome app の ID]', {
command: 'read',
path: 'path/to/local/file'
},
function (response) {
// response = {
// path: '/absolute/path/to/local/file',
// name: 'file',
// content: '...',
// size: 100, // size in bytes
// lastModified: 00000... // UNIX time in milliseconds
// }
});

という感じで。

いくつか気になるのは、

  • Windows みたいにドライブが複数ある環境ではたぶん [cci]getVolumeList()[/cci] で得られるリストを予め得ておく必要がある、はず
  • このような動作をするアプリケーションは、他のどの extension/application からのメッセージも受け付ける、というわけにはいかない。油断すると即バックドア化してしまう。来たメッセージが確かに wasavi からのものか、確実にチェックする必要がある
  • ファイルシステムのルート以外を wasavi 側の仮想ルートに割り当てると、双方で絶対パスの位置が異なってしまい面倒そう
  • 他のブラウザでどうするか? さすがに Presto Opera は無理だが(とは言うものの、実は Presto Opera でも Opera Unite によってローカルファイルシステムへのアクセスはかつてはできた)、Firefox ならこんな面倒なことをしなくてもローカルファイルシステムへのアクセスは拡張から普通にできる。ただし、Firefox の拡張が WebExtensions へ収束する流れを考えると、そういった強い権限を必要とする機能はいずれ拡張には公開されなくなる恐れもある

Leave a Reply

Your email address will not be published. Required fields are marked *