I've upgraded the API of the example and improved the language slightly. If you have suggested edits, please use the Github feature to suggest edits so I can easily approve them.
I used chatgpt to follow the final tutorial and this is the module you end up with:
use spacetimedb::{table, reducer, Table, ReducerContext, Identity, Timestamp};
#[table(name = user, public)]
pub struct User {
#[primary_key]
identity: Identity,
name: Option<String>,
online: bool,
}
#[table(name = message, public)]
pub struct Message {
sender: Identity,
sent: Timestamp,
text: String,
}
#[reducer]
/// Clients invoke this reducer to set their user names.
pub fn set_name(ctx: &ReducerContext, name: String) -> Result<(), String> {
let name = validate_name(name)?;
if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
ctx.db.user().identity().update(User { name: Some(name), ..user });
Ok(())
} else {
Err("Cannot set name for unknown user".to_string())
}
}
/// Takes a name and checks if it's acceptable as a user's name.
fn validate_name(name: String) -> Result<String, String> {
if name.is_empty() {
Err("Names must not be empty".to_string())
} else {
Ok(name)
}
}
#[reducer]
/// Clients invoke this reducer to send messages.
pub fn send_message(ctx: &ReducerContext, text: String) -> Result<(), String> {
let text = validate_message(text)?;
log::info!("{}", text);
ctx.db.message().insert(Message {
sender: ctx.sender,
text,
sent: ctx.timestamp,
});
Ok(())
}
/// Takes a message's text and checks if it's acceptable to send.
fn validate_message(text: String) -> Result<String, String> {
if text.is_empty() {
Err("Messages must not be empty".to_string())
} else {
Ok(text)
}
}
#[reducer(client_connected)]
// Called when a client connects to the SpacetimeDB
pub fn client_connected(ctx: &ReducerContext) {
if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
// If this is a returning user, i.e. we already have a `User` with this `Identity`,
// set `online: true`, but leave `name` and `identity` unchanged.
ctx.db.user().identity().update(User { online: true, ..user });
} else {
// If this is a new user, create a `User` row for the `Identity`,
// which is online, but hasn't set a name.
ctx.db.user().insert(User {
name: None,
identity: ctx.sender,
online: true,
});
}
}
#[reducer(client_disconnected)]
// Called when a client disconnects from SpacetimeDB
pub fn identity_disconnected(ctx: &ReducerContext) {
if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
ctx.db.user().identity().update(User { online: false, ..user });
} else {
// This branch should be unreachable,
// as it doesn't make sense for a client to disconnect without connecting first.
log::warn!("Disconnect event for unknown user with identity {:?}", ctx.sender);
}
}
Overview
I've upgraded the API of the example and improved the language slightly. If you have suggested edits, please use the Github feature to suggest edits so I can easily approve them.
Rendered: https://github.com/clockworklabs/spacetime-docs/blob/57ccb7a8c3bf569b775eabfb7f7f18eea5314426/docs/modules/rust/quickstart.md
I used chatgpt to follow the final tutorial and this is the module you end up with: