kosian is here #7

wasavi を構成するコンポーネントとして

  • バックエンド
  • フロントエンド: エージェント
  • フロントエンド: wasavi 本体

の 3 種がある。バックエンドはいわゆるエクステンションのバックグラウンドスクリプト、フロントエンドはコンテントスクリプトなどと言われるものである。エージェントは textarea 要素を持つページにアタッチされて、wasavi を起動させるかどうかの監視などを行う。

これら 3 つが協調することで wasavi が動作する。協調するためにはメッセージングを行う必要がある。

フロントエンドとバックエンド同士のメッセージングは、各ブラウザのエクステンションがその仕組みを提供しているので問題はない。一方で不思議なことに、どのエクステンションも、ドキュメント同士のメッセージング機構はない。

おそらく、ドキュメント同士なら html の規格通りにクロスサイトメッセージングを使ってね! ということなのだろう。でも、[cci]window.postMessage()[/cci] によるやりとりというのは非常に汎用的なものなので、つまりだれでもリスンし放題なのである。怪しげなサイト上で wasavi を起動したりした場合、エージェントに対してクリティカルな情報(たとえば、wasavi のレジスタの内容は更新されるたび同期のためエージェントに内容が通知される)を直接投げるのはちょっとこわい。

ということで、ドキュメント同士のメッセージングとしてはバックエンドを経由してエクステンションのシステムの中で完結するようにした。正確には、もともとそうなっていたのだけど、ここ数ヶ月のソースは [cci]window.postMessage()[/cci] を使うようになっていた。それを元に戻した。

そして、そろそろ各ブラウザのエクステンションストアに置いてある版もここのところのテストが終わったら更新する頃合いだと思う。

kosian is here #6

wasavi のフロントエンドとバックエンドとの通信の方式について若干の変更を行いたい。

そのあたりはもちろん kosian 側で抽象化してあるのだが、wasavi はまず Chrome 上で作り始めたので、Chrome のエクステンションにおけるバックグラウンドとコンテントスクリプトの通信の作法をだいたいそのまま持ってきている。

つまり
extension.postMessage(message [, callback])
というメソッドを用いる。この callback がこの記事の主役である。

この callback を指定することにより、投げたメッセージに対する直接の応答を得ることができる。つまり非常に限定されたメッセージリスナとみなすことができる。一方、フロントエンドはコンテントスクリプト毎の汎用メッセージもリスンしていて:
chrome.extension.onRequest.addListener(handleMessage);
こちらは例えば他のタブで動作中の wasavi で設定が変更されたという同期通知や、dropbox(など)からのファイル読み込みの進捗通知などを扱う。

要するに、2 種類のメッセージリスナを扱っている。この状況で、それぞれが扱うメッセージの性格が完全に分離されているのならば、別に 2 種類あることは悪いことではないのだけど。がしかし上記のファイル読み込みの進捗通知というものが、微妙にどっちつかずな存在なのである。

ファイル読み込みは、フロントエンドからバックエンドへパスなどを渡し、バックエンドで認証などを済まし、読み込むためのリクエストを発行し、その結果をフロントエンドへ返す。フロントエンド側で見るとこの処理は ex コマンド [cci]read[/cci] の処理ということになり、そのハンドラの中で完結するはずのものである。が、実際は [cci]read[/cci] コマンド実行中のバックエンドからのメッセージは、汎用メッセージ側で処理している。これはやや不格好だ。

なぜ postMessage() の callback を使わないのかといえば、つまり [cci]read[/cci] 実行中、バックエンドからのメッセージは複数回送信されるからである。callback は 1 度呼び出されて終わりなのだ。これを拡張し、複数回 callback が呼び出される構造にすれば、必要な処理はすべて [cci]read[/cci] ハンドラの中に掛けば済むようになって、収まりがよいはずだ。

というわけでそうした。ここで、ソースの修正は割とすぐに終わったのだけど、実際に Opera 12 で動かしてみるとさっぱり狙った動作をせず、あーでもないこーでもないとした挙句、単に Opera を再起動させたらちゃんと動くようになったというなんとも言えない事件があったのだが、まあ Opera においては特に珍しいことではないので、いいのだ。

kosian is here #5

kosian ベースの wasavi の作成がひと通り作り終わったので、Selenium によるテストをしている。Chrome、Opera、Firefox のそれぞれでテストをしているのだが、

  • Chrome: 安定して自動テストを行うことができる。また、速い
  • Opera: 不安定な時期もあったが、最終バージョンの operadriver においては安定している。遅くはない
  • Firefox: キーボード入力のエミュレーションがろくに動かない。wasavi のテストでこれは致命的だ。また、べらぼうに遅い。Chrome/Opera での全テストがだいたい 80 分ほどで完走するのに対し、2 〜 3 倍ほどの時間がかかる。それから、必ずフォアグラウンドの状態にしておかないとまともに動かない

と、こんな調子である。Firefox だけが根本的にダメダメなのが気になる。なんとなく環境依存の現象がしないでもないがそんなほいほいテストマシン用意できないしなあ…。

kosian is here #4

  • Firefox でもだいたい動くようにした
  • エクステンションのビルドは make で行うようにした

ということで、Ant は使わなくなったのだが、機能テストは例によって Selenium を用いるので、Ant というか java は結局使うことになる。

kosian is here #3

kosian ベースの wasavi を Firefox で動かすべくあちこち直している。

Chrome と Presto Opera のエクステンションの仕組みは、もちろん同じではないにしても、いとこ程度には基本的な構造は似通っているので、一方が動けば他方はそれに合わせて直すだけでいいので楽なのだ。

問題は Firefox の Add-on SDK なのである。このプラットフォームで作る拡張機能というのは、かなり異質だ。Chrome や Opera の遠い親戚の、隣に住んでいるバングラデシュ人くらい異質だ。

Add-on SDK でいわゆる content script 的なものを動かすには、PageMod API を使う。このとき、どの URL で content script をアタッチし、あるいはどの URL ならアタッチしないかという include と exclude の情報が必要になる。wasavi の場合フロントエンドは agent と wasavi 本体にコードがわかれていてアタッチの仕方が若干複雑なので、exclude 機能は必須である。で、どちらを指定する機能も、Chrome と Opera は当然持っている。

Add-on SDK の PageMod は include の指定しかできないのである。意味が、わからない。そして、最新のドキュメントを見ると exclude 機能は Firefox 32 で実装されるよ! 乞うご期待! という扱いになっているのである。意味がわからない。

どうするか。include には URL がマッチすべき文字列か正規表現オブジェクトを渡すことになっている。ここで PageMod が求める正規表現オブジェクトとは必ずしも RegExp のインスタンスである必要はなく、test() と exec() メソッドを備えていてそれぞれがそれぞれの働きをすれば通してくれるので、今まで wasavi ではそのように振る舞う独自のオブジェクトを渡していた。この時点でちょっとアクロバティックである。

で、Firefox 30 でそのコードを動かしてみると見事に動かない。なんと include に渡されたものが文字列か RegExp インスタンスかどうかのチェックを行うようになったのである。このチェック自体は正しい。しかし前述の通り Firefox 30 の PageMod には exclude 機能はない。意味がわからない。どうしろというのか。

仕方がないのでさらにアクロバティックなことをして(互換性はないのに constructor を RegExp にする)動かすようにしたのだが、もちろんかなり嫌なコードである。なお、さらに PageMod 内部で摩訶不思議な RegExp インスタンスのキャッシュ機構が働いているらしく、toString() も上書きしないとダメだったりする。本当にがっかりさせられる。

最初から exclude 機能をつけてくれればこんな変なことをする必要はないのだし、そもそも include 機能があって exclude はないという API のデザインセンスの意味がわからない。

こういう記録が残るブログであまり穏やかではないことは書きたくないのだけど、Add-on SDK チームってバカなんかじゃないかと思う。

kosian is here #2

wasavi-kosian そういうわけで、kosian ベースの wasavi が Chrome と Opera で動くようになった。次は Firefox。

ところで、Linux 版の Opera 12.16 というのは、全体的にはよく出来ているのだけど、「なんでそこを見落とすの!?」という箇所がバグっている不思議なプロダクトである。

  • 数日起動させっぱなしにすると、ソケットやファイルを開きすぎです!的なエラーが出て何も読み込めなくなる。つまりいったん開いたそれらを閉じる処理を、全てではないが一部見逃している感じ。なんでそこを見落とすの…
  • IME との連携は壊滅的にめちゃくちゃで、まったくテストされていないと言っていい。プリエディットや変換候補のポップアップが出る位置、プリエディット中の ctrl などのモディファイアキーの取り扱い、アドレスバーにカーソルがある場合の不自然に中途半端な IME の対応、などなど。また Windows 版で苦労してでっち上げた擬似 Composition Events も、input イベントなどの発生仕様が Windows 版よりもさらにぶっ壊れているのでそもそも Linux 版の Opera 上の wasavi で日本語入力はまったくできない
  • 詳細は忘れたけど、エクステンションとして読み込むソースファイルがシンボリックリンクだった場合に Windows 版と振る舞いが異なる
  • 詳細は忘れたけど、ショートカットキーに定義したストロークがまったく無視されることが割とけっこうある

なんとなく、作った奴はかなりの切れ者なのだろう。しかしテストした奴が極めて少人数だったか、相当ぼんやりしていたか、あるいはぐでんぐでんに酔っ払いながら仕事したのだろうと思わせる惜しい出来なのである。

kosian is here

以前にも書いたとおり、wasavi のバックエンドから汎用的な部分を抜き出す作業をしている。

  • wasavi のバックエンドから汎用的な部分を抜き出す。これは kosian ライブラリと呼んでいる: 完了
  • kosian を中心にして赤福プラスを作る: Presto Opera 版はとりあえず公開済み
  • kosian を中心にして wasavi のバックエンドを書き直す: いまここ
  • 赤福プラスを Presto Opera 以外でも動くようにする

kosian とは漉し餡のことではあるが、そもそも赤福の中心部は餡じゃなく餅であったり、山葵と餡は絶対に巡り合わない人たちだったり、かなり支離滅裂なネーミングであったりする。

add a ad

赤福プラスを公開したわけだが、いくつか積み残している、つまり未実装のものがある。

まず、「自動追尾」なる機能について、ページ上にリンクはあるものの、その機能本体をまだまったく実装していない。それどころか、どういう仕様にするかもまだ決めていない。ぼんやりと思い描く分には、これはつまり自動追尾属性をスレッドに与えることにより、適当な間隔で自動的に「続きを読む」機能を実行し、加えてスレッドが落ちたらやはり自動的にそのログを MHT 形式で dropbox などに保存する……というものだ。なお、あらゆるスレッドにこの属性を付与されるとなかなかトラフィック的な問題もあるので、同時に登録できるのは n スレッドまで、みたいな制限は加えることになると思う。

次に、虹裏 may などに存在するお絵かき機能への対応をまだしていない。以前も書いたが、赤福プラス version 3.0 以降では、ページの内容が完全に赤福プラスの制御下にあるという構造になっている。これにより様々なメリットを享受できるのだが、一方でふたばのサーバが返す生の html に含まれる javascript コードでやっていることの再利用ができず、赤福プラス側で同じ処理を書かなければいけないというデメリットもある。で、お絵かき機能の処理をまだ書いていないということなのである。具体的にその処理とは、単にお絵かき要素の可視・不可視を切り替えるだけのことだ。

じゃあ、書けばいいじゃん! ということなのだが、いくつか気になる点がある。このお絵かき機能はあんまり高機能なものではないのである。これは、ふたばの管理人さんが「あえて」低機能なままにしているのだと思うが、別に高機能なオプションがあってもいいのではないか。また、お絵かき機能は flash で実装されているので、ハンドリングがややめんどいというのもある。

そこで、html5 の canvas を活用した、もう少しだけイケてるお絵かき機能を実装すればよいのではないかと考えている。加えて、ふたばに貼られた画像を引用する機能も欲しい。これにより、スレッド上でお絵かきのコラボレーションみたいなものが簡単に実現できることになる。

実は Opera に canvas が実装されてすぐ、レイヤーや自由領域選択やフィルタやその他もろもろといった、だいたい Photoshop Elements に相当する機能を備えたそういうアプリを書いてみたことがあるので、おそらくそれを持ってくることになると思う。

最後に気になっているのは、ふたば上の広告の扱いである。というわけでやっとタイトルに絡めることができたのだが、力尽きたのでまた明日。

the 15th single

前の記事の続き。

  • Unifont には ambiguous 属性を持つ文字について、1 カラム分(いわゆる半角)と 2 カラム分(全角)の両方のグリフが混在している
  • Unifont には neutral 属性の字の内、2 カラム分のグリフのものが大量にあるが、端末エミュレータはそれを 1 カラム分の文字として表示する

という問題。

まず、ambiguous な方は、UFO 側のグリフを 1 カラム分で統一するようにほとんどすべて書き直した。これはつまり、●とか◎とかの日本古来の(?)全角文字が UFO においては半角分の幅のちっこい丸で表示されるということを意味する。これはなかなか反感を食らいそうな決定ではあるのだけど、でもねえギリシャアルファベットやキリルアルファベットを始めとして、本質的に 1 カラム分のグリフで扱ったほうが収まりがいい字が 2 カラム分のそれの、ざっくり 4 倍くらいあるんですよ。

ちなみにそういうわけなので、UFO を使用する際は vim の ambiwidth は single にしないといけない。

neutral な方は、フォント側ではいかんともしがたいので知らないふりをする。こちらもそれぞれのグリフを 1 カラム分に書きなおすことができれば、それはそれでひとつの解決策ではあるので、ためしに Devanagari でやってみたのだが、えー、まあ、無理です。ちっこすぎて目が悪くなる。

くわえて Devanagari 特有の合成処理が、(xfce-terminal では)なんか動いているような動いてないような、vim 側の問題のようなそうでないような、微妙な感じなのでそのへんも含めてやはりフォント側で頑張ってどうこうなる問題ではないと思う。

うーん、これはどうなんだろうか。もしかしたら、端末エミュレータと、込み入った Unicode 文字の処理というのは、想像以上に食い合わせが悪い関係なのかもしれない。実用に即していないおかしな仕様を、これまた中途半端に摩訶不思議な実装をしたまま、誰もそれをどううまく直せばいいのかわからないという。

いやーまさかそんなことはないんだよね……?