Integrate unfinished server-rs refactor worklists

This commit is contained in:
2026-04-30 13:39:06 +08:00
parent 62934b0809
commit 7ab0933f6d
676 changed files with 24487 additions and 21531 deletions

View File

@@ -1,3 +1,167 @@
//! 剧情应用编排过渡落位
//! 剧情应用服务与读模型映射
//!
//! 这里只返回剧情快照、事件和待投影结果,不直接调用模型或数据库。
//! 应用层负责把命令变成快照、事件和前端可消费记录;它不直接调用模型、HTTP、
//! SpacetimeDB 或旧 Node 兼容服务。
use crate::commands::{StoryContinueInput, StorySessionInput, normalize_optional_value};
use crate::domain::{INITIAL_STORY_SESSION_VERSION, StorySessionSnapshot, StorySessionStatus};
use crate::errors::StorySessionFieldError;
use crate::events::{StoryEventKind, StoryEventSnapshot};
use serde::{Deserialize, Serialize};
use shared_kernel::format_timestamp_micros;
#[cfg(feature = "spacetime-types")]
use spacetimedb::SpacetimeType;
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StorySessionProcedureResult {
pub ok: bool,
pub session: Option<StorySessionSnapshot>,
pub event: Option<StoryEventSnapshot>,
pub error_message: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StorySessionStateProcedureResult {
pub ok: bool,
pub session: Option<StorySessionSnapshot>,
pub events: Vec<StoryEventSnapshot>,
pub error_message: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StorySessionRecord {
pub story_session_id: String,
pub runtime_session_id: String,
pub actor_user_id: String,
pub world_profile_id: String,
pub initial_prompt: String,
pub opening_summary: Option<String>,
pub latest_narrative_text: String,
pub latest_choice_function_id: Option<String>,
pub status: String,
pub version: u32,
pub created_at: String,
pub updated_at: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StoryEventRecord {
pub event_id: String,
pub story_session_id: String,
pub event_kind: String,
pub narrative_text: String,
pub choice_function_id: Option<String>,
pub created_at: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StorySessionResultRecord {
pub session: StorySessionRecord,
pub event: StoryEventRecord,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StorySessionStateRecord {
pub session: StorySessionRecord,
pub events: Vec<StoryEventRecord>,
}
pub fn build_story_session_snapshot(input: StorySessionInput) -> StorySessionSnapshot {
StorySessionSnapshot {
story_session_id: input.story_session_id,
runtime_session_id: input.runtime_session_id,
actor_user_id: input.actor_user_id,
world_profile_id: input.world_profile_id,
initial_prompt: input.initial_prompt,
opening_summary: normalize_optional_value(input.opening_summary),
latest_narrative_text: String::new(),
latest_choice_function_id: None,
status: StorySessionStatus::Active,
version: INITIAL_STORY_SESSION_VERSION,
created_at_micros: input.created_at_micros,
updated_at_micros: input.created_at_micros,
}
}
pub fn apply_story_continue(
current: StorySessionSnapshot,
input: StoryContinueInput,
) -> Result<(StorySessionSnapshot, StoryEventSnapshot), StorySessionFieldError> {
crate::commands::validate_story_continue_input(&input)?;
if current.version == 0 {
return Err(StorySessionFieldError::InvalidVersion);
}
let event = StoryEventSnapshot {
event_id: input.event_id,
story_session_id: current.story_session_id.clone(),
event_kind: StoryEventKind::StoryContinued,
narrative_text: input.narrative_text.clone(),
choice_function_id: normalize_optional_value(input.choice_function_id),
created_at_micros: input.updated_at_micros,
};
let next = StorySessionSnapshot {
latest_narrative_text: input.narrative_text,
latest_choice_function_id: event.choice_function_id.clone(),
version: current.version + 1,
updated_at_micros: input.updated_at_micros,
..current
};
Ok((next, event))
}
pub fn build_story_session_record(snapshot: StorySessionSnapshot) -> StorySessionRecord {
StorySessionRecord {
story_session_id: snapshot.story_session_id,
runtime_session_id: snapshot.runtime_session_id,
actor_user_id: snapshot.actor_user_id,
world_profile_id: snapshot.world_profile_id,
initial_prompt: snapshot.initial_prompt,
opening_summary: snapshot.opening_summary,
latest_narrative_text: snapshot.latest_narrative_text,
latest_choice_function_id: snapshot.latest_choice_function_id,
status: snapshot.status.as_str().to_string(),
version: snapshot.version,
created_at: format_timestamp_micros(snapshot.created_at_micros),
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
}
}
pub fn build_story_event_record(snapshot: StoryEventSnapshot) -> StoryEventRecord {
StoryEventRecord {
event_id: snapshot.event_id,
story_session_id: snapshot.story_session_id,
event_kind: snapshot.event_kind.as_str().to_string(),
narrative_text: snapshot.narrative_text,
choice_function_id: snapshot.choice_function_id,
created_at: format_timestamp_micros(snapshot.created_at_micros),
}
}
pub fn build_story_session_result_record(
session: StorySessionSnapshot,
event: StoryEventSnapshot,
) -> StorySessionResultRecord {
StorySessionResultRecord {
session: build_story_session_record(session),
event: build_story_event_record(event),
}
}
pub fn build_story_session_state_record(
session: StorySessionSnapshot,
events: Vec<StoryEventSnapshot>,
) -> StorySessionStateRecord {
StorySessionStateRecord {
session: build_story_session_record(session),
events: events
.into_iter()
.map(build_story_event_record)
.collect::<Vec<_>>(),
}
}