mcpField
R
rivetkit-client-rust

rivetkit-client-rust

github.com/rivet-dev開発44888 回インストール1 日前に更新
リポジトリ

rivetkit-client-rust について

`rivetkit::client` で Rivet Actors に接続する Rust クライアント開発向けのスキルです。型付きアクションやイベント、接続管理、設定、バックエンドでの利用方法を扱います。

主な機能

  1. 01型付き Actor アクションとイベント
  2. 02ステートレス呼び出しと永続接続
  3. 03型付きイベント購読
  4. 04バックオフ付き自動再接続
  5. 05低レベル HTTP と WebSocket 呼び出し

活用シーン

  1. 01Rust アプリケーションから Rivet Actors を呼び出す
  2. 02接続経由で型付き Actor イベントを受信する
  3. 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

はじめに

  1. 依存関係を追加します
    cargo add rivetkit anyhow async-trait
    cargo add serde --features derive
    cargo add tokio --features full
    
  2. 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 スキルを使用してください。

コメント