イベント

概要で説明した通り、Oceanは、接続されたストリームからのイベントを受け取ると、自動的に対処できないものは、イベントハンドラに渡し、その処理を任せます。サービス開発者は、このハンドラの中身を実装していくことになります。

イベントカテゴリ

イベントの種類をイベントカテゴリと呼び、Oceanでは次のようにイベントを分類しています。

カテゴリ名 概要
Nodeサーバーに関するイベント。起動、終了、タイマー
Authen認証に関するイベント
Connection接続情報に関するイベント
People友人リストやプロフィール情報などの要求イベント
Messageメッセージ配信に関するイベント
P2Pコネクション間でのダイレクトなやりとりを中継するためのイベント
Roomグループチャットに関するイベント

イベントのカテゴリ毎に、そのイベントのハンドラメソッドを実装するモジュールが切り分けられます

プロジェクトテンプレート生成時に、例えばハンドラネームスペースをFoo::Handlerにした場合は、

  • Foo::Handler::Node
  • Foo::Handler::Authen
  • Foo::Handler::Connection
  • Foo::Handler::People
  • Foo::Handler::Message
  • Foo::Handler::P2P
  • Foo::Handler::Room

の各モジュールが自動で生成され、これらの中に具体的な実装を書き込んでいくことになります。

イベントハンドラ

それぞれのイベントカテゴリに対応したモジュール内で実装される、全てのイベントハンドラはon_を接頭語にします。

引数は二つあり、一つ目はContextオブジェクトで、二つ目はHandleArgsオブジェクトになります。

この二つについては後ほど解説しますので、まずは雰囲気をつかむために実際のコードを見てみます。

Context

Oceanサーバーでは、起動時にコンフィグファイルで指定されたContextクラスのオブジェクトを生成し、そのオブジェクトのinitializeメソッドを呼び出します。 また、サーバー終了時にはfinalizeメソッドを呼び出します。

各イベントハンドラが呼び出されるときには必ず、このContextオブジェクトが渡されます。

Contextクラスは、プロジェクトテンプレート作成時に、Ocean::Contextを継承しただけの状態で生成されますので、そこに拡張を加えていくとよいでしょう。

一例として、initializeメソッドでデータベースへの接続を行い、その接続情報を保持し、finalize時に解放するということが出来ます。

各イベントハンドラからは、このContextを経由して、データベースの情報を取得することが出来るようになります。

Contextの例

呼び出し側の例。$ctxget_user_infoメソッドを呼んでいます。

また、Contextにはget/setメソッドがあり、単純なstashとしても利用できます。

実際は、この例のようにDBへのアクセスを保持すると、DBサーバー側でコネクション保持用のスレッドが解放されないまま増えすぎて問題になる場合があります。

HandlerArgs

Contextと共に渡されるオブジェクトがHandlerArgsです。HandlerArgsはイベントの種類毎に用意されており、それぞれそのイベントのデータを保持しています。例えばSASL認証イベントでは、Ocean::HandlerArgs::SASLAuthRequestが渡されますし、ロスター要求イベントではOcean::HandlerArgs::RosterRequestが渡されます。HandlerArgsオブジェクトは、それらのデータを取得するためのアクセサを持つだけのシンプルなオブジェクトです。

DeliveryRequest

ほとんどのイベントでは、配送処理が必要になります。

Request/Responseタイプのイベントでは、要求を行ったユーザー本人に結果を返します。

[画像が入る]

メッセージは、宛先となるユーザーにメッセージを配送します。

[画像が入る]

プレゼンス変更は、そのユーザーの友人全員にブロードキャストします。

[画像が入る]

これらのイベントは移送には、DeliveryRequestを利用します。

DeliveryRequestを生成するためには、それぞれのイベント専用のDeliveryRequestBuilderが用意されています。

DeliveryRequestBuilderを利用してビルドしたものを、Contextのdeliverメソッドに渡します

次のコードは、SASL認証失敗レスポンスを配送するときの例になります。


まとめると、イベントハンドラでは、サーバーとほぼ同じライフサイクルで保持されているContextオブジェクトと、該当イベントに対応したHandlerArgsオブジェクトの二つを受け取り、そのイベントの処理を実装していきます。ユーザーへの配送が必要な場合には、該当イベントに対応したDeliveryRequestBuilderを利用します。

スタンドアロンプロジェクトの実装を参考にする

イベントハンドラのオーソドックスな処理については、スタンドアロンプロジェクトでの動作を参考にするとよいでしょう。

スタンドアロンプロジェクトで利用されるコンテキストやハンドラは、Ocean::Standalone名前空間下のモジュールを継承しています。

Ocean::Standalone::Contextや、Ocean::Standalone::Handler::XXXなどを読むと、基本的な動作について、一通りの理解が得られます

例えばOcean::Standalone::Handler::Authenは次のようになっています。

このように、スタンドアロン用のハンドラには、標準的な動作で実装がされています。