Files
Genarrative/server-rs/crates/spacetime-module/src/auth.rs

123 lines
3.7 KiB
Rust

use crate::*;
const AUTH_STORE_SNAPSHOT_ID: &str = "default";
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
pub struct AuthStoreSnapshotRecord {
pub snapshot_json: Option<String>,
pub updated_at_micros: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
pub struct AuthStoreSnapshotUpsertInput {
pub snapshot_json: String,
pub updated_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
pub struct AuthStoreSnapshotProcedureResult {
pub ok: bool,
pub record: Option<AuthStoreSnapshotRecord>,
pub error_message: Option<String>,
}
#[spacetimedb::table(accessor = auth_store_snapshot)]
pub struct AuthStoreSnapshot {
#[primary_key]
pub(crate) snapshot_id: String,
pub(crate) snapshot_json: String,
pub(crate) updated_at: Timestamp,
}
// Axum 启动恢复认证状态时读取当前快照;记录不存在代表尚未产生登录态。
#[spacetimedb::procedure]
pub fn get_auth_store_snapshot(ctx: &mut ProcedureContext) -> AuthStoreSnapshotProcedureResult {
match ctx.try_with_tx(|tx| get_auth_store_snapshot_tx(tx)) {
Ok(record) => AuthStoreSnapshotProcedureResult {
ok: true,
record: Some(record),
error_message: None,
},
Err(message) => AuthStoreSnapshotProcedureResult {
ok: false,
record: None,
error_message: Some(message),
},
}
}
// Axum 每次鉴权仓储变更后覆盖写入整份快照,后续拆表阶段再替换为细粒度 reducer。
#[spacetimedb::procedure]
pub fn upsert_auth_store_snapshot(
ctx: &mut ProcedureContext,
input: AuthStoreSnapshotUpsertInput,
) -> AuthStoreSnapshotProcedureResult {
match ctx.try_with_tx(|tx| upsert_auth_store_snapshot_tx(tx, input.clone())) {
Ok(record) => AuthStoreSnapshotProcedureResult {
ok: true,
record: Some(record),
error_message: None,
},
Err(message) => AuthStoreSnapshotProcedureResult {
ok: false,
record: None,
error_message: Some(message),
},
}
}
fn get_auth_store_snapshot_tx(ctx: &ReducerContext) -> Result<AuthStoreSnapshotRecord, String> {
Ok(
match ctx
.db
.auth_store_snapshot()
.snapshot_id()
.find(&AUTH_STORE_SNAPSHOT_ID.to_string())
{
Some(row) => AuthStoreSnapshotRecord {
snapshot_json: Some(row.snapshot_json),
updated_at_micros: Some(row.updated_at.to_micros_since_unix_epoch()),
},
None => AuthStoreSnapshotRecord {
snapshot_json: None,
updated_at_micros: None,
},
},
)
}
fn upsert_auth_store_snapshot_tx(
ctx: &ReducerContext,
input: AuthStoreSnapshotUpsertInput,
) -> Result<AuthStoreSnapshotRecord, String> {
let snapshot_json = input.snapshot_json.trim().to_string();
if snapshot_json.is_empty() {
return Err("认证快照 JSON 不能为空".to_string());
}
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
if ctx
.db
.auth_store_snapshot()
.snapshot_id()
.find(&AUTH_STORE_SNAPSHOT_ID.to_string())
.is_some()
{
ctx.db
.auth_store_snapshot()
.snapshot_id()
.delete(&AUTH_STORE_SNAPSHOT_ID.to_string());
}
ctx.db.auth_store_snapshot().insert(AuthStoreSnapshot {
snapshot_id: AUTH_STORE_SNAPSHOT_ID.to_string(),
snapshot_json: snapshot_json.clone(),
updated_at,
});
Ok(AuthStoreSnapshotRecord {
snapshot_json: Some(snapshot_json),
updated_at_micros: Some(input.updated_at_micros),
})
}