【初期化クラスの実装】

はじめに

初期化クラスは、サーバー起動時に必要なデータ(UNITパラメータインスタンス)や処理(ログライター、シリアライザー/アンシリアライザー、コマンドディスパッチャー、緊急停止コールバック)を読み込むための実装を行うところで、専用のコマンドを使ってスキャルフォールディングできます。

初期化クラスを生成するコマンドは以下の通り。
> php worker craft:init InitForTest

[success] 初期化クラスの生成に成功しました (InitForTest)
                    

コマンドを実行する事でapp/InitClassの場所にInitForTestというクラス名でIInitSocketManagerインターフェイスをimplementsした初期化クラスが生成されます。

以降では生成されたクラス内で実装が必要なインターフェイスメソッドの内訳を見ていきます。

➤ログライター

error_logの標準関数やLoggerなどの有名なライブラリを使ってログを出力する事ができます。
イベントハンドラ(UNIT)内ではパラメータ経由で使いますので$param->logWriter('debug', ['メッセージ受信' => $message])のように記述します。
【メソッド】getLogWriter(): Closure|string|null

【パラメータ】なし

【戻り値】
    Closure|string|null
    - ログ出力を行う場合: Closure
        パラメータ:
            $p_level - string - 必須 - ログレベル
                現状では以下のレベルが定義されています。
                debug
                info
                notice
                warning
                error
            $p_param - array  - 必須 - 出力内容
                連想配列の形式で以下のように指定します。
                ['メッセージ受信' => $message]
        戻り値: void
    - ログ出力を行う場合: string
        ヘルパー関数などの関数名
    - ログ出力を行わない場合: null
                    

public function getLogWriter()
{
    return function(string $p_level, array $p_param)
    {
        // ファイル名を設定
        $filename = date('Ymd');
        
        // 現在日付を含むログ内容を作成
        $now = date('Y-m-d H:i:s');
        $log = $now." {$p_level} ".print_r($p_param, true)."\n";

        // ログ出力(カレントパスはプロジェクトルートになる)
        error_log($log, 3, "./logs/socket-manager-log/{$filename}.log");
    };
}
                    

※カレントパスはプロジェクトルートになるので./logs/debug.logのように指定します。
※このメソッドはフレームワークのライブラリからもコールされますので、イベントハンドラのログも含めて時系列で出力されます。

➤シリアライザー

送信するデータをシリアライズするためのメソッドを実装します。
【メソッド】getSerializer(): Closure|string|null

【パラメータ】なし

【戻り値】
    Closure|string|null
    - シリアライズを行う場合: Closure
        パラメータ:
            $p_data - mixed - 必須 - 送信データ
                イベントハンドラで設定された送信データがそのまま渡されます。
        戻り値: mixed
            シリアライズ後のデータ
    - シリアライズを行う場合: string
        ヘルパー関数などの関数名
    - シリアライズを行わない場合: null
                    

public function getSerializer()
{
    return function($p_data)
    {
        return json_encode($p_data);
    };
}
                    

※シリアライザーはデータ送信時にライブラリから自動でコールされます。
※Websocketサーバーとして使う場合はJSON形式で使うのがいいでしょう。
※通信データ量を減らすためにバイナリデータを扱う事も可能です。

➤アンシリアライザー

受信データを取得する時にアンシリアライズするためのメソッドを実装します。
【メソッド】getUnserializer(): Closure|string|null

【パラメータ】なし

【戻り値】
    Closure|string|null
    - アンシリアライズを行う場合: Closure
        パラメータ:
            $p_data - mixed - 必須 - 受信データ
                シリアライズされている受信データがそのまま渡されます。
        戻り値: mixed
            アンシリアライズ後のデータ
    - アンシリアライズを行う場合: string
        ヘルパー関数などの関数名
    - アンシリアライズを行わない場合: null
                    

public function getUnserializer()
{
    return function($p_data)
    {
        return json_decode($p_data, true);
    };
}
                    

※アンシリアライザーは受信データ取得時にライブラリから自動でコールされます。
※Websocketサーバーとして使う場合はJSON形式で使うのがいいでしょう。
※通信データ量を減らすためにバイナリデータを扱う事も可能です。

➤コマンドディスパッチャー

受信データを受け取った時に呼び出され、そのデータを解析した上でサーバーコンテンツ(コマンドUNIT)上の適切なイベントハンドラを呼び出すためのルーティングの役割を果たします。
コマンドディスパッチャーからは、ルーティングするキュー名を返す事でイベントハンドラを呼び出す事ができます。
【メソッド】getCommandDispatcher(): Closure|string|null

【パラメータ】なし

【戻り値】
    Closure|string|null
    - コマンドディスパッチャーを使う場合: Closure
        パラメータ:
            $p_param - SocketManagerParameter - 必須 - UNITパラメータクラスのインスタンス
                各イベントハンドラで共通の引数として使用されるインスタンス。
                SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
            $p_dat   - mixed                  - 必須 - 受信データ
                アンシリアライズ化された受信データがそのまま渡されます。
        戻り値: string
            ルーティングするキュー名
    - コマンドディスパッチャーを使う場合: string
        ヘルパー関数などの関数名
    - コマンドディスパッチャーを使わない場合: null
                    

public function getCommandDispatcher()
{
    return function(SocketManagerParameter $p_param, $p_dat): ?string
    {
        // コマンド部のキュー名と一致している必要があります
        return $p_dat['command'];
    };
}
                    


➤緊急切断コールバック

クライアントとの接続が維持できなくなった時に呼び出されるコールバックメソッドを実装します。
例えば以下の場面で呼び出されます。
  • アライブチェック処理のタイムアウト
  • コマンドディスパッチャーでの例外発生
  • 相手先による強制切断
【メソッド】getEmergencyCallback(): Closure|string|null

【パラメータ】なし

【戻り値】
    Closure|string|null
    - 緊急切断コールバックを使う場合: Closure
        パラメータ:
            $p_param - SocketManagerParameter - 必須 - UNITパラメータクラスのインスタンス
                各イベントハンドラで共通の引数として使用されるインスタンス。
                SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
        戻り値: mixed
            シリアライズ後のデータ
    - 緊急切断コールバックを使う場合: string
        ヘルパー関数などの関数名
    - 緊急切断コールバックを使わない場合: null
                    

public function getEmergencyCallback()
{
    return function(SocketManagerParameter $p_param)
    {
        // 送信データを作成
        $send_data = [];
        $send_data['command'] = 'close';
        $send_data['message'] = '切断されました';
        $send_data['connection_id'] = $p_param->getConnectionId(); // 接続IDを取得

        // 全員へ配信(第二パラメータがtrueの場合は自身を除く)
        $p_param->setSendStackAll($send_data, true);
    };
}
                    


➤UNITパラメータインスタンス

UNITとしてのイベントハンドラを実行する時に渡されるUNITパラメータクラスのインスタンスを指定します。
基底クラスであるSocketManagerParameterクラスのインスタンスがデフォルトで指定されていますが、このクラスを継承した拡張クラスを使用する場合はそのインスタンスを戻り値に指定する必要があります。
ここで指定したインスタンスはそのままUNITの引数として使われますので、動的に増殖してメモリを圧迫する心配はありません。
【メソッド】getUnitParameter(): SocketManagerParameter|null

【パラメータ】なし

【戻り値】SocketManagerParameter|null
    - UNITパラメータクラスを使う場合: SocketManagerParameter
        各イベントハンドラで共通の引数として使用されるインスタンス。
        SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
    - UNITパラメータクラスを使わない場合: null
                    

public function getUnitParameter(): ?SocketManagerParameter
{
    return new SocketManagerParameter();
}
                    

※UNITパラメータクラスの詳細については▶UNITパラメータクラスのページをご覧ください。


おわりに

生成されたクラスのインスタンスは、メイン処理クラス内で$manager->setInitSocketManager()メソッドに引き渡す事で適用されます。
複数の初期化クラスやメイン処理クラスを用意している場合は、サーバーの実装内容によって最適なインスタンスを動的、あるいは静的に適用する事で柔軟なサーバー構築が可能になります。