No description
- Rust 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Client::set_reconnect / reconnect と Client::set_note_protocol を追加 - 再接続を試している途中で切ると、次の試行をせずに止まる - 音符の形式は次にまとめて送る分から切り替わる - ガイド 08 / 09 章に追記、結合テストを追加 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Hm8WmeHv9Q7vxZNoBiPqVd |
||
| docs | ||
| examples | ||
| server-tests | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
mpp-client
MultiPlayerPiano のクライアント SDK (Rust)。extended-mppserver-idk の Rust 版・JS 版を主な相手に作っていて、JSON の音符しか知らない従来型のサーバーにもつなげる。
できること
- 接続と
hi、部屋への参加、チャット、名前・色・AFK の変更、カーソル、王冠の受け渡し、部屋の設定、kickban、部屋一覧の購読、admin message - 音符の送受信。既定はバイナリ形式 (v2、色付きにも対応)、
NoteProtocol::Jsonで JSON 形式。受信はどちらの形式も同じイベントになる - サーバーと同じ計算で音符クォータを手元でも数え、サーバーに捨てられる音は送らない (
start_noteがOk(false)を返す) - 20 秒ごとの時刻合わせ。
server_time()でサーバーの時計が分かる - 切断時の自動再接続 (1 秒から倍々で最大 30 秒)。再接続後は同じ部屋に入り直し、SDK で設定した名前と色を付け直す
- fake user (
fake_user(password, uuid)) でpasswordとX-MPP-Fake-User-UUIDヘッダーを送る - 描画 (線、折れ線、図形) の送受信と消去
- 通知の受信と送信 (
notify、管理パスワードでadmin_notify) - 部屋の参加者、自分、王冠などの状態をいつでも読める
- プロトコルの全メッセージに型がある (
mpp_client::protocol)。client.send(ClientMessage::…)で何でも送れ、届いたメッセージも型のまま受け取れる
ドキュメント
- ガイド:
docs/に機能ごとの使い方とサンプルがある (はじめに、イベント、チャット、音符、部屋、プロフィール、fake user、接続の管理、ほかのサーバー、描画、プロトコルの型、通知)。コードはどれもコピペで動く完成形で、cargo testで全部コンパイルを確かめている - API リファレンス:
cargo doc --open。主なメソッドには使い方の例が付いている
使い方
[dependencies]
mpp-client = { git = "ssh://[email protected]:2222/ced/mpp-sdk-rs.git" }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
SSH の取得は ~/.ssh/config の設定 (鍵や HostName) に従わせたいので、git コマンド経由で取りに行かせる。プロジェクトの .cargo/config.toml に次を書くか、環境変数 CARGO_NET_GIT_FETCH_WITH_CLI=true を付ける。
[net]
git-fetch-with-cli = true
use mpp_client::{Client, ConnectOptions, Event};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), mpp_client::Error> {
let (client, mut events) =
Client::connect(ConnectOptions::new("wss://mpp.dev.c30.life/").channel("test/my-bot")).await?;
while let Some(event) = events.recv().await {
match event {
Event::Chat(chat) if chat.message == "!hello" => {
client.chat(format!("hello, {}!", chat.sender.name))?;
client.play_note("c3", 0.8, Duration::from_millis(300))?;
}
Event::Notes { participant_id, notes, .. } => {
for note in notes {
println!("{participant_id} {} {:?}", note.key, note.velocity);
}
}
Event::Disconnected { will_reconnect: false, .. } => break,
_ => {}
}
}
Ok(())
}
Clientは複製できるハンドル。送信系のメソッドはasyncではなく、裏のタスクに積むだけなので音符もすぐ返る。最後のハンドルを捨てるかdisconnect().awaitで切断する- イベントは
Events::recv()で受け取る。部屋に入るとParticipantJoined(自分も含む) のあとChannelが届く - 鍵盤は MPP の名前 (
"c3"が真ん中のド、"a-1"がピアノの一番下) か MIDI 番号 (60が真ん中のド) かKeyで指定する - 通常の接続はつないだ IP のアカウントになる。
name()/set_name()で名前を変えるとサーバーに保存されるので、bot には fake user を使う
fake user
let options = ConnectOptions::new("wss://mpp.example/")
.fake_user(fake_user_password, Some("6f9619ff-8b86-d011-b42d-00cf4fc964ff"))
.name("bot #1")
.channel("test/bots");
同じ UUID なら同じユーザー。None なら接続ごとに別のユーザーになる。fake user はサーバーの DB に保存されない。
サンプル
cargo run --example <名前> -- <URL> [部屋]
| サンプル | 内容 |
|---|---|
echo_bot |
!ping、!who、!scale に答えるチャット bot |
note_logger |
ほかの人が弾いた音を、鳴るべきタイミングで表示する |
room_watcher |
部屋一覧を購読して、変わるたびに表示する |
melody |
色付きのメロディと伴奏の和音を弾いて抜ける |
room_host |
部屋を作り、!solo、!hide、!crown、!kick などのコマンドで管理する |
draw_shapes |
星、円、虹色の線を描く |
fake_swarm |
fake user を何体か入れて、手分けして和音を弾く (MPP_FAKE_PASSWORD が要る) |
cargo run --example echo_bot -- wss://mpp.dev.c30.life/ "test/bot room"
MPP_FAKE_PASSWORD=... cargo run --example fake_swarm -- wss://mpp.dev.c30.life/ test/swarm 4
普通の接続はつないだ IP のアカウントになる。名前を変えるサンプル (echo_bot、melody) は、fake user で動かしたときだけ名前を付ける。
テスト
cargo test # SDK 単体 (鍵盤、バイナリ形式、クォータ)
cargo test --manifest-path server-tests/Cargo.toml # 実サーバー相手の結合テスト
server-tests/ は extended-mppserver-rs をこのリポジトリの隣 (../extended-mppserver-rs) に置いたときだけ動く。サーバーを立てて、SDK 同士で入室、チャット、両形式の音符、クォータ、fake user、再接続、部屋一覧を確かめる。SDK 本体はサーバーに依存しないので、単体で clone してもビルドできる。
ライセンス
MIT (LICENSE)