
Ruby/IRC ライブラリ  開発メモ

○モジュール階層の見直し
IRC
IRC::Constants
IRC::Connection
IRC::Message
IRC::MessageQueue # メッセージ種別によるフィルタリング機構を備える
IRC::Agent
IRC::ActiveAgent
IRC::PassiveAgent
IRC::Client

○低レベルAPI(IRC::Connectionクラス)
＊流量コントロール
＊Message#parseの検証

○リソース（rcファイル）
＊評価値がHashオブジェクトであるRubyスクリプト
＊デフォルト値のために別に（ユーザがいじらない）スクリプトを用意。

○ログ機構
＊エージェント機構に依存しないシステムログ
  ログ取りエージェントでは、このエージェントの起動前・停止後のログを
  記録することができない（当然ながら）。
＊priority
＊タグ

○エージェントモデル

＊エージェントの特性
・スレッドの有無とメッセージの受け取り方法（キュー／メソッド呼出）
・受け取るメッセージの種類(mask)
  （当面は指定できなくてもよいか？ 不要なメッセージは捨てればいいので）

＊エージェントの保持する情報
・Client
・Connection
・エージェントの生成時刻
・その他エージェントの状態
ActiveAgent固有
・message_queue
・log_queue(LogAgentとして独立に定義したほうがよいか？)
PassiveAgent固有

＊エージェントに対する操作
・スレッドあり
  登録・起動・進化・停止・削除
・スレッドなし
  登録・起動・進化・停止・削除
・スレッドなし・非永続的
  起動（登録されることなく停止削除）

＊プラグインスクリプト仕様
・評価値がagentオブジェクトとなっている
・値がnilのとき登録されない。1回限りの処理の記述に有効。
・進化の際必要となる旧エージェントの情報は、
  スクリプト評価後にClientが必要なメソッド呼出により提供する。
  したがってプラグインスクリプトでは標準的な初期化だけを行って
  おけばよい。
・"syslog.api", "init.api"は特別扱い。Client#start内で起動される。
・init.api以外のstart agentをClient#start(init)で指定できるようにする。

＊エージェントの生成・登録方法
・スレッドあり
  プラグインスクリプトを評価しエージェントオブジェクトを生成する。
  新規スレッドを作成しその中でstartメソッドを呼び出す。
  エージェントテーブルに登録する。
・スレッドなし
  プラグインスクリプトを評価しエージェントオブジェクトを生成する。
  startメソッドを呼び出す。このときClientやConnectionなどを渡す。
  エージェントテーブルに登録する。

＊エージェントの起動・進化・停止のきっかけ
・起動
  startAgentメソッドの呼出。
  実際の生成・起動時刻はThreadのスケジューリングに依存。
・停止
  stopAgentメソッドの呼出。
  実際の生成・起動時刻はThreadのスケジューリングに依存。
・進化
  message_threadによるプラグイン更新検出。
  ActiveAgentへのenqueue・PassiveAgentへのnotifyMessage時に、
  エージェントのプラグインスクリプトが更新されているならば
  一連の進化を行う。
  新旧エージェントが置き換わる間にメッセージが到着し、
  当該エージェントがこのメッセージを受け取りそこなうことが
  ないようにする。進化処理をmessage_threadが行うならば
  この問題は起こらない。log_threadとの関係は？

＊エージェントの進化方法
・スレッドあり
  稼働中のスレッドを例外送出により通知し旧エージェント内部から
  returnさせる。このreturnスレッドは新エージェントを生成して
  旧エージェントを新エージェントに渡し、必要な情報をコピーさせる。
  restart(old_agent)などのメソッドを定義しておく。
  このときメッセージキューも引き継ぐ。
  その後Clientに保持されている旧エージェントを新エージェントで
  置き換える。
・スレッドなし
  新エージェントを生成。
  旧エージェントを新エージェントに渡し、必要な情報をコピーさせる。
  restart(old_agent)などのメソッドを定義しておく。
  その後Clientに保持されている旧エージェントを新エージェントで
  置き換える。

＊Client内部でのエージェント管理
保持しておくもの
・エージェント名→プラグインスクリプト
  一意的にする。関数として定義する。
・エージェント名→エージェントオブジェクト
  エージェントの再起動に備える。
・メッセージキュー・メッセージマスクの組の集合
  ClientとActiveAgentのどちらが生成・管理（保持）すべきか？
  →ActiveAgent#{message,log}_queue == nilなら受け取らない。

○スレッド
・(main_thread)
  Client#startを呼び出したスレッド。message_threadの終了を待ち合わせる。
・message_thread
  メッセージのrecv・配布
  配布時にPassiveAgent#notifyMessage内に移る。
・log_thread
  ログの配布
  配布時にPassiveAgent#notifyLog内に移る。
・(input_thread)
・agent_thread
  主にActiveAgent内で動作。

○オペレータと特権命令の概念

○解決すべき問題
＊プラグインエージェントの危険な動作に対する防御（例外送出その他）
・プラグインスクリプトの評価方法
・Agent#startメソッドの呼出
・PassiveAgent#notifyXXXメソッドの呼出
＊IRCメッセージ(IRC::Message)におけるtrailingの扱い
  RFCによるとparamsと同等の扱いをすることになっているが、
  どう実装するか？  （現在は特別扱いしている。）
＊不意の接続切断後の自動回復

----
Hiroshi IGARASHI <iga@ruby-lang.org>
http://www.ueda.info.waseda.ac.jp/~igarashi/
