新月 - P2P掲示板

新月プロトコル 0.6 ドラフト2

2006-02-21

はじめに

新月は複数のノードが協調して動作しており、 そこには何らかのプロトコルが存在すると考えられる。 これを第1次のプロトコルと呼ぶ。 この文書は第1次のプロトコルを明文化して再定義することを試みるものであるが、 残念ながら未だ完全なものではない。

新月ネットワークのノード間で交換されるメッセージは 新月プロトコルに従うことが求められる。 この文書で定義する新月プトロコルのバージョンは0.6である。

新月ネットワーク

新月ネットワークの構成

新月のネットワークはノード間の接続によって構成される。 各々のノードはネットワーク上で一意な名前を持つ。 この一意な名前をノード名という。 ネットワーク上の各々のノードは、 他のノードと通信を行うために他のノード名を保持する。 あるノードがネットワークの維持のために保持している 他のノード名のことを隣接ノードと呼ぶ。 隣接ノード同士は互いに相手のノード名を保持していることが望ましいが、 保証される必要はない。

ノード間の通信はHTTP/1.0またはHTTP/1.1の仕様に従って行う。 ノード間のリクエスト・レスポンスのメッセージは GETメソッドの規約に従わなければならない。

ノードのレスポンスは便宜的に 文字エンコーディングがUTF-8であるプレインテキストとみなす。 厳密にはレスポンスは構造化されており、 各部分について文字エンコーディングが定義されている。

新月のノード間の通信コマンドは最終的にURLとして構築される。 他のノードに送信するコマンドはURL の仕様に従わなければならない。

ノード

新月プロトコルを実装しているプログラム・コンピュータの1単位をノードという。 新月ネットワークに接続するノードは 新月プロトコルを満たすよう正確に実装しなければならない。 プログラムの新月プロトコルの実装にあたっては、 HTTP、URL の仕様も満たさなければならない。

ノードはネットワーク上で一意の名前を持つ。これをノード名といった。 ノード名の形式は次のように定義する:

ホスト名:ポート番号/パス名

ここでホスト名はDNS名またはIPv4のIPアドレスとする。 ポート番号は10進表現の整数である。

新月プロトコルは、ノード名の構成要素であるポート番号を指定しない。 各々のノードはノード名に使用するポート番号を自由に設定することができる。 ノード名に使用するポート番号が1024未満の場合は、 ウェルノウンポート番号に従うべきである。

メッセージ

ノード間でリクエスト・レスポンス時に交換する情報をメッセージという。 メッセージの内容は多岐にわたる。 例えば、/ping コマンドに対するレスポンスである 通信相手のノードのIP アドレスがある。 /getコマンドで交換するファイルもある。

通信相手ノードにリクエストメッセージを送信し、 レスポンスメッセージを受信するノードは、 圧縮されていない通常のメッセージに加えて、 gzip 形式で圧縮しているメッセージも解釈できることが望ましい。 ただし、gzip 形式で圧縮したメッセージをノードに送信する場合、 通信相手ノードはリクエストのメッセージヘッダを解析し、 ノードがgzip形式で圧縮されたメッセージを解釈できるかどうか 判断しなければならない。 もし、判断後ノードがgzip形式で圧縮されたメッセージが解釈可能であれば、 gzip形式で圧縮したメッセージを送信する。 圧縮されているメッセージを解釈できるノードは、 できるだけ通信相手ノードにそれが可能な旨を通知すべきである。 メッセージの圧縮を行うことにより、メッセージを圧縮することができ、 圧縮通信の利点を享受できる。

ノード間のプロトコルコマンド

ノード間の通信はプロトコルコマンドを送信することによって行う。 プロトコルコマンドはノード名から生成したURLのパス部の末尾に付加する。 プロトコルコマンドを付加したURLの例を示す:

http://example.com:8000/server.cgi/ping

次に、ノード間で通信を確立するためのプロトコルコマンドと、 それを受けたノードの振舞いを示す。 \nは改行コード(0x0a)を表わす。

/ping
ノードは「PONG\n相手ノードのIPアドレス」を返す。
/node
ノードはノード自身が接続しているノードを1つ選択し、 そのノード名を返す。
/join/ノード名
相手を隣接ノードに加えるかどうかを判断し、 加えるのであれば「WELCOME」または「WELCOME\n別のノードのノード名」 を返す。 判断には相手ノードが指定するノード名が有効であることを /pingによって確かめること、 相手ノードのノード名のDNS名部分が、 接続しようとしている相手ノード自身を示しているかどうかの検査 などが考えられるが、ここでは定義しない。 相手ノードのノード名のホスト名は省略することができる。 ノード名のパスは/を+ に置き換えたものとする。 相手ノードにはノード保持リストに加えてもらい、 レスポンスで指定したノードに接続することを期待する。
/bye/ノード名
隣接ノードリストから相手ノードを削除し、「BYEBYE」を返す。 判断には相手ノードのノード名のDNS名部分が、 接続しようとしている相手ノード自身を示しているかどうかの検査 などが考えられるが、ここでは定義しない。
/have/ファイル名
ファイル名のファイルを持っていれば「YES」、 そうでなければ「NO」を返す。
/get/ファイル名/時刻引数
ファイル名で指定したファイルの、時刻引数を満たすレコードを返す。 時刻引数は次のうちどれかひとつである:
  • 「時刻」指定した時刻のレコード
  • 「-時刻」指定した時刻以前のレコードすべて
  • 「時刻-」指定した時刻以降のレコードすべて
  • 「時刻-時刻」指定した時刻の間のレコードすべて
  • 「時刻/識別子」指定した時刻と識別子のレコード
/head/ファイル名/時刻引数
/get と同様のレスポンスである。 ただし、各レコードの時刻と識別子のみを返す。
/update/ファイル名/時刻/識別子/ノード名
ノードにファイルが更新されたことを知らせる。 もしすでにファイルの更新に関する処理をしているのなら何もしない。 自分の持っているファイルならば、それを更新したのち、 ノード名を自ノードのノード名に書き換えて接続しているノードにも通知する。 そうでなければそのまま、 送信されてきたプロトコルコマンドを接続しているノードに転送する。 ノード名のパスは/を+に置き換えたものとする。 /joinと同様にホスト名を省略できる。
/recent/時刻引数
時刻引数で指定した範囲の/update命令のあったレコード名を 擬似的なファイルとして返す。 時刻引数は次のうちどれかひとつである:
  • 「時刻」指定した時刻のレコード
  • 「-時刻」指定した時刻以前のレコードすべて
  • 「時刻-」指定した時刻以降のレコードすべて
  • 「時刻-時刻」指定した時刻の間のレコードすべて
レスポンスは次のようになる。
タイムスタンプ<>識別子<>ファイル名
/
ノード固有のメッセージを表示する。 通信には使わないので、何を出力してもよい。

ファイルの伝播

ノードは、ファイルの内容に変更が生じたときに、 変更された事実を/updateコマンドを使用して他のノードへ通知することができる。 ファイルの変更があったことを通知するかどうかの判断の処理は、 実装によって異なる。

ファイル

ファイルの定義

1つの掲示板を構成する、0個以上のレコードの集合をファイルと呼ぶ。 それらのレコードを\nで接続した書式を持つ。 ファイルは無限の長さを持っており、 実際には1つのファイルの全体を目にすることはできない。 ノードが扱うのは常にファイルの一部である。

ファイル名

ファイル名は prefix_basename という形式である。 prefixに使える文字は半角英数字、 basenameに使える文字は半角英数字とアンダースコア(_)である。

prefixはファイルの種類を表す。 basenameはファイルの「名前」などを表わすことになるだろう。 ファイル名を定義するのはアプリケーションである。

レコード

レコードとはファイルを構成する要素のことである。 レコードの形式は、次のように定義する:

タイムスタンプ<>識別子<>本文

識別子は本文のMD5値である。 レコードの要素は<>で区切る。 タイムスタンプは基準時刻から経過した整数値の秒数を表す。

本文の書式

本文を構成する要素は「<>」で区切る。 本文は複数の名前付きフィールドで構成される。 名前付きフィールドの形式は「名前:値」である。 名前付きフィールドの名前に使える文字は半角英数字とアンダースコア(_)である。 名前付きフィールドの名前は重複してはならない。 重複した場合の例外処理は実装依存である。 名前付きフィールドのstamp, id は予約されており、 それぞれタイムスタンプ、識別子を表わす。 本文での名前付きフィールドの出現順番は問わない。 名前付きフィールドのフィールド値には「<」「>」が含まれてはならない。 例外として「<文字列>」(タグと呼ぶ)を含むことができる (文字列は長さが1 文字以上であって、「<」「>」が含まれてはならない)。 どのようなタグが使えるのかはアプリケーションが定める。

時刻

新月プロトコルで用いる基点時刻は 「1970年1月1日午前0時(グリニッジ標準時)」である。 ある時刻は基点時刻を基準として表される整数値の秒で表す。

ブラケットリンク

アプリケーションは、ファイルの内容をなんらかのデータ形式に変換し、 結果を出力する場合において、 本文に次に述べるようなブラケットリンクがあるときは、 文字列が指定するリンクを作成しなければならない。

アプリケーションtypeが存在するとする。 標準的なブラケットリンクの形式は[[/type/文字列]] である。 文字列の形式はアプリケーション(type) が定義する。 /typeは省略することができる。 /typeを省略したブラケットリンクの形式である[[文字列]]は、 本文が記録されているファイル形式のtypeが省略されていると考える。

現在アプリケーションとして定義されているthreadの ブラケットリンクの作成例を次に示す。

[[すれっど]]
本文が記録されているファイル形式がthreadなら、 threadの「すれっど」へリンクする。
[[すれっど/7889e7db]]
本文が記録されているファイル形式がthreadなら、 thread「すれっど」の識別子「7889e7db」を持つレコードへリンクする。
[[/thread/すれっど/7889e7db]]
thread「すれっど」の識別子「7889e7db」を持つレコードへリンクする。

署名

署名の定義は新月プロトコル0.5 ドラフト#2 PDFを参照せよ。

プラグインとアプリケーション

プラグインはアプリケーションを含む概念だが、まだ定義できない。 通信、署名、削除通知以外の部分がプラグインということになるだろうか。

プラグインのうち、 ファイルの書式を定義するプラグインをアプリケーションと呼ぶ。 新月プロトコル0.6の定義するアプリケーションはthreadの1種類である。

かつては他に8種類のアプリケーションが存在した。

アプリケーションとは実装のことではない。

フィールド

アプリケーションは、 レコード本文の要素として複数の名前付きフィールドを持つことができる。 名前付きフィールドはアプリケーションごとに定義を行う。 名前付きフィールドの形式を次に示す:

field_name:field_value

field_nameは名前付きフィールドの名前をである。 field_valueは名前付きフィールドの値である。 なお、フィールドの区切り文字は「<>」である。

アプリケーション間で共通する名前付きフィールド

名前付きフィールドには、アプリケーション間で共通のフィールドがある。 次にアプリケーション間で共通する名前付きフィールドを示す。

署名に関連する名前付きフィールド
署名に関連する名前付きフィールドとその説明を示す:
pubkey
署名の公開鍵を記す。
sign
署名を記す。
target
どのフィールドを署名するか「,」で区切って並べる。
削除通知に関連する名前付きフィールド
削除通知に関連する名前付きフィールドのフィールド名とその説明を記す:
remove_stamp
同じファイル中で削除するstamp を指定する。
remove_id
同じファイル中で削除するid を指定する。

threadアプリケーション

いわゆる掲示板のアプリケーションである。

ファイル名

thread_エンコードされた掲示板タイトル という形式である。 エンコードされた掲示板タイトルとは 掲示板タイトルをUTF-8で表現し、16進数表現(0-9A-F)に変換した文字列である。

名前付きフィールド

name
投稿者の名前
body
書き込みの本文。 タグは改行を表わす「<br>」のみが使える。 「<BR>」や「<br />」は不可。
attach
添付付ファイルをbase64エンコードしたもの
suffix
添付ファイルの拡張子
mail
投稿者のメールアドレス
name
投稿者の名前

コメントください: [[新月の開発]]

Copyright© 2003-2017 shinGETsu Project. All Rights Reserved.
webmaster@shingetsu.info (Legal Notices)