Files
Genarrative/server-rs/crates/shared-contracts/src/story.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

165 lines
5.9 KiB
Rust

use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BeginStorySessionRequest {
pub runtime_session_id: String,
pub world_profile_id: String,
pub initial_prompt: String,
#[serde(default)]
pub opening_summary: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ContinueStoryRequest {
pub story_session_id: String,
pub narrative_text: String,
#[serde(default)]
pub choice_function_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct StorySessionPayload {
pub story_session_id: String,
pub runtime_session_id: String,
pub actor_user_id: String,
pub world_profile_id: String,
pub initial_prompt: String,
#[serde(default)]
pub opening_summary: Option<String>,
pub latest_narrative_text: String,
#[serde(default)]
pub latest_choice_function_id: Option<String>,
pub status: String,
pub version: u32,
pub created_at: String,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct StoryEventPayload {
pub event_id: String,
pub story_session_id: String,
pub event_kind: String,
pub narrative_text: String,
#[serde(default)]
pub choice_function_id: Option<String>,
pub created_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct StorySessionMutationResponse {
pub story_session: StorySessionPayload,
pub story_event: StoryEventPayload,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct StorySessionStateResponse {
pub story_session: StorySessionPayload,
pub story_events: Vec<StoryEventPayload>,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn continue_story_request_uses_camel_case_fields() {
let payload = serde_json::to_value(ContinueStoryRequest {
story_session_id: "storysess_1".to_string(),
narrative_text: "继续前进".to_string(),
choice_function_id: Some("npc_chat".to_string()),
})
.expect("payload should serialize");
assert_eq!(
payload,
json!({
"storySessionId": "storysess_1",
"narrativeText": "继续前进",
"choiceFunctionId": "npc_chat"
})
);
}
#[test]
fn story_session_mutation_response_uses_camel_case_fields() {
let payload = serde_json::to_value(StorySessionMutationResponse {
story_session: StorySessionPayload {
story_session_id: "storysess_1".to_string(),
runtime_session_id: "runtime_1".to_string(),
actor_user_id: "user_1".to_string(),
world_profile_id: "profile_1".to_string(),
initial_prompt: "进入营地".to_string(),
opening_summary: Some("营地开场".to_string()),
latest_narrative_text: "篝火正在燃烧。".to_string(),
latest_choice_function_id: Some("talk".to_string()),
status: "active".to_string(),
version: 1,
created_at: "1.000000Z".to_string(),
updated_at: "1.000000Z".to_string(),
},
story_event: StoryEventPayload {
event_id: "storyevt_1".to_string(),
story_session_id: "storysess_1".to_string(),
event_kind: "session_started".to_string(),
narrative_text: "篝火正在燃烧。".to_string(),
choice_function_id: Some("talk".to_string()),
created_at: "1.000000Z".to_string(),
},
})
.expect("payload should serialize");
assert_eq!(
payload["storySession"]["storySessionId"],
json!("storysess_1")
);
assert_eq!(payload["storyEvent"]["eventKind"], json!("session_started"));
assert_eq!(payload["storyEvent"]["choiceFunctionId"], json!("talk"));
}
#[test]
fn story_session_state_response_uses_camel_case_fields() {
let payload = serde_json::to_value(StorySessionStateResponse {
story_session: StorySessionPayload {
story_session_id: "storysess_1".to_string(),
runtime_session_id: "runtime_1".to_string(),
actor_user_id: "user_1".to_string(),
world_profile_id: "profile_1".to_string(),
initial_prompt: "进入营地".to_string(),
opening_summary: Some("营地开场".to_string()),
latest_narrative_text: "你看见篝火边有人招手。".to_string(),
latest_choice_function_id: Some("talk_to_npc".to_string()),
status: "active".to_string(),
version: 2,
created_at: "1.000000Z".to_string(),
updated_at: "2.000000Z".to_string(),
},
story_events: vec![StoryEventPayload {
event_id: "storyevt_2".to_string(),
story_session_id: "storysess_1".to_string(),
event_kind: "story_continued".to_string(),
narrative_text: "你看见篝火边有人招手。".to_string(),
choice_function_id: Some("talk_to_npc".to_string()),
created_at: "2.000000Z".to_string(),
}],
})
.expect("payload should serialize");
assert_eq!(
payload["storySession"]["latestChoiceFunctionId"],
json!("talk_to_npc")
);
assert_eq!(
payload["storyEvents"][0]["eventKind"],
json!("story_continued")
);
}
}