rivetkit-client-rust について
`rivetkit::client` で Rivet Actors に接続する Rust クライアント開発向けのスキルです。型付きアクションやイベント、接続管理、設定、バックエンドでの利用方法を扱います。
主な機能
- 01型付き Actor アクションとイベント
- 02ステートレス呼び出しと永続接続
- 03型付きイベント購読
- 04バックオフ付き自動再接続
- 05低レベル HTTP と WebSocket 呼び出し
活用シーン
- 01Rust アプリケーションから Rivet Actors を呼び出す
- 02接続経由で型付き Actor イベントを受信する
- 03Tokio バックエンドのハンドラーから Actors を呼び出す
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rivet-dev/ skills --skill rivetkit-client-rustインストール後、Claude Code で/rivetkit-client-rustを入力して読み込まれたか確認します。
同梱ファイルindex.json
詳細
RivetKit Rust クライアント
rivetkit::client を使用して Rivet Actors に接続する Rust クライアントを構築するときに、このスキルを使用してください。
バージョン
RivetKit のバージョン:2.3.7
はじめに
- 依存関係を追加します
cargo add rivetkit anyhow async-trait cargo add serde --features derive cargo add tokio --features full Client::new(ClientConfig::new(endpoint))でクライアントを作成し、get_or_create_typed_default::<A>(...)で型指定されたアクションを呼び出します。
エラー処理ポリシー
- デフォルトでは、フェイルファスト動作を優先してください。
?でanyhow::Resultを伝播させます。 - 絶対に必要な場合を除き、広範な
matchアームでエラーを握りつぶさないでください。 - インラインでエラーを処理する場合は、少なくともログに記録するなど、明示的に処理してください。
Rust のサポートはベータ版です。サポート対象の公開 Rust API は rivetkit と rivetkit::client です。低レベルのクレートは内部実装の詳細であり、安定性は保証されません。完全な API リファレンスは docs.rs/rivetkit を、実行可能な例は hello-world-rust をご覧ください。
はじめに
開始方法については、Rust クイックスタートガイドをご覧ください。
インストール
rivetkit クレートとその関連クレートを追加します。
cargo add rivetkit anyhow async-trait
cargo add serde --features derive
cargo add tokio --features full
Rust クライアントは強い型付けがされています。アクターと同じアクション型およびイベント型を共有するため、アクターを src/lib.rs で定義し、サーバーとクライアントの両方からそれらの型をインポートしてください。クライアント側でアクターを再定義する必要はありません。このページの基礎となるアクター定義については、クイックスタートのアクターを定義するをご覧ください。
最小限のクライアント
use counter::{Counter, Increment};
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let counter = client.get_or_create_typed_default::<Counter>("counter", ["my-counter"])?;
let count = counter.send(Increment { amount: 1 }).await?;
println!("New count: {count}");
Ok(())
}
ここでの counter はクレート名です(Cargo.toml のパッケージ name。ハイフンはアンダースコアに置き換えます)。Counter と Increment は、アクターとともに定義した型です。
ステートレスとステートフル
use counter::{Counter, Increment, NewCount};
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let counter = client.get_or_create_typed_default::<Counter>("counter", ["my-counter"])?;
// Stateless: each call is independent
counter.send(Increment { amount: 1 }).await?;
// Stateful: keep a connection open for realtime events
let connection = counter.connect();
connection
.on::<NewCount>(|event| println!("count: {}", event.count))
.await;
connection.send(Increment { amount: 1 }).await?;
connection.disconnect().await;
Ok(())
}
ハンドルでステートレス呼び出しを行うと、アクションごとに短時間のリクエストが開かれます。接続では WebSocket が開いたままになるため、イベントを受信したり、複数の呼び出しで再利用したりできます。
アクターの取得
use counter::Counter;
use rivetkit::{
client::{Client, ClientConfig, GetOrCreateOptions},
prelude::*,
TypedClientExt,
};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
// Get or create an actor
let room = client.get_or_create_typed_default::<Counter>("counter", ["room-42"])?;
// Get an existing actor handle (fails when used if the actor does not exist)
let existing = client.get_typed_default::<Counter>("counter", ["room-42"])?;
// Create a new actor with input
let created = client.get_or_create_typed::<Counter>(
"counter",
["game-1"],
GetOrCreateOptions {
create_with_input: Some(json!({ "mode": "ranked" })),
..Default::default()
},
)?;
// Get an actor handle by ID
let by_id = client.get_for_id("counter", "actor-id", Default::default())?;
// Resolve the actor ID
let resolved_id = room.inner().resolve().await?;
println!("Resolved ID: {resolved_id}");
Ok(())
}
get_typed_default / get_or_create_typed_default はデフォルトのオプションを使用します。デフォルト以外のバリアント(get_typed / get_or_create_typed)では、接続パラメーター、入力、リージョンを指定する GetOptions / GetOrCreateOptions を受け取ります。1 つのアクターについてクライアントに設定されたプールを上書きするには、GetOrCreateOptions または CreateOptions で pool_name を設定します。
接続パラメーター
ハンドルのオプションを通じて接続パラメーターを渡します。これらはアクターの create_conn_state コールバックに渡されます。
use counter::Counter;
use rivetkit::{
client::{Client, ClientConfig, GetOrCreateOptions},
prelude::*,
TypedClientExt,
};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let chat = client.get_or_create_typed::<Counter>(
"counter",
["general"],
GetOrCreateOptions {
params: Some(json!({ "authToken": "jwt-token-here" })),
..Default::default()
},
)?;
let connection = chat.connect();
connection.disconnect().await;
Ok(())
}
イベントの購読
on はイベントに対する型指定されたコールバックを登録し、購読の登録が完了すると戻ります。
use counter::{Counter, NewCount};
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let connection = client
.get_or_create_typed_default::<Counter>("counter", ["general"])?
.connect();
connection
.on::<NewCount>(|event| println!("count changed: {}", event.count))
.await;
Ok(())
}
イベントコールバックは同期的に実行され、一致するすべてのイベントに対して呼び出されます。アクターが発行したイベント型(ここでは NewCount)は、型指定された値にデコードされます。
接続のライフサイクル
低レベルの接続では、ライフサイクルコールバックと現在のステータスを確認できます。connection.inner() からアクセスします。
use counter::Counter;
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let connection = client
.get_or_create_typed_default::<Counter>("counter", ["general"])?
.connect();
let inner = connection.inner().clone();
inner.on_open(|| println!("connected")).await;
inner.on_close(|| println!("disconnected")).await;
inner.on_error(|message| eprintln!("error: {message}")).await;
inner
.on_status_change(|status| println!("status: {status:?}"))
.await;
println!("current status: {:?}", inner.conn_status());
connection.disconnect().await;
Ok(())
}
ConnectionStatus は Idle、Connecting、Connected、Disconnected のいずれかです。接続は、disconnect を呼び出すまで、バックオフを伴って自動的に再接続します。
低レベルの HTTP と WebSocket
on_request または on_websocket を実装するアクターでは、型なしハンドル(handle.inner())から直接呼び出します。fetch は reqwest::Response を返し、web_socket は tokio_tungstenite ストリームを返します。この例では、追加のクレートもいくつか必要です。
cargo add futures-util tokio-tungstenite
cargo add reqwest --features json
use counter::Counter;
use futures_util::{SinkExt, StreamExt};
use reqwest::{header::HeaderMap, Method};
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
use tokio_tungstenite::tungstenite::Message;
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let handle = client.get_or_create_typed_default::<Counter>("counter", ["general"])?;
// Raw HTTP request
let response = handle
.inner()
.fetch("history", Method::GET, HeaderMap::new(), None)
.await?;
let history: Vec<String> = response.json().await?;
println!("history: {history:?}");
// Raw WebSocket connection
let mut ws = handle.inner().web_socket("stream", None).await?;
ws.send(Message::text("hello")).await?;
if let Some(message) = ws.next().await {
println!("received: {:?}", message?);
}
Ok(())
}
バックエンドからの呼び出し
クライアントは通常の Tokio 型なので、バックエンド(Axum、Actix など)で保持し、リクエストハンドラーからアクターを呼び出せます。クライアントは Clone 可能で、共有しても負荷はほとんどありません。
use counter::{Counter, Increment};
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
async fn increment(client: Client) -> Result<i64> {
let counter = client.get_or_create_typed_default::<Counter>("counter", ["server-counter"])?;
let count = counter.send(Increment { amount: 1 }).await?;
Ok(count)
}
エラー処理
アクションと接続の呼び出しは anyhow::Result を返します。アクター側のエラーは、エラーグループ、コード、メッセージ、メタデータを含む anyhow::Error として表面化します。
use counter::{Counter, Increment};
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
let counter = client.get_or_create_typed_default::<Counter>("counter", ["my-counter"])?;
match counter.send(Increment { amount: 1 }).await {
Ok(count) => println!("count: {count}"),
Err(error) => eprintln!("action failed: {error:#}"),
}
Ok(())
}
概念
キー
キーはアクターインスタンスを一意に識別します。階層的にアドレス指定するには、複合キー(配列)を使用します。
use counter::Counter;
use rivetkit::{
client::{Client, ClientConfig},
prelude::*,
TypedClientExt,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420").namespace("default"));
// Compound key: [org, room]
let room = client.get_or_create_typed_default::<Counter>("counter", ["org-acme", "general"])?;
let actor_id = room.inner().resolve().await?;
println!("Actor ID: {actor_id}");
Ok(())
}
キーには &str または String の配列(["org-acme", "general"])を指定できます。user_id にユーザーデータが含まれる場合は、format!("org:{user_id}") のような文字列補間でキーを作成しないでください。キーインジェクション攻撃を防ぐため、配列を使用してください。
設定
ClientConfig::new(endpoint) はビルダーです。エンドポイントは常に必須で、デフォルト値はありません。一般的なオプションは次のとおりです。
use rivetkit::client::ClientConfig;
let config = ClientConfig::new("http://localhost:6420")
.namespace("default")
.token("pk_...")
.pool_name("my-pool")
.header("x-custom", "value");
namespace- 対象の名前空間(エンジンに設定された名前空間がデフォルトです)。token- エンジンの認証トークン。pool_name- 対象とするランナープール。header/headers- 各リクエストで送信する追加の HTTP ヘッダー。max_input_size- エンコードされたアクション入力のサイズ上限。
サーバーレスデプロイでは、エンドポイントにアプリの /api/rivet URL を設定してください。詳しくはエンドポイントをご覧ください。
API リファレンス
クライアント API の全ドキュメントは docs.rs/rivetkit-clientをご覧ください。
クライアント以外について詳しく知りたい場合
Rivet Actors、レジストリ、またはサーバーサイドの RivetKit について詳しく知りたい場合は、メインスキルを追加してください。
npx skills add rivet-dev/skills
バックエンドのガイダンスには rivetkit スキルを使用してください。