タスク分離
タスクは、2つの大きな機能に分けることができます。
- サイト上のトレント分布のディレクトリ(通常、フォーラムとして実装されています)、
- 配信プロセスに直接関与するトラッカー自体。
トラッカーは、BitTorrentプロトコルの仕様に従ってhttpアプリケーションであり、要求に応じて、配信のすべての参加者についてクライアントに通知します。 クライアントは絶えず定期的にリクエストを送信するため、トラッカーは生産的である必要があります。応答時間は最小限である必要があります。
PHPの世界では、CatalogとTrackerは多くの場合、2つの専用アプリケーションに分割されていません。 たとえば、人気のあるTBDevトラッカーは、カタログフォーラムとトラッカーを組み合わせたアプリケーションとして存在します。 (作成者は、アプリケーションの人気にうんざりしているので、サイトが長い間更新されておらず、アプリケーションをダウンロードするのは非現実的です。しかし、Webで多くのクローンを見つけることができます。)
一部のTracker実装は、もともとPythonで記述されていましたが、パフォーマンス上の理由からC ++で書き直されました。 そのため、最近ではPythonトラッカーは存在しません(少なくとも私は見つけることができませんでした)。 したがって、残っている唯一のことは、個別のトラッカーアプリケーションをインストールし、Pythonディレクトリと統合することです。
制御と保護
コントロールが必要ない場合は、次のとおりです。
- トラッカーがどのディストリビューションをサポートするかは気にしません。匿名ユーザーは自分のディストリビューションをトラッカーに追加できます。
- そして、日常的に、匿名ユーザーは既存のディストリビューションにアクセスできると考えています。
その後、 プログラムの 1つをインストールするだけで、最も軽量で生産性の高いプログラムを選択できます。
さらに、ユーザーにディレクトリエントリを作成し、自分で作成した.torrentファイルをアップロードおよびダウンロードする機会を与えるだけです。 トラッカーの正しいアナウンスアドレスを事前に通知しておくと、トラッカーはディストリビューションの作成時に.torrentファイルに書き込みます。
私の場合のように、少なくともある種の制御を確立したい場合、さらにそれを実現したい場合は、特定のディストリビューションへのユーザーグループのアクセスを制限したい場合、いわゆる「プライベートトラッカー」が必要です。
理論的には、これは次のように行われます。
- 匿名配布の追加の防止:トラッカーは、許可ユーザーがディレクトリに追加した配布のみをサポートする必要があります。 ディレクトリエントリを作成して.torrentファイルを添付する場合、サイトのコードはトラッカーの許可された配布のリストに配布を追加する必要があります。
- 匿名ユーザーによる.torrentファイルの受信防止は、カタログを使用して実装されます
- 配布へのユーザーアクセスの制限(および配布に参加しているユーザーの追跡)は原則に従って実行されます。誰かがディレクトリエントリを確認して添付の.torrentファイルをダウンロードできる場合、配布への参加が許可されます。 この場合、トラッカーはユーザーを識別する必要があります。 これは、ユーザーが.torrentファイルをダウンロードしたときに、トラッカーURLをアナウンスするための一意のユーザーコードをフラッシュすることで実行されます。 つまり、Directoryコードがこれを行う必要があります。
- 「ブロードキャスト配布交換」プロトコルの禁止:ハッシュテーブル(DHT)、ピア交換(PEX)、ローカルサービス検出(LSD)を配布します。これにより、トラッカーなしで、したがってアクセス制御なしで作業できます。 これは、.torrentファイルでフラグ「private = 1」を設定することにより実装されます。
実装
上記のすべてを考慮すると、私が選択したのは、任意のディレクトリサイトと統合するように設計されたプライベートトラッカーの唯一の実装としてのXBTトラッカーです。
XBT TrackerはC ++で記述され、ソースからビルドしてインストールされます。 Ubuntu Server 12.04では、64ビットが初めてビルドされます。
依存関係
XBTトラッカーとの相互作用はトラッカーMySQLデータベースを介して行われるため、PythonディレクトリはMySQLデータベースを読み書きできる必要があります。 このために、
pymysql
パッケージを使用し
pymysql
。
.torrentファイルを解析および変更するには、
BitTorrent-bencode
パッケージも必要です。
import bencode, pymysql
機能
まだ許可されていない場合は、許可ユーザーを追加します。 ここでは、
torrent_pass
テーブルの
torrent_pass
フィールドを使用して、サイトのユーザーIDとXBTトラッカーのユーザーIDをリンクします。 以前、torrent_passは、アナウンスURLで指定されたキーを使用してユーザーを承認するために使用されていましたが、現在はXBTトラッカーが異なるアルゴリズムを使用しています-以下を参照してください。
uid
フィールドは自動インクリメントです。
c = db.cursor() c.execute("SELECT uid, torrent_pass, torrent_pass_version, downloaded, uploaded FROM xbt_users WHERE torrent_pass = %s", (request.user.id,)) rec = c.fetchone() if not rec: # insert a new user c.execute("INSERT INTO xbt_users(torrent_pass) VALUES(%s)", (request.user.id)) c.execute("SELECT uid, torrent_pass, torrent_pass_version, downloaded, uploaded FROM xbt_users WHERE torrent_pass = %s", (request.user.id,)) #rowcount =0 rec = c.fetchone() db.commit() uid, torrent_pass, torrent_pass_version, downloaded, uploaded = rec
.torrentファイルの読み取りと解析:
with open(fpath, 'rb') as f: buf = f.read() bt = bencode.bdecode(buf)
プライベートフラグを強制的に設定し、info_hashを計算します(プライベートフラグはinfoセクションに含まれており、ハッシュに影響します)。
if xbt_force_private: bt['info']['private'] = 1 info_hash_obj = hashlib.sha1(bencode.bencode(bt['info']))
xbt_files
テーブルにディストリビューションが登録されていない場合は登録します。
sha = info_hash_obj.hexdigest() c = db.cursor() c.execute("SELECT flags FROM xbt_files WHERE info_hash=UNHEX(%s)", (sha,)) flag = c.fetchone() if flag is None: c.execute("INSERT INTO xbt_files(info_hash, mtime, ctime) VALUES(UNHEX(%s), UNIX_TIMESTAMP(), UNIX_TIMESTAMP())", (sha,)) db.commit() elif flag[0] % 2 : error_msg(pagename, request, _("Torrent is marked for deletion!")) return
アナウンスURLの認証キーの計算
XBT Trackerは非常にトリッキーなキー計算アルゴリズムを使用します。 値のセットが取得されます。
- ユーザーID:
xbt_users.uid
、 - ユーザーキーバージョン:
xbt_users.torrent_pass_version
、 - サーバー秘密鍵(XBTトラッカーの最初の起動時に自動的に生成されます):テーブル
xbt_config
、値torrent_pass_private_key
、 - このディストリビューションのinfo_hashの値は
xbt_files.info_hash
です。
これらはすべて、「私はひねり、混乱させたい」という原則に従って、魔法のように混ぜられています。
c.execute("select value from xbt_config where name = 'torrent_pass_private_key'") torrent_pass_private_key = c.fetchone()[0] s = "%s %d %d %s" % (torrent_pass_private_key, torrent_pass_version, uid, info_hash_obj.digest()) sha = hashlib.sha1(s).hexdigest()[0:24] pwd = "%08x%s" % (uid, sha) bt['announce'] = 'http://xbt.host:port/%s/announce' % pwd # remove other trackers if bt.has_key('announce-list'): del bt['announce-list']
これにより、
xbt_users.torrent_pass_version
の目的が
xbt_users.torrent_pass_version
なります。この値を変更することにより、以前にダウンロードしたすべての.torrentファイルを無効にすることができます。 つまり、一種のパスワードリセットアナログです。
最後に、.torrentファイルをエンコードして行に戻し、クライアントに送信します。
buf = bencode.bencode(bt)
ディストリビューションを削除する
添付ファイルを削除する場合、登録済みディストリビューションのリストからディストリビューションを削除する必要があります(テーブル
xbt_files
)。
ポライト削除の方法があります。この方法では、ディストリビューションを削除済みとしてマークしますが、実際には、最後の人が完全にダウンロードしたときにトラッカーによって削除されます。
c.execute("update xbt_files set flags = 1 where info_hash = UNHEX(%s)", (info_hash, ))
まあ、それだけです。 さらなるサイトのねじれ:ディストリビューターの数とリストの表示、評価のカウント、ディストリビューション内のファイルのリストの表示、装飾に起因します。 それらは非常に明らかに実装されています:統計を含むすべての必要な情報はトラッカーデータベースで利用でき、Pierre Fermatに続いて私はそれらの場所を無駄にすみません。
概説されたソリューションは、人気のあるWikiエンジンMoinMoinの プラグインとして実装されます
提案されたソリューションには重大な欠点があることに注意する必要があります。Pythonサポートを使用した仮想ホスティングは一般に比較的まれであり、C ++アプリケーションを実際に構築する可能性はありません。 唯一の選択肢は、TBDev Trackerのクローンをいくつか取り、そこからトラッカー機能を直接実装するコードを噛むことです。
私の経験が誰かに役立つことを願っています。