ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

五分钟上手 SpacetimeDB Rust 模块:用 basic-rs 模板搭建数据表、Reducer 与客户端绑定

2026/9/13 12:03:03 拓冰建站 浏览量
五分钟上手 SpacetimeDB Rust 模块:用 basic-rs 模板搭建数据表、Reducer 与客户端绑定 五分钟上手 SpacetimeDB Rust 模块用 basic-rs 模板搭建数据表、Reducer 与客户端绑定【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB本文是 SpacetimeDB 官方basic-rs模板的完整实战指南围绕 templates/basic-rs/README.md 展开讲解如何用一条命令创建「Rust 服务端模块 Rust 客户端」的完整项目并深入拆解表Table、Reducer、自动生成的客户端绑定与 CLI 联调流程。读完本文你将能够在本地运行 SpacetimeDB 服务器写出可查询、可写入、带日志的服务端模块并用命令行与 Rust SDK 客户端同时与它交互。前置条件准备 Rust 工具链与 SpacetimeDB CLI开始之前需要准备两样东西Rust 工具链SpacetimeDB 模块以cdylib形式编译为 Wasm客户端以普通 Rust 程序运行均依赖 Rust 编译器安装方式参考 rust-lang.org 官方指引本仓库使用 Rust edition 2024 编译模块见下文 Cargo.toml。SpacetimeDB CLI命令行工具spacetime承担了创建项目、启动本地服务器、编译发布模块、生成绑定、执行 SQL、调用 Reducer、查看日志等全部职责。仓库中的安装脚本 crates/update/spacetime-install.sh 提供了 Unix 系的安装路径CLI 的完整命令参考见 skills/cli/SKILL.md。环境就绪后即可进入下一步创建项目。创建项目spacetime dev --template basic-rs在任意目录下运行spacetime dev --template basic-rs这一条命令会一气呵成地完成四件事启动本地 SpacetimeDB 服务器创建一个包含 Rust SpacetimeDB 模块的新项目以basic-rs为模板编译并发布publish你的模块生成 Rust 客户端绑定代码bindings。从 dev 子命令源码 可以看到spacetime dev的本质是「开发模式」它会监听文件变化自动重新生成客户端模块绑定、自动重新构建、自动重新发布。命令行里对该命令的定位描述是Start development mode with auto-regenerate client module bindings, auto-rebuild, and auto-publish on file changes.这对本地迭代非常友好改完服务端代码保存绑定与发布立即更新无需手动执行 build / generate / publish。dev子命令还支持几个实用参数见 dev.rs参数说明默认值--template name指定创建项目所用的模板如basic-rs若当前目录已存在 SpacetimeDB 项目该参数会被忽略并提示警告无--module-bindings-path path客户端绑定目录相对于项目根目录src/module_bindings--client-lang lang生成绑定所用的客户端语言如typescript、csharp、rust、unrealcpp未指定时从项目自动探测自动探测需要注意--module-bindings-path必须是相对路径--module-path、--project-path、--module-bindings-path三个参数不能同时用于创建新项目的场景。另外所有官方服务端模板的模块代码都约定放在spacetimedb/目录下源码注释中明确说明这是所有模板的约定。项目结构一份工程服务端与客户端并存spacetime dev --template basic-rs生成的项目同时包含服务端与客户端代码结构如下my-spacetime-app/ ├── spacetimedb/ # 你的 SpacetimeDB 模块 │ ├── Cargo.toml │ └── src/ │ └── lib.rs # 服务端逻辑 ├── Cargo.toml ├── src/ │ ├── main.rs # 客户端应用 │ └── module_bindings/ # 自动生成的类型 └── README.md对照仓库中的实际模板 templates/basic-rs各文件与职责对应如下服务端模块spacetimedb/src/lib.rs表与 Reducer 的定义都在这里是服务端逻辑的入口服务端 Cargo.tomlspacetimedb/Cargo.toml包名为basic-rs-template-moduleRust edition 2024crate-type [cdylib]编译为 Wasm 动态库依赖spacetimedb源码路径../../../crates/bindings与log 0.4客户端程序src/main.rs用 Rust SDK 连接本地数据库、订阅表并响应数据变化客户端 Cargo.tomlCargo.toml包名spacetimedb-client通过[workspace] exclude [spacetimedb]将服务端模块排除在客户端 workspace 之外依赖spacetimedb-sdk源码路径../../sdks/rust生成绑定src/module_bindings/由 CLI 自动生成的类型与调用代码用于在客户端中安全地访问表与调用 Reducer。其中src/module_bindings/下的文件头部都带有一行醒目标注THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE WILL NOT BE SAVED.—— 提示你不要手工编辑生成文件修改表结构请回到服务端spacetimedb/src/lib.rs重新生成即可。理解表Table与 Reducer数据模型的核心抽象打开spacetimedb/src/lib.rs即可看到模块代码。模板内置了一张Person表和两个 Reduceradd用于插入一个人say_hello用于向所有人问好。核心概念表Table存储数据Reducer 是修改数据的函数是写入数据库的唯一途径。客户端不能直接改表只能调用 Reducer 触发写入。仓库中的模板实际代码比 README 示例更完整除了add与say_hello还包含了三个生命周期回调 Reducer见 templates/basic-rs/spacetimedb/src/lib.rsuse spacetimedb::{ReducerContext, Table}; #[spacetimedb::table(accessor person, public)] pub struct Person { name: String, } #[spacetimedb::reducer(init)] pub fn init(_ctx: ReducerContext) { // Called when the module is initially published } #[spacetimedb::reducer(client_connected)] pub fn identity_connected(_ctx: ReducerContext) { // Called everytime a new client connects } #[spacetimedb::reducer(client_disconnected)] pub fn identity_disconnected(_ctx: ReducerContext) { // Called everytime a client disconnects } #[spacetimedb::reducer] pub fn add(ctx: ReducerContext, name: String) { ctx.db.person().insert(Person { name }); } #[spacetimedb::reducer] pub fn say_hello(ctx: ReducerContext) { for person in ctx.db.person().iter() { log::info!(Hello, {}!, person.name); } log::info!(Hello, World!); }几个关键语法点#[spacetimedb::table(accessor person, public)]声明一个表。accessor person指定访问器名称即后续代码中ctx.db.person()的personpublic标记表为公开可查询。结构体字段即表的列String字段会映射为数据库中的字符串列。#[spacetimedb::reducer]把一个普通函数提升为 Reducer接收ReducerContext作为上下文函数参数即 Reducer 的入参。init、client_connected、client_disconnected是三种特殊类型的 Reducer分别在模块发布、客户端连接、客户端断开时由系统自动触发。ctx.db.person()通过访问器拿到表的句柄insert(...)插入一行iter()遍历所有行。得益于accessor代码读起来像在直接操作person集合。自动生成的客户端绑定服务端类型的安全镜像spacetime dev会在发布模块后根据服务端 schema 自动生成 src/module_bindings/ 下的代码仓库中这份生成文件对应 CLI v2.0.4注释中记录了 commit 号结构如下src/module_bindings/ ├── mod.rs # 总入口Reducer 枚举、DbConnection、各类事件上下文 ├── add_reducer.rs # add Reducer 的调用封装add / add_then ├── person_table.rs # person 表句柄on_insert / on_delete / iter / count ├── person_type.rs # Person 行类型与模块中的 Person 结构体一一对应 └── say_hello_reducer.rs # say_hello Reducer 的调用封装从 mod.rs 可以看到生成代码的整体面貌Reducer枚举把每个 Reducer 变成枚举变体如Reducer::Add { name: String }、Reducer::SayHello并实现reducer_name()与args_bsatn()用 BSATN 序列化参数DbConnection连接远程模块的入口暴露db表、reducersReducer、procedures三组句柄并提供run_threaded()、run_async()、frame_tick()、advance_one_message()等消息推进方式必须调用其中一种否则连接永远不前进事件上下文EventContext、ReducerEventContext、SubscriptionEventContext、ErrorContext等分别用于行回调、Reducer 回调、订阅回调与错误回调表句柄在 person_table.rs 中PersonTableAccess::person()返回PersonTableHandle支持count()、iter()、on_insert(cb)、on_delete(cb)等操作Reducer 调用在 add_reducer.rs 中add(name)发送请求并立即返回add_then(name, cb)额外注册回调在 Reducer 执行完成后获得执行结果。这段生成代码是「类型安全」的体现服务端改表结构后重新生成客户端编译期即可发现不匹配的字段与调用。客户端接入main.rs 是怎么工作的模板自带的客户端 templates/basic-rs/src/main.rs 演示了完整的连接流程mod module_bindings; use module_bindings::*; use std::env; use spacetimedb_sdk::{DbContext, Table}; fn main() { // The URI of the SpacetimeDB instance hosting our chat module. let host: String env::var(SPACETIMEDB_HOST).unwrap_or(http://localhost:3000.to_string()); // The module name we chose when we published our module. let db_name: String env::var(SPACETIMEDB_DB_NAME).unwrap_or(my-db.to_string()); // Connect to the database let conn DbConnection::builder() .with_database_name(db_name) .with_uri(host) .on_connect(|_, _, _| { println!(Connected to SpacetimeDB); }) .on_connect_error(|_ctx, e| { eprintln!(Connection error: {:?}, e); std::process::exit(1); }) .build() .expect(Failed to connect); conn.run_threaded(); // Subscribe to the person table conn.subscription_builder() .on_applied(|_ctx| println!(Subscripted to the person table)) .on_error(|_ctx, e| eprintln!(There was an error when subscring to the person table: {e})) .add_query(|q| q.from.person()) .subscribe(); // Register a callback for when rows are inserted into the person table conn.db().person().on_insert(|_ctx, person| { println!(New person: {}, person.name); }); // Keep the main thread alive so the connection stays open loop { std::thread::sleep(std::time::Duration::from_secs(1)); } }这个客户端展示了四条核心用法构建连接DbConnection::builder()链式指定数据库名默认my-db与 URI默认http://localhost:3000即本地spacetime dev服务器的默认地址并注册连接成功/失败回调两个值均可通过环境变量SPACETIMEDB_HOST、SPACETIMEDB_DB_NAME覆盖推进消息循环conn.run_threaded()派生一个后台线程持续处理 WebSocket 消息让连接「活」起来订阅表subscription_builder().add_query(|q| q.from.person()).subscribe()订阅person表客户端随即在本地维护一份该表的物化视图并可通过on_applied感知订阅生效响应行变化conn.db().person().on_insert(...)注册插入回调——每当person表新增一行例如由其他客户端调用addReducer 触发这个回调就会在本地被触发并打印新行。整体机制是客户端通过订阅维持本地缓存通过回调感知数据变更通过 Reducer 写数据——订阅、回调、调用三者闭环。用 CLI 联调调用 Reducer、查询数据、查看日志本地开发时除了客户端程序还可以直接在终端里通过 CLI 与数据库交互。打开一个新终端进入项目目录cd my-spacetime-app # 调用 add Reducer 插入一个人 spacetime call add Alice # 查询 person 表 spacetime sql SELECT * FROM person name --------- Alice # 调用 say_hello 向所有人问好 spacetime call say_hello # 查看模块日志 spacetime logs 2025-01-13T12:00:00.000000Z INFO: Hello, Alice! 2025-01-13T12:00:00.000000Z INFO: Hello, World!上述命令的通用形式与更多选项参考 skills/cli/SKILL.md如下命令通用形式说明调用 Reducerspacetime call database reducer args...每个参数作为独立的位置参数传入例如spacetime call my-db my_reducer value 123SQL 查询spacetime sql database query支持--interactive进入 REPL 交互模式查看日志spacetime logs database-f持续跟随输出-n num控制返回行数描述 schemaspacetime describe database [table\|reducer] ...支持--json输出可分别查看表与 Reducer 定义在spacetime dev的默认上下文中数据库与模块已自动发布好因此示例里省略了数据库名将项目发布到指定数据库时按上述通用形式补上数据库名即可。say_hello的日志输出顺序也印证了代码逻辑先遍历person表逐行打印问候最后再打印Hello, World!。下一步继续深入的方向跑通模板之后可以沿着仓库内的资源继续深入更多模板参考 templates/chat-console-rs控制台聊天程序、templates/basic-ts、templates/basic-cs 等观察同一套表/Reducer 概念在其他语言与形态下的呈现服务端开发技能skills/rust-server/SKILL.md 整理了 Rust 服务端模块开发的最佳实践与进阶用法核心概念体系skills/concepts/SKILL.md 系统讲解表、Reducer、订阅、身份等 SpacetimeDB 通用概念帮助你把模板中的示例泛化成自己的业务模型Rust SDK 源码sdks/rust 是spacetimedb-sdk的实现客户端main.rs用到的DbContext、Table、订阅构建器等全部在此定义适合深入了解底层机制CLI 深度使用crates/cli/src/subcommands/dev.rs 与 skills/cli/SKILL.md 覆盖spacetime的发布publish、生成generate、服务器管理server等完整命令集可配合 standalone 部署说明 将模块部署到生产环境。【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考