Getdownその3、Getdownの実際

2019年5月27日

※Getdownについては/tag/getdownに投稿一覧がある。

実際にしばらくGetdownを使用してみた。もちろん、まだ製品としてリリースするまでには至っていない。

※追加:2019/5時点で既に製品としてリリースしている。

あくまでもテストとしてなのだが、おそらくこれでリリースするか、あるいは、少々中身を変更して別のバージョンを作るかもしれない。少々不都合な点があるからだ。

ドキュメントが不足している

使用中のものは1.7.0で、ドキュメントはhttps://github.com/threerings/getdown/wikiにあるのだが、ドキュメントは1.7.0(おそらく現時点で最新の1.7.1も)の動きを反映していない。

つまり、1.7.0を動作させてみると、ドキュメントに記述の無いファイルができてしまうのである。それらを含めてここで解説してみる。

基本的な仕組み

再度だが、Getdownの基本的な仕組みをおさらいしておく。

前提として、ここではバージョニングはしないものとするが、この意味としては、ユーザ側が好きなバージョンを選択できるということである。バージョニングしない場合はユーザ側は「常に最新バージョン」となる。多くの場合には、これで事足りるであろう。アプリを起動した場合に、その時点の最新バージョンに強制されるということだ。

さて、仕組みとしては簡単だ。あるウェブサイトの特定のパスにあるファイル群が、ユーザ側の特定のフォルダに転送され、それらが同一のファイル群となった上で、指定されたjarファイルの指定されたクラスが起動されるということである。

そもそもJava Web Startの代替を目指しているのだから、当然の動作である。

しかし、Java Web Startとは異なり、各Jarに署名などは必要無いし、当然署名を検証することもない。

クライアント側

「種」のダウンロード

これもJava Web Startと異なるところだが、最初に「種」となるプログラムをユーザ側にダウンロードさせなければならない。このプログラムを起動することによって、先に説明したウェブ上のファイル群をユーザ側のフォルダと同期するわけである。

そして、「種」プログラムは、アプリのバージョンが変わっても、変更する必要の無いようなプログラムであることが望ましい。ファイル群の同期と、その後のアプリの起動に集中するわけである。

種プログラムが行うべきこと

以下を行う。

  • ユーザ側のフォルダを決める。
  • そのフォルダの中にgetdown.txtを作成する。あるいは既にあれば、その内容を確認する。
  • getdownを起動する。

仮にユーザ側フォルダをc:\myfolderとすると、この中にgetdown.txtが存在しなければならない。既にGetdownを実行していれば、その内容が何行にも渡るものになっているが、存在しない場合には、以下の一行だけを書いておけばよい。

appbase=http://foobar.com/app

つまり、ファイル群が格納されているウェブ側のパスをappbaseという名前で指定するだけである。

あとは、Getdownを起動する。

String appdir = "c:\\myfolder";
...
com.threerings.getdown.launcher.GetdownApp.start(new String[] {
      appdir
});

これによって、http://foobar.com/appに格納されたファイル群がc:\myfolderに転送される。

その中には、getdown.txtも含まれているため、最初は一行だったgetdown.txtは、サーバ側で記述された複数行バージョンのgetdown.txtのものに置き換わることになる。当然ながら、ここには最初の「appbase=http://foobar.com/app」が含まれていなければならない。

※ここまで読めば当然なのだが、種プログラムにはGetdownのライブラリが含まれていなければならない。

サーバ側

サーバ側に格納されているべきもの

前述の説明からわかるように、サーバ側「http://foobar.com/app」には、getdown.txtの他にアプリとして必要なすべてのjarファイルが格納されていなければならない。

それに加え、digest.txtおよびdigest2.txtが存在しなければならない。このdigest2.txtについては、先のドキュメントには記述が無いがgetdown(のサーバ側機能)を使用すると自動で生成される。

すなわち、サーバ側の指定パスには以下のファイルが格納されることになる。

  • getdown.txt
  • digest.txt
  • digest2.txt
  • アプリを構成する複数のjarファイル

getdown.txtの記述

サーバ側の格納するgetdown.txtには以下のような記述が必要になる。

appbase=http://foobar.com/app
class=foo.bar.Start
ui.name=アプリ名称
jvmarg=VM引数1
jvmarg=VM引数2
apparg=アプリ引数1
apparg=アプリ引数2
code=foo1.jar
code=foo2.jar
resource=resource1.jar
resource=resource2.jar

codeに記述したものは、アプリ起動時にクラスパスに自動的に指定されるが、resourceに記述したものは、ファイルが転送されるだけである。
jar以外のもの、あるいは何らかの事情でクラスパスに含めたく無いものはresourceとする。

digest.txt, digest2.txtの生成

getdown.txtを記述したら、digest.txt, digest2.txtを作成する。これは共に、getdown.txtに記述したファイルのチェックサムが記述されるファイルである。二つある理由は、Getdownの初期バージョンではdigest.txtのみだったが、これはハッシュ関数が弱いとのことで、より強いハッシュ値のdigest2.txtが新設されたようだ。

File folder = ...; // getdown.txtとそこに記述したファイルが存在するフォルダ
com.threerings.getdown.tools.Digester.createDigests(folder, (File)null, (String)null, (String)null);

これにより、このフォルダの中にdigest.txt、digest2.txtが生成される。

これでサーバ側の準備は完了となる。アプリがバージョンアップした際には、適切にgetdown.txtを修正し、新たなjarファイルをこのフォルダに格納し、再度digest.txt、digest2.txtを作成すればよい。

同期の際の注意点とjarvファイル

サーバ側からクライアント側フォルダにファイル群が転送される際に注意しなければならない点がある。そして、特にこの点が独自のGetdownの作成をも考慮中の理由でもある。それは、以下だ。

  • ユーザ側フォルダに既に存在するファイルは削除されない。
  • 同期されたファイルに対応するjarvという0バイトのファイルが作成される。

つまり、サーバ側のフォルダとクライアント側のフォルダが全く同一になるわけではなく、クライアント側フォルダに余計なファイルがある場合には、それは消去されることは無い。

例えば、アプリ実行時にログをこのフォルダに出力していれば、それが消去されることは無いのである。これは便利だが、しかし一方で、jarファイルのバージョンが変わった場合にも以前のバージョンは残ってしまう。例えば、abc-1.0.jar、abc-1.1.jar、abc-1.2.jarなどとバージョンアップした場合、歴代のjarファイルはすべて残る。

二点目としては、同期されたファイルについては、同じ名前+vという名前の0バイトのファイルが作成される。先の例で、現在abc-1.2.jarを同期したとすると、これに関するファイルは以下になる。

abc-1.0.jar
abc-1.1.jar
abc-1.2.jar
abc-1.2.jarv

もちろん、1.0や1.1を使用していたときは、それに対応するjarvがあったのだが、1.2になったときにはそれらは消されており、abc-1.2.jarvのみになる。

このjarvファイルについてもドキュメントには一切の記述が無く、以上の動作を何らかのオプションで変更できるものかどうかも現在のところ不明である。

おそらく古いバージョンが消えないことを指摘され、後からjarvという「マーカー」を追加したのだろうけれども、いかにも泥縄的な仕様だ。

現在のところ、こちらでは「対応するjarvファイルの存在しないjarファイルを消す」という操作を行っている。古いバージョンが残っていても意味がないからだ。このあたり何とかならないのだろうかと思う。完全にサーバ側と同一にし、不要ファイルを消去してくれても何も問題無いと思うが。。。。