Files
Genarrative/server-rs/crates/spacetime-module/src/runtime/settings.rs
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

142 lines
4.7 KiB
Rust

use crate::*;
#[spacetimedb::table(accessor = runtime_setting)]
pub struct RuntimeSetting {
#[primary_key]
pub(crate) user_id: String,
pub(crate) music_volume: f32,
pub(crate) platform_theme: RuntimePlatformTheme,
pub(crate) created_at: Timestamp,
pub(crate) updated_at: Timestamp,
}
// procedure 面向 Axum 同步读取设置;若没有持久化记录则返回默认值快照,但不产生额外写入。
#[spacetimedb::procedure]
pub fn get_runtime_setting_or_default(
ctx: &mut ProcedureContext,
input: RuntimeSettingGetInput,
) -> RuntimeSettingProcedureResult {
match ctx.try_with_tx(|tx| get_runtime_setting_snapshot(tx, input.clone())) {
Ok(record) => RuntimeSettingProcedureResult {
ok: true,
record: Some(record),
error_message: None,
},
Err(message) => RuntimeSettingProcedureResult {
ok: false,
record: None,
error_message: Some(message),
},
}
}
// procedure 面向 Axum 同步写入设置,并返回最终归一化后的持久化结果。
#[spacetimedb::procedure]
pub fn upsert_runtime_setting_and_return(
ctx: &mut ProcedureContext,
input: RuntimeSettingUpsertInput,
) -> RuntimeSettingProcedureResult {
match ctx.try_with_tx(|tx| upsert_runtime_setting(tx, input.clone())) {
Ok(record) => RuntimeSettingProcedureResult {
ok: true,
record: Some(record),
error_message: None,
},
Err(message) => RuntimeSettingProcedureResult {
ok: false,
record: None,
error_message: Some(message),
},
}
}
fn get_runtime_setting_snapshot(
ctx: &ReducerContext,
input: RuntimeSettingGetInput,
) -> Result<RuntimeSettingSnapshot, String> {
let validated_input =
build_runtime_setting_get_input(input.user_id).map_err(|error| error.to_string())?;
if let Some(existing) = ctx
.db
.runtime_setting()
.user_id()
.find(&validated_input.user_id)
{
return Ok(RuntimeSettingSnapshot {
user_id: existing.user_id,
music_volume: existing.music_volume,
platform_theme: existing.platform_theme,
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
updated_at_micros: existing.updated_at.to_micros_since_unix_epoch(),
});
}
Ok(RuntimeSettingSnapshot {
user_id: validated_input.user_id,
music_volume: DEFAULT_MUSIC_VOLUME,
platform_theme: DEFAULT_PLATFORM_THEME,
created_at_micros: 0,
updated_at_micros: 0,
})
}
fn upsert_runtime_setting(
ctx: &ReducerContext,
input: RuntimeSettingUpsertInput,
) -> Result<RuntimeSettingSnapshot, String> {
let validated_input = build_runtime_setting_upsert_input(
input.user_id,
input.music_volume,
input.platform_theme,
input.updated_at_micros,
)
.map_err(|error| error.to_string())?;
let updated_at = Timestamp::from_micros_since_unix_epoch(validated_input.updated_at_micros);
let snapshot = match ctx
.db
.runtime_setting()
.user_id()
.find(&validated_input.user_id)
{
Some(existing) => {
ctx.db.runtime_setting().user_id().delete(&existing.user_id);
ctx.db.runtime_setting().insert(RuntimeSetting {
user_id: existing.user_id.clone(),
music_volume: validated_input.music_volume,
platform_theme: validated_input.platform_theme,
created_at: existing.created_at,
updated_at,
});
RuntimeSettingSnapshot {
user_id: existing.user_id,
music_volume: validated_input.music_volume,
platform_theme: validated_input.platform_theme,
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
updated_at_micros: validated_input.updated_at_micros,
}
}
None => {
ctx.db.runtime_setting().insert(RuntimeSetting {
user_id: validated_input.user_id.clone(),
music_volume: validated_input.music_volume,
platform_theme: validated_input.platform_theme,
created_at: updated_at,
updated_at,
});
RuntimeSettingSnapshot {
user_id: validated_input.user_id,
music_volume: validated_input.music_volume,
platform_theme: validated_input.platform_theme,
created_at_micros: validated_input.updated_at_micros,
updated_at_micros: validated_input.updated_at_micros,
}
}
};
Ok(snapshot)
}