ruby-qstat
ゲームサーバー統計取得ツールの QStat を Ruby から使うためのラッパー gem です。qstat コマンドを起動して、マスターサーバーからのサーバー一覧取得や、個別のゲームサーバーへの状態問い合わせの結果を、Ruby のオブジェクトとして返します。
README 記載の動作要件は Ruby 1.9 と QStat 2.12 です。
使い方
gem install ruby-qstat
README にある例です。
# マスターサーバーからサーバー一覧を取得
QStat.query_serverlist("hl2master.steampowered.com:27011", "stm", "left4dead2", maxping = 100)
# 個別サーバーの状態を取得
QStat.query("xxx.yyy.zzz.qqq", "a2s")
# 個別サーバーの状態を取得(サーバー情報のみ)
QStat.query_serverinfo("xxx.yyy.zzz.qqq", "a2s")
内部設計
ライブラリ本体は lib/ruby-qstat.rb の1ファイルで、API は QStat クラスのクラスメソッド群として提供します(インスタンス化はできない作りです)。qstat コマンドの起動は共通の exec_cmd に集約されていて、出力の形式によってパース経路が2系統に分かれます。
- exec_cmd —
Open3.popen3で qstat を起動し、stdout を読むスレッドと stderr を Logger に流すスレッドの2本で出力を回収します。filter ブロックを渡すと、stdout を1行読むごとに判定して、条件が成立した時点で qstat プロセスをTERMで打ち切れます。qstat のパスはQStat.qstat_path=、ロガーはQStat.logger=で差し替えられます - XML 系(
query_serverlist/qslist)—-xmlオプション付きで起動して、出力を Nokogiri でパースします。Responseオブジェクトが XML と DOM を保持し、valid?(先頭の server 要素の status が UP か)やto_ror(ActiveSupport のHash.from_xmlによるハッシュ化)を提供します - テキスト系(
query/query_serverinfo)—-P(プレイヤー情報)・-R(サーバールール)付きのプレーンテキスト出力を正規表現でパースしてServerInfoを作ります。「no response」「DOWN」の応答もヘッダ行の正規表現で判定します - 結果オブジェクト —
ServerInfo(アドレス・サーバー名・マップ・人数・ping・status など)、PlayerInfo(名前・frags・プレイ時間。qstat の「1h 2m 3s」のような時間表記を秒に換算するパーサ入り)、Rule(protocol・gamedir・secure・version・game_tag などのサーバールール)。ServerInfo#playing_timeは、いちばん長くプレイしているプレイヤーの時間を返します - ゲームタイプ推定 —
ServerInfo#suggest_game_typeは、gametype が取れなかったときにサーバールールの game_tag(@以降のカンマ区切りタグ)から推定し、それもなければunknownを返します - 文字コード対策 — qstat には常に
-utf8を付け、さらにString#force_convert_to(UTF-16BE を経由して不正なバイトを?に置換してから戻す monkey patch)で、サーバー名などに混ざる壊れたバイト列を無害化します
サーバー一覧取得(query_serverlist)の流れです。maxping を超えるサーバーが現れた時点で qstat を打ち切る作りで、途中で切れた XML はそのまま Nokogiri に渡してパースします。
- 打ち切りで末尾が壊れた XML も Nokogiri の寛容なパースで DOM 化し、そのうえで ping が maxping 以上の server 要素を DOM から取り除きます
- qstat の XML 出力は先頭の server 要素が構造情報なので除去し(コード内コメントに明記)、残りを
ServerInfoの配列にして返します QStat.read_from_xmlを使うと、保存しておいた XML ファイルから同じ手順でServerInfoの配列を作れます
自作 gem の vrowser(HalfLife2 系ゲーム向けサーバーブラウザライブラリ)がこの gem の上に乗っています。自分のサイトで公開しているサーバーブラウザでも使っています。