推进 SpacetimeDB adapter 与 client 收口

This commit is contained in:
2026-04-29 16:53:54 +08:00
parent f82775b852
commit 62934b0809
17 changed files with 1023 additions and 597 deletions

View File

@@ -8,8 +8,14 @@ use module_combat::{
BattleMode, BattleStateInput, ResolveCombatActionInput, generate_battle_state_id,
};
use module_npc::{NPC_FIGHT_FUNCTION_ID, NPC_SPAR_FUNCTION_ID, ResolveNpcInteractionInput};
use serde::Deserialize;
use serde_json::{Value, json};
use shared_contracts::story::{
CreateStoryBattleRequest, CreateStoryNpcBattleRequest, CreateStoryNpcBattleResponse,
ResolveStoryBattleRequest, ResolveStoryBattleResponse, StoryBattleRewardItemPayload,
StoryBattleRewardItemRequest, StoryBattleStatePayload, StoryBattleStateResponse,
StoryCombatActionPayload, StoryNpcInteractionPayload, StoryNpcStanceProfilePayload,
StoryNpcStatePayload,
};
use shared_kernel::{normalize_optional_string, normalize_required_string, normalize_string_list};
use spacetime_client::{ResolveNpcBattleInteractionInput, SpacetimeClientError};
@@ -18,84 +24,6 @@ use crate::{
request_context::RequestContext, state::AppState,
};
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateStoryBattleRequest {
pub story_session_id: String,
pub runtime_session_id: String,
#[serde(default)]
pub chapter_id: Option<String>,
pub target_npc_id: String,
pub target_name: String,
pub battle_mode: String,
pub player_hp: i32,
pub player_max_hp: i32,
pub player_mana: i32,
pub player_max_mana: i32,
pub target_hp: i32,
pub target_max_hp: i32,
#[serde(default)]
pub experience_reward: u32,
#[serde(default)]
pub reward_items: Vec<StoryBattleRewardItemRequest>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResolveStoryBattleRequest {
pub battle_state_id: String,
pub function_id: String,
pub action_text: String,
pub base_damage: i32,
pub mana_cost: i32,
pub heal: i32,
pub mana_restore: i32,
pub counter_multiplier_basis_points: u32,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateStoryNpcBattleRequest {
pub story_session_id: String,
pub runtime_session_id: String,
pub npc_id: String,
pub npc_name: String,
pub interaction_function_id: String,
#[serde(default)]
pub release_npc_id: Option<String>,
#[serde(default)]
pub battle_state_id: Option<String>,
pub player_hp: i32,
pub player_max_hp: i32,
pub player_mana: i32,
pub player_max_mana: i32,
pub target_hp: i32,
pub target_max_hp: i32,
#[serde(default)]
pub experience_reward: u32,
#[serde(default)]
pub reward_items: Vec<StoryBattleRewardItemRequest>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StoryBattleRewardItemRequest {
pub item_id: String,
pub category: String,
pub item_name: String,
#[serde(default)]
pub description: Option<String>,
pub quantity: u32,
pub rarity: String,
#[serde(default)]
pub tags: Vec<String>,
pub stackable: bool,
#[serde(default)]
pub stack_key: String,
#[serde(default)]
pub equipment_slot_id: Option<String>,
}
pub async fn create_story_battle(
State(state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
@@ -152,9 +80,9 @@ pub async fn create_story_battle(
Ok(json_success_body(
Some(&request_context),
json!({
"battleState": build_battle_state_payload(&result),
}),
StoryBattleStateResponse {
battle_state: build_battle_state_payload(&result),
},
))
}
@@ -185,14 +113,14 @@ pub async fn resolve_story_battle(
Ok(json_success_body(
Some(&request_context),
json!({
"battleState": build_battle_state_payload(&result.battle_state),
"combat": {
"damageDealt": result.damage_dealt,
"damageTaken": result.damage_taken,
"outcome": result.outcome,
}
}),
ResolveStoryBattleResponse {
battle_state: build_battle_state_payload(&result.battle_state),
combat: StoryCombatActionPayload {
damage_dealt: result.damage_dealt,
damage_taken: result.damage_taken,
outcome: result.outcome,
},
},
))
}
@@ -212,9 +140,9 @@ pub async fn get_story_battle_state(
Ok(json_success_body(
Some(&request_context),
json!({
"battleState": build_battle_state_payload(&result),
}),
StoryBattleStateResponse {
battle_state: build_battle_state_payload(&result),
},
))
}
@@ -278,58 +206,69 @@ pub async fn create_story_npc_battle(
Ok(json_success_body(
Some(&request_context),
json!({
"npcInteraction": build_npc_interaction_payload(&result.npc_interaction),
"battleState": build_battle_state_payload(&result.battle_state),
}),
CreateStoryNpcBattleResponse {
npc_interaction: build_npc_interaction_payload(&result.npc_interaction),
battle_state: build_battle_state_payload(&result.battle_state),
},
))
}
fn build_battle_state_payload(record: &spacetime_client::BattleStateRecord) -> Value {
json!({
"battleStateId": record.battle_state_id,
"storySessionId": record.story_session_id,
"runtimeSessionId": record.runtime_session_id,
"actorUserId": record.actor_user_id,
"chapterId": record.chapter_id,
"targetNpcId": record.target_npc_id,
"targetName": record.target_name,
"battleMode": record.battle_mode,
"status": record.status,
"playerHp": record.player_hp,
"playerMaxHp": record.player_max_hp,
"playerMana": record.player_mana,
"playerMaxMana": record.player_max_mana,
"targetHp": record.target_hp,
"targetMaxHp": record.target_max_hp,
"experienceReward": record.experience_reward,
"rewardItems": record.reward_items.iter().map(|item| {
json!({
"itemId": item.item_id,
"category": item.category,
"itemName": item.item_name,
"description": item.description,
"quantity": item.quantity,
"rarity": format_runtime_item_reward_item_rarity(item.rarity),
"tags": item.tags,
"stackable": item.stackable,
"stackKey": item.stack_key,
"equipmentSlotId": item
.equipment_slot_id
.map(format_runtime_item_equipment_slot),
})
}).collect::<Vec<_>>(),
"turnIndex": record.turn_index,
"lastActionFunctionId": record.last_action_function_id,
"lastActionText": record.last_action_text,
"lastResultText": record.last_result_text,
"lastDamageDealt": record.last_damage_dealt,
"lastDamageTaken": record.last_damage_taken,
"lastOutcome": record.last_outcome,
"version": record.version,
"createdAt": record.created_at,
"updatedAt": record.updated_at,
})
fn build_battle_state_payload(
record: &spacetime_client::BattleStateRecord,
) -> StoryBattleStatePayload {
StoryBattleStatePayload {
battle_state_id: record.battle_state_id.clone(),
story_session_id: record.story_session_id.clone(),
runtime_session_id: record.runtime_session_id.clone(),
actor_user_id: record.actor_user_id.clone(),
chapter_id: record.chapter_id.clone(),
target_npc_id: record.target_npc_id.clone(),
target_name: record.target_name.clone(),
battle_mode: record.battle_mode.clone(),
status: record.status.clone(),
player_hp: record.player_hp,
player_max_hp: record.player_max_hp,
player_mana: record.player_mana,
player_max_mana: record.player_max_mana,
target_hp: record.target_hp,
target_max_hp: record.target_max_hp,
experience_reward: record.experience_reward,
reward_items: record
.reward_items
.iter()
.map(build_battle_reward_item_payload)
.collect(),
turn_index: record.turn_index,
last_action_function_id: record.last_action_function_id.clone(),
last_action_text: record.last_action_text.clone(),
last_result_text: record.last_result_text.clone(),
last_damage_dealt: record.last_damage_dealt,
last_damage_taken: record.last_damage_taken,
last_outcome: record.last_outcome.clone(),
version: record.version,
created_at: record.created_at.clone(),
updated_at: record.updated_at.clone(),
}
}
fn build_battle_reward_item_payload(
item: &module_runtime_item::RuntimeItemRewardItemSnapshot,
) -> StoryBattleRewardItemPayload {
StoryBattleRewardItemPayload {
item_id: item.item_id.clone(),
category: item.category.clone(),
item_name: item.item_name.clone(),
description: item.description.clone(),
quantity: item.quantity,
rarity: format_runtime_item_reward_item_rarity(item.rarity).to_string(),
tags: item.tags.clone(),
stackable: item.stackable,
stack_key: item.stack_key.clone(),
equipment_slot_id: item
.equipment_slot_id
.map(format_runtime_item_equipment_slot)
.map(ToOwned::to_owned),
}
}
fn format_runtime_item_reward_item_rarity(
@@ -354,51 +293,53 @@ fn format_runtime_item_equipment_slot(
}
}
fn build_npc_state_payload(record: &spacetime_client::NpcStateRecord) -> Value {
json!({
"npcStateId": record.npc_state_id,
"runtimeSessionId": record.runtime_session_id,
"npcId": record.npc_id,
"npcName": record.npc_name,
"affinity": record.affinity,
"relationStance": record.relation_stance,
"helpUsed": record.help_used,
"chattedCount": record.chatted_count,
"giftsGiven": record.gifts_given,
"recruited": record.recruited,
"tradeStockSignature": record.trade_stock_signature,
"revealedFacts": record.revealed_facts,
"knownAttributeRumors": record.known_attribute_rumors,
"firstMeaningfulContactResolved": record.first_meaningful_contact_resolved,
"seenBackstoryChapterIds": record.seen_backstory_chapter_ids,
"stanceProfile": {
"trust": record.trust,
"warmth": record.warmth,
"ideologicalFit": record.ideological_fit,
"fearOrGuard": record.fear_or_guard,
"loyalty": record.loyalty,
"currentConflictTag": record.current_conflict_tag,
"recentApprovals": record.recent_approvals,
"recentDisapprovals": record.recent_disapprovals,
fn build_npc_state_payload(record: &spacetime_client::NpcStateRecord) -> StoryNpcStatePayload {
StoryNpcStatePayload {
npc_state_id: record.npc_state_id.clone(),
runtime_session_id: record.runtime_session_id.clone(),
npc_id: record.npc_id.clone(),
npc_name: record.npc_name.clone(),
affinity: record.affinity,
relation_stance: record.relation_stance.clone(),
help_used: record.help_used,
chatted_count: record.chatted_count,
gifts_given: record.gifts_given,
recruited: record.recruited,
trade_stock_signature: record.trade_stock_signature.clone(),
revealed_facts: record.revealed_facts.clone(),
known_attribute_rumors: record.known_attribute_rumors.clone(),
first_meaningful_contact_resolved: record.first_meaningful_contact_resolved,
seen_backstory_chapter_ids: record.seen_backstory_chapter_ids.clone(),
stance_profile: StoryNpcStanceProfilePayload {
trust: record.trust,
warmth: record.warmth,
ideological_fit: record.ideological_fit,
fear_or_guard: record.fear_or_guard,
loyalty: record.loyalty,
current_conflict_tag: record.current_conflict_tag.clone(),
recent_approvals: record.recent_approvals.clone(),
recent_disapprovals: record.recent_disapprovals.clone(),
},
"createdAt": record.created_at,
"updatedAt": record.updated_at,
})
created_at: record.created_at.clone(),
updated_at: record.updated_at.clone(),
}
}
fn build_npc_interaction_payload(record: &spacetime_client::NpcInteractionRecord) -> Value {
json!({
"npcState": build_npc_state_payload(&record.npc_state),
"interactionStatus": record.interaction_status,
"actionText": record.action_text,
"resultText": record.result_text,
"storyText": record.story_text,
"battleMode": record.battle_mode,
"encounterClosed": record.encounter_closed,
"affinityChanged": record.affinity_changed,
"previousAffinity": record.previous_affinity,
"nextAffinity": record.next_affinity,
})
fn build_npc_interaction_payload(
record: &spacetime_client::NpcInteractionRecord,
) -> StoryNpcInteractionPayload {
StoryNpcInteractionPayload {
npc_state: build_npc_state_payload(&record.npc_state),
interaction_status: record.interaction_status.clone(),
action_text: record.action_text.clone(),
result_text: record.result_text.clone(),
story_text: record.story_text.clone(),
battle_mode: record.battle_mode.clone(),
encounter_closed: record.encounter_closed,
affinity_changed: record.affinity_changed,
previous_affinity: record.previous_affinity,
next_affinity: record.next_affinity,
}
}
fn parse_battle_mode_strict(raw: &str) -> Option<BattleMode> {

View File

@@ -138,6 +138,220 @@ pub struct StoryRuntimeProjectionResponse {
pub toast: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct StoryBattleRewardItemRequest {
pub item_id: String,
pub category: String,
pub item_name: String,
#[serde(default)]
pub description: Option<String>,
pub quantity: u32,
pub rarity: String,
#[serde(default)]
pub tags: Vec<String>,
pub stackable: bool,
#[serde(default)]
pub stack_key: String,
#[serde(default)]
pub equipment_slot_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CreateStoryBattleRequest {
pub story_session_id: String,
pub runtime_session_id: String,
#[serde(default)]
pub chapter_id: Option<String>,
pub target_npc_id: String,
pub target_name: String,
pub battle_mode: String,
pub player_hp: i32,
pub player_max_hp: i32,
pub player_mana: i32,
pub player_max_mana: i32,
pub target_hp: i32,
pub target_max_hp: i32,
#[serde(default)]
pub experience_reward: u32,
#[serde(default)]
pub reward_items: Vec<StoryBattleRewardItemRequest>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CreateStoryNpcBattleRequest {
pub story_session_id: String,
pub runtime_session_id: String,
pub npc_id: String,
pub npc_name: String,
pub interaction_function_id: String,
#[serde(default)]
pub release_npc_id: Option<String>,
#[serde(default)]
pub battle_state_id: Option<String>,
pub player_hp: i32,
pub player_max_hp: i32,
pub player_mana: i32,
pub player_max_mana: i32,
pub target_hp: i32,
pub target_max_hp: i32,
#[serde(default)]
pub experience_reward: u32,
#[serde(default)]
pub reward_items: Vec<StoryBattleRewardItemRequest>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ResolveStoryBattleRequest {
pub battle_state_id: String,
pub function_id: String,
pub action_text: String,
pub base_damage: i32,
pub mana_cost: i32,
pub heal: i32,
pub mana_restore: i32,
pub counter_multiplier_basis_points: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryBattleRewardItemPayload {
pub item_id: String,
pub category: String,
pub item_name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub quantity: u32,
pub rarity: String,
pub tags: Vec<String>,
pub stackable: bool,
pub stack_key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub equipment_slot_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryBattleStatePayload {
pub battle_state_id: String,
pub story_session_id: String,
pub runtime_session_id: String,
pub actor_user_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub chapter_id: Option<String>,
pub target_npc_id: String,
pub target_name: String,
pub battle_mode: String,
pub status: String,
pub player_hp: i32,
pub player_max_hp: i32,
pub player_mana: i32,
pub player_max_mana: i32,
pub target_hp: i32,
pub target_max_hp: i32,
pub experience_reward: u32,
pub reward_items: Vec<StoryBattleRewardItemPayload>,
pub turn_index: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_action_function_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_action_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_result_text: Option<String>,
pub last_damage_dealt: i32,
pub last_damage_taken: i32,
pub last_outcome: String,
pub version: u32,
pub created_at: String,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryBattleStateResponse {
pub battle_state: StoryBattleStatePayload,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryCombatActionPayload {
pub damage_dealt: i32,
pub damage_taken: i32,
pub outcome: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ResolveStoryBattleResponse {
pub battle_state: StoryBattleStatePayload,
pub combat: StoryCombatActionPayload,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryNpcStanceProfilePayload {
pub trust: u8,
pub warmth: u8,
pub ideological_fit: u8,
pub fear_or_guard: u8,
pub loyalty: u8,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub current_conflict_tag: Option<String>,
pub recent_approvals: Vec<String>,
pub recent_disapprovals: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryNpcStatePayload {
pub npc_state_id: String,
pub runtime_session_id: String,
pub npc_id: String,
pub npc_name: String,
pub affinity: i32,
pub relation_stance: String,
pub help_used: bool,
pub chatted_count: u32,
pub gifts_given: u32,
pub recruited: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trade_stock_signature: Option<String>,
pub revealed_facts: Vec<String>,
pub known_attribute_rumors: Vec<String>,
pub first_meaningful_contact_resolved: bool,
pub seen_backstory_chapter_ids: Vec<String>,
pub stance_profile: StoryNpcStanceProfilePayload,
pub created_at: String,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StoryNpcInteractionPayload {
pub npc_state: StoryNpcStatePayload,
pub interaction_status: String,
pub action_text: String,
pub result_text: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub story_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub battle_mode: Option<String>,
pub encounter_closed: bool,
pub affinity_changed: bool,
pub previous_affinity: i32,
pub next_affinity: i32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CreateStoryNpcBattleResponse {
pub npc_interaction: StoryNpcInteractionPayload,
pub battle_state: StoryBattleStatePayload,
}
#[cfg(test)]
mod tests {
use super::*;
@@ -312,4 +526,66 @@ mod tests {
assert!(payload.get("viewModel").is_none());
assert!(payload.get("presentation").is_none());
}
#[test]
fn story_battle_responses_use_story_contract_shape() {
let battle_state = StoryBattleStatePayload {
battle_state_id: "battle_1".to_string(),
story_session_id: "storysess_1".to_string(),
runtime_session_id: "runtime_1".to_string(),
actor_user_id: "user_1".to_string(),
chapter_id: None,
target_npc_id: "npc_wolf".to_string(),
target_name: "黑爪狼".to_string(),
battle_mode: "fight".to_string(),
status: "active".to_string(),
player_hp: 28,
player_max_hp: 40,
player_mana: 12,
player_max_mana: 20,
target_hp: 18,
target_max_hp: 30,
experience_reward: 12,
reward_items: vec![StoryBattleRewardItemPayload {
item_id: "wolf-fang".to_string(),
category: "material".to_string(),
item_name: "狼牙".to_string(),
description: None,
quantity: 1,
rarity: "common".to_string(),
tags: vec!["beast".to_string()],
stackable: true,
stack_key: "wolf-fang".to_string(),
equipment_slot_id: None,
}],
turn_index: 1,
last_action_function_id: Some("battle_attack_basic".to_string()),
last_action_text: Some("普通攻击".to_string()),
last_result_text: Some("你击中了黑爪狼。".to_string()),
last_damage_dealt: 10,
last_damage_taken: 3,
last_outcome: "ongoing".to_string(),
version: 2,
created_at: "1.000000Z".to_string(),
updated_at: "2.000000Z".to_string(),
};
let payload = serde_json::to_value(ResolveStoryBattleResponse {
battle_state,
combat: StoryCombatActionPayload {
damage_dealt: 10,
damage_taken: 3,
outcome: "ongoing".to_string(),
},
})
.expect("payload should serialize");
assert_eq!(payload["battleState"]["battleStateId"], json!("battle_1"));
assert_eq!(
payload["battleState"]["rewardItems"][0]["itemName"],
json!("狼牙")
);
assert_eq!(payload["combat"]["damageDealt"], json!(10));
assert!(payload["battleState"].get("chapterId").is_none());
}
}

View File

@@ -14,7 +14,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_profile_list_result);
send_once(&sender, mapped);
},
@@ -38,7 +38,7 @@ impl SpacetimeClient {
.procedures()
.get_custom_world_library_detail_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_library_detail_result);
send_once(&sender, mapped);
});
@@ -57,7 +57,7 @@ impl SpacetimeClient {
.procedures()
.upsert_custom_world_profile_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_library_mutation_result);
send_once(&sender, mapped);
});
@@ -88,7 +88,7 @@ impl SpacetimeClient {
.procedures()
.publish_custom_world_profile_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_library_mutation_result);
send_once(&sender, mapped);
});
@@ -117,7 +117,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_library_mutation_result);
send_once(&sender, mapped);
},
@@ -143,7 +143,7 @@ impl SpacetimeClient {
.procedures()
.delete_custom_world_profile_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_profile_list_result);
send_once(&sender, mapped);
});
@@ -159,7 +159,7 @@ impl SpacetimeClient {
.procedures()
.list_custom_world_gallery_entries_then(move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_gallery_list_result);
send_once(&sender, mapped);
});
@@ -182,7 +182,7 @@ impl SpacetimeClient {
.procedures()
.get_custom_world_gallery_detail_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_library_mutation_result);
send_once(&sender, mapped);
});
@@ -201,7 +201,7 @@ impl SpacetimeClient {
.procedures()
.get_custom_world_gallery_detail_by_code_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_library_mutation_result);
send_once(&sender, mapped);
});
@@ -220,7 +220,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_publish_world_result);
send_once(&sender, mapped);
},
@@ -259,7 +259,7 @@ impl SpacetimeClient {
.procedures()
.create_custom_world_agent_session_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_session_procedure_result);
send_once(&sender, mapped);
});
@@ -282,7 +282,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -302,7 +302,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_works_list_result);
send_once(&sender, mapped);
},
@@ -326,7 +326,7 @@ impl SpacetimeClient {
.procedures()
.delete_custom_world_agent_session_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_works_list_result);
send_once(&sender, mapped);
});
@@ -351,7 +351,7 @@ impl SpacetimeClient {
.procedures()
.get_custom_world_agent_card_detail_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_draft_card_detail_result);
send_once(&sender, mapped);
});
@@ -377,7 +377,7 @@ impl SpacetimeClient {
.procedures()
.execute_custom_world_agent_action_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_action_execute_result);
send_once(&sender, mapped);
});
@@ -403,7 +403,7 @@ impl SpacetimeClient {
.procedures()
.submit_custom_world_agent_message_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_operation_procedure_result);
send_once(&sender, mapped);
});
@@ -451,7 +451,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_operation_procedure_result);
send_once(&sender, mapped);
},
@@ -486,7 +486,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_operation_procedure_result);
send_once(&sender, mapped);
},
@@ -512,7 +512,7 @@ impl SpacetimeClient {
.procedures()
.get_custom_world_agent_operation_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_custom_world_agent_operation_procedure_result);
send_once(&sender, mapped);
});

View File

@@ -575,18 +575,12 @@ pub(crate) fn map_runtime_setting_procedure_result(
result: RuntimeSettingProcedureResult,
) -> Result<RuntimeSettingsRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 runtime settings 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("runtime settings 快照"))?;
Ok(build_runtime_setting_record(map_runtime_setting_snapshot(
snapshot,
@@ -620,16 +614,12 @@ pub(crate) fn map_auth_store_snapshot_import_procedure_result(
result: AuthStoreSnapshotImportProcedureResult,
) -> Result<AuthStoreSnapshotImportRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure ??????".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let record = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB procedure ???????".to_string())
})?;
let record = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("认证快照导入结果"))?;
Ok(AuthStoreSnapshotImportRecord {
imported_user_count: record.imported_user_count,
@@ -642,11 +632,7 @@ pub(crate) fn map_runtime_browse_history_procedure_result(
result: RuntimeBrowseHistoryProcedureResult,
) -> Result<Vec<RuntimeBrowseHistoryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(result
@@ -662,18 +648,12 @@ pub(crate) fn map_runtime_profile_dashboard_procedure_result(
result: RuntimeProfileDashboardProcedureResult,
) -> Result<RuntimeProfileDashboardRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile dashboard 快照"))?;
Ok(build_runtime_profile_dashboard_record(
map_runtime_profile_dashboard_snapshot(snapshot),
@@ -684,11 +664,7 @@ pub(crate) fn map_runtime_profile_wallet_ledger_procedure_result(
result: RuntimeProfileWalletLedgerProcedureResult,
) -> Result<Vec<RuntimeProfileWalletLedgerEntryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(result
@@ -706,18 +682,12 @@ pub(crate) fn map_runtime_profile_wallet_adjustment_procedure_result(
result: RuntimeProfileWalletAdjustmentProcedureResult,
) -> Result<RuntimeProfileDashboardRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile dashboard 快照"))?;
Ok(build_runtime_profile_dashboard_record(
map_runtime_profile_dashboard_snapshot(snapshot),
@@ -728,18 +698,12 @@ pub(crate) fn map_runtime_profile_recharge_center_procedure_result(
result: RuntimeProfileRechargeCenterProcedureResult,
) -> Result<RuntimeProfileRechargeCenterRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 profile recharge center 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile recharge center 快照"))?;
Ok(build_runtime_profile_recharge_center_record(
map_runtime_profile_recharge_center_snapshot(snapshot),
@@ -756,23 +720,15 @@ pub(crate) fn map_runtime_profile_recharge_order_procedure_result(
SpacetimeClientError,
> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let center = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 profile recharge center 快照".to_string(),
)
})?;
let order = result.order.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 profile recharge order 快照".to_string(),
)
})?;
let center = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile recharge center 快照"))?;
let order = result
.order
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile recharge order 快照"))?;
Ok((
build_runtime_profile_recharge_center_record(map_runtime_profile_recharge_center_snapshot(
@@ -788,18 +744,12 @@ pub(crate) fn map_runtime_referral_invite_center_procedure_result(
result: RuntimeReferralInviteCenterProcedureResult,
) -> Result<RuntimeReferralInviteCenterRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 referral invite center 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("referral invite center 快照"))?;
Ok(build_runtime_referral_invite_center_record(
map_runtime_referral_invite_center_snapshot(snapshot),
@@ -810,18 +760,12 @@ pub(crate) fn map_runtime_referral_redeem_procedure_result(
result: RuntimeReferralRedeemProcedureResult,
) -> Result<RuntimeReferralRedeemRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 referral redeem 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("referral redeem 快照"))?;
Ok(build_runtime_referral_redeem_record(
map_runtime_referral_redeem_snapshot(snapshot),
@@ -832,18 +776,12 @@ pub(crate) fn map_runtime_profile_reward_code_redeem_procedure_result(
result: RuntimeProfileRewardCodeRedeemProcedureResult,
) -> Result<RuntimeProfileRewardCodeRedeemRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 reward redeem 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("reward redeem 快照"))?;
Ok(build_runtime_profile_reward_code_redeem_record(
map_runtime_profile_reward_code_redeem_snapshot(snapshot),
@@ -854,16 +792,12 @@ pub(crate) fn map_runtime_profile_redeem_code_admin_procedure_result(
result: RuntimeProfileRedeemCodeAdminProcedureResult,
) -> Result<RuntimeProfileRedeemCodeRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 redeem code 快照".to_string())
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("redeem code 快照"))?;
Ok(build_runtime_profile_redeem_code_record(
map_runtime_profile_redeem_code_snapshot(snapshot),
@@ -874,18 +808,12 @@ pub(crate) fn map_runtime_profile_play_stats_procedure_result(
result: RuntimeProfilePlayStatsProcedureResult,
) -> Result<RuntimeProfilePlayStatsRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 profile play stats 快照".to_string(),
)
})?;
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("profile play stats 快照"))?;
Ok(build_runtime_profile_play_stats_record(
map_runtime_profile_play_stats_snapshot(snapshot),
@@ -896,11 +824,7 @@ pub(crate) fn map_runtime_snapshot_procedure_result(
result: RuntimeSnapshotProcedureResult,
) -> Result<Option<RuntimeSnapshotRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
result
@@ -915,11 +839,8 @@ pub(crate) fn map_runtime_snapshot_procedure_result(
pub(crate) fn map_runtime_snapshot_required_procedure_result(
result: RuntimeSnapshotProcedureResult,
) -> Result<RuntimeSnapshotRecord, SpacetimeClientError> {
map_runtime_snapshot_procedure_result(result)?.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 runtime snapshot 快照".to_string(),
)
})
map_runtime_snapshot_procedure_result(result)?
.ok_or_else(|| SpacetimeClientError::missing_snapshot("runtime snapshot 快照"))
}
pub(crate) fn map_runtime_snapshot_delete_procedure_result(
@@ -932,11 +853,7 @@ pub(crate) fn map_runtime_profile_save_archive_list_procedure_result(
result: RuntimeProfileSaveArchiveProcedureResult,
) -> Result<Vec<RuntimeProfileSaveArchiveRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
result
@@ -955,23 +872,15 @@ pub(crate) fn map_runtime_profile_save_archive_resume_procedure_result(
result: RuntimeProfileSaveArchiveProcedureResult,
) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let archive = result.record.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 save archive 快照".to_string(),
)
})?;
let snapshot = result.current_snapshot.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回恢复后的 runtime snapshot".to_string(),
)
})?;
let archive = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("save archive 快照"))?;
let snapshot = result
.current_snapshot
.ok_or_else(|| SpacetimeClientError::missing_snapshot("恢复后的 runtime snapshot"))?;
Ok((
build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot(
@@ -1004,11 +913,7 @@ pub(crate) fn map_custom_world_profile_list_result(
result: CustomWorldProfileListResult,
) -> Result<Vec<CustomWorldLibraryEntryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
result
@@ -1022,11 +927,7 @@ pub(crate) fn map_custom_world_library_detail_result(
result: CustomWorldLibraryMutationResult,
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let entry = result
@@ -1048,11 +949,7 @@ pub(crate) fn map_custom_world_gallery_list_result(
result: CustomWorldGalleryListResult,
) -> Result<Vec<CustomWorldGalleryEntryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(result
@@ -1066,18 +963,12 @@ pub(crate) fn map_custom_world_library_mutation_result(
result: CustomWorldLibraryMutationResult,
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let entry = result
.entry
.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string())
})
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry"))
.and_then(map_custom_world_library_entry_from_profile_snapshot)?;
let gallery_entry = result
.gallery_entry
@@ -1094,26 +985,16 @@ pub(crate) fn map_custom_world_publish_world_result(
result: CustomWorldPublishWorldResult,
) -> Result<CustomWorldPublishWorldRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let compiled_record = result
.compiled_record
.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 published profile compile 快照".to_string(),
)
})
.ok_or_else(|| SpacetimeClientError::missing_snapshot("published profile compile 快照"))
.and_then(map_custom_world_published_profile_compile_snapshot)?;
let entry = result
.entry
.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string())
})
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry"))
.and_then(map_custom_world_library_entry_from_profile_snapshot)?;
let gallery_entry = result
.gallery_entry
@@ -1121,9 +1002,7 @@ pub(crate) fn map_custom_world_publish_world_result(
.transpose()?;
let session_stage = result
.session_stage
.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB 未返回 session stage".to_string())
})
.ok_or_else(|| SpacetimeClientError::missing_snapshot("session stage"))
.map(map_rpg_agent_stage)?;
Ok(CustomWorldPublishWorldRecord {
@@ -1138,18 +1017,12 @@ pub(crate) fn map_custom_world_agent_session_procedure_result(
result: CustomWorldAgentSessionProcedureResult,
) -> Result<CustomWorldAgentSessionRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let session = result.session.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 custom world agent session 快照".to_string(),
)
})?;
let session = result
.session
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world agent session 快照"))?;
map_custom_world_agent_session_snapshot(session)
}
@@ -1158,17 +1031,11 @@ pub(crate) fn map_custom_world_agent_operation_procedure_result(
result: CustomWorldAgentOperationProcedureResult,
) -> Result<CustomWorldAgentOperationRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let operation = result.operation.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 custom world agent operation 快照".to_string(),
)
SpacetimeClientError::missing_snapshot("custom world agent operation 快照")
})?;
Ok(map_custom_world_agent_operation_snapshot(operation))
@@ -1178,11 +1045,7 @@ pub(crate) fn map_custom_world_works_list_result(
result: CustomWorldWorksListResult,
) -> Result<Vec<CustomWorldWorkSummaryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
result
@@ -1196,18 +1059,12 @@ pub(crate) fn map_custom_world_draft_card_detail_result(
result: CustomWorldDraftCardDetailResult,
) -> Result<CustomWorldDraftCardDetailRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let card = result.card.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 custom world card detail 快照".to_string(),
)
})?;
let card = result
.card
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world card detail 快照"))?;
map_custom_world_draft_card_detail_snapshot(card)
}
@@ -1216,17 +1073,11 @@ pub(crate) fn map_custom_world_agent_action_execute_result(
result: CustomWorldAgentActionExecuteResult,
) -> Result<CustomWorldAgentActionExecuteRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let operation = result.operation.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 custom world action operation 快照".to_string(),
)
SpacetimeClientError::missing_snapshot("custom world action operation 快照")
})?;
Ok(CustomWorldAgentActionExecuteRecord {
@@ -1238,18 +1089,12 @@ pub(crate) fn map_puzzle_agent_session_procedure_result(
result: PuzzleAgentSessionProcedureResult,
) -> Result<PuzzleAgentSessionRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let session_json = result.session_json.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 puzzle agent session 快照".to_string(),
)
})?;
let session_json = result
.session_json
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle agent session 快照"))?;
let session: DomainPuzzleAgentSessionSnapshot =
serde_json::from_str(&session_json).map_err(|error| {
SpacetimeClientError::Runtime(format!("puzzle agent session_json 非法: {error}"))
@@ -1261,16 +1106,12 @@ pub(crate) fn map_puzzle_work_procedure_result(
result: PuzzleWorkProcedureResult,
) -> Result<PuzzleWorkProfileRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let item_json = result.item_json.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle work 快照".to_string())
})?;
let item_json = result
.item_json
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle work 快照"))?;
let item: DomainPuzzleWorkProfile = serde_json::from_str(&item_json).map_err(|error| {
SpacetimeClientError::Runtime(format!("puzzle work item_json 非法: {error}"))
})?;
@@ -1281,18 +1122,12 @@ pub(crate) fn map_puzzle_works_procedure_result(
result: PuzzleWorksProcedureResult,
) -> Result<Vec<PuzzleWorkProfileRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let items_json = result.items_json.ok_or_else(|| {
SpacetimeClientError::Procedure(
"SpacetimeDB procedure 未返回 puzzle works 快照".to_string(),
)
})?;
let items_json = result
.items_json
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle works 快照"))?;
let items: Vec<DomainPuzzleWorkProfile> =
serde_json::from_str(&items_json).map_err(|error| {
SpacetimeClientError::Runtime(format!("puzzle works items_json 非法: {error}"))
@@ -1304,16 +1139,12 @@ pub(crate) fn map_puzzle_run_procedure_result(
result: PuzzleRunProcedureResult,
) -> Result<PuzzleRunRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::Procedure(
result
.error_message
.unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()),
));
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let run_json = result.run_json.ok_or_else(|| {
SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle run 快照".to_string())
})?;
let run_json = result
.run_json
.ok_or_else(|| SpacetimeClientError::missing_snapshot("puzzle run 快照"))?;
let run: DomainPuzzleRunSnapshot = serde_json::from_str(&run_json).map_err(|error| {
SpacetimeClientError::Runtime(format!("puzzle run run_json 非法: {error}"))
})?;
@@ -3214,7 +3045,7 @@ pub(crate) fn parse_big_fish_creation_stage(
"ready_to_publish" => Ok(BigFishCreationStage::ReadyToPublish),
"published" => Ok(BigFishCreationStage::Published),
other => Err(SpacetimeClientError::Runtime(format!(
"big fish creation stage `{other}` ??????"
"big fish creation stage `{other}` 当前尚未支持"
))),
}
}

View File

@@ -21,7 +21,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -45,7 +45,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -71,7 +71,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -101,7 +101,7 @@ impl SpacetimeClient {
.procedures()
.finalize_puzzle_agent_message_turn_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
});
@@ -126,7 +126,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -151,7 +151,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -176,7 +176,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_agent_session_procedure_result);
send_once(&sender, mapped);
},
@@ -206,7 +206,7 @@ impl SpacetimeClient {
.procedures()
.publish_puzzle_work_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_work_procedure_result);
send_once(&sender, mapped);
});
@@ -225,7 +225,7 @@ impl SpacetimeClient {
.procedures()
.list_puzzle_works_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_works_procedure_result);
send_once(&sender, mapped);
});
@@ -244,7 +244,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_work_procedure_result);
send_once(&sender, mapped);
},
@@ -273,7 +273,7 @@ impl SpacetimeClient {
.procedures()
.update_puzzle_work_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_work_procedure_result);
send_once(&sender, mapped);
});
@@ -296,7 +296,7 @@ impl SpacetimeClient {
.procedures()
.delete_puzzle_work_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_works_procedure_result);
send_once(&sender, mapped);
});
@@ -312,7 +312,7 @@ impl SpacetimeClient {
.procedures()
.list_puzzle_gallery_then(move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_works_procedure_result);
send_once(&sender, mapped);
});
@@ -331,7 +331,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_work_procedure_result);
send_once(&sender, mapped);
},
@@ -356,7 +356,7 @@ impl SpacetimeClient {
.procedures()
.start_puzzle_run_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_run_procedure_result);
send_once(&sender, mapped);
});
@@ -379,7 +379,7 @@ impl SpacetimeClient {
.procedures()
.get_puzzle_run_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_run_procedure_result);
send_once(&sender, mapped);
});
@@ -404,7 +404,7 @@ impl SpacetimeClient {
.procedures()
.swap_puzzle_pieces_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_run_procedure_result);
send_once(&sender, mapped);
});
@@ -430,7 +430,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_run_procedure_result);
send_once(&sender, mapped);
},
@@ -454,7 +454,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_run_procedure_result);
send_once(&sender, mapped);
},
@@ -482,7 +482,7 @@ impl SpacetimeClient {
.procedures()
.submit_puzzle_leaderboard_entry_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_puzzle_run_procedure_result);
send_once(&sender, mapped);
});

View File

@@ -14,7 +14,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_setting_procedure_result);
send_once(&sender, mapped);
},
@@ -36,7 +36,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_browse_history_procedure_result);
send_once(&sender, mapped);
},
@@ -58,7 +58,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_dashboard_procedure_result);
send_once(&sender, mapped);
},
@@ -80,7 +80,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_wallet_ledger_procedure_result);
send_once(&sender, mapped);
},
@@ -112,7 +112,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_wallet_adjustment_procedure_result);
send_once(&sender, mapped);
},
@@ -142,7 +142,7 @@ impl SpacetimeClient {
.procedures()
.refund_profile_wallet_points_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_wallet_adjustment_procedure_result);
send_once(&sender, mapped);
});
@@ -163,7 +163,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_recharge_center_procedure_result);
send_once(&sender, mapped);
},
@@ -201,7 +201,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_recharge_order_procedure_result);
send_once(&sender, mapped);
},
@@ -223,7 +223,7 @@ impl SpacetimeClient {
.procedures()
.get_profile_referral_invite_center_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_referral_invite_center_procedure_result);
send_once(&sender, mapped);
});
@@ -247,7 +247,7 @@ impl SpacetimeClient {
.procedures()
.redeem_profile_referral_invite_code_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_referral_redeem_procedure_result);
send_once(&sender, mapped);
});
@@ -271,7 +271,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_reward_code_redeem_procedure_result);
send_once(&sender, mapped);
},
@@ -311,7 +311,7 @@ impl SpacetimeClient {
.procedures()
.admin_upsert_profile_redeem_code_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_redeem_code_admin_procedure_result);
send_once(&sender, mapped);
});
@@ -338,7 +338,7 @@ impl SpacetimeClient {
.procedures()
.admin_disable_profile_redeem_code_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_redeem_code_admin_procedure_result);
send_once(&sender, mapped);
});
@@ -359,7 +359,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_play_stats_procedure_result);
send_once(&sender, mapped);
},
@@ -381,7 +381,7 @@ impl SpacetimeClient {
.procedures()
.get_runtime_snapshot_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_snapshot_procedure_result);
send_once(&sender, mapped);
});
@@ -414,7 +414,7 @@ impl SpacetimeClient {
.procedures()
.upsert_runtime_snapshot_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_snapshot_required_procedure_result);
send_once(&sender, mapped);
});
@@ -435,7 +435,7 @@ impl SpacetimeClient {
.procedures()
.delete_runtime_snapshot_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_snapshot_delete_procedure_result);
send_once(&sender, mapped);
});
@@ -456,7 +456,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_save_archive_list_procedure_result);
send_once(&sender, mapped);
},
@@ -480,7 +480,7 @@ impl SpacetimeClient {
.procedures()
.resume_profile_save_archive_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_profile_save_archive_resume_procedure_result);
send_once(&sender, mapped);
});
@@ -509,7 +509,7 @@ impl SpacetimeClient {
.procedures()
.upsert_runtime_setting_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_setting_procedure_result);
send_once(&sender, mapped);
});
@@ -535,7 +535,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_browse_history_procedure_result);
send_once(&sender, mapped);
},
@@ -559,7 +559,7 @@ impl SpacetimeClient {
procedure_input,
move |_, result| {
let mapped = result
.map_err(|error| SpacetimeClientError::Procedure(error.to_string()))
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_browse_history_procedure_result);
send_once(&sender, mapped);
},

View File

@@ -66,7 +66,6 @@ fn upsert_asset_entity_binding(
return Err("asset_entity_binding.asset_object_id 对应的 asset_object 不存在".to_string());
}
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
// 首版绑定按 entity_kind + entity_id + slot 幂等定位,后续访问量明确后再改为组合索引扫描。
let current = ctx.db.asset_entity_binding().iter().find(|row| {
row.entity_kind == input.entity_kind
@@ -80,7 +79,7 @@ fn upsert_asset_entity_binding(
.asset_entity_binding()
.binding_id()
.delete(&existing.binding_id);
let row = AssetEntityBinding {
let snapshot = AssetEntityBindingSnapshot {
binding_id: existing.binding_id.clone(),
asset_object_id: input.asset_object_id.clone(),
entity_kind: input.entity_kind.clone(),
@@ -89,27 +88,16 @@ fn upsert_asset_entity_binding(
asset_kind: input.asset_kind.clone(),
owner_user_id: input.owner_user_id.clone(),
profile_id: input.profile_id.clone(),
created_at: existing.created_at,
updated_at,
};
ctx.db.asset_entity_binding().insert(row);
AssetEntityBindingSnapshot {
binding_id: existing.binding_id,
asset_object_id: input.asset_object_id,
entity_kind: input.entity_kind,
entity_id: input.entity_id,
slot: input.slot,
asset_kind: input.asset_kind,
owner_user_id: input.owner_user_id,
profile_id: input.profile_id,
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
updated_at_micros: input.updated_at_micros,
}
};
ctx.db
.asset_entity_binding()
.insert(build_asset_entity_binding_row(&snapshot));
snapshot
}
None => {
let created_at = updated_at;
let row = AssetEntityBinding {
let snapshot = AssetEntityBindingSnapshot {
binding_id: input.binding_id.clone(),
asset_object_id: input.asset_object_id.clone(),
entity_kind: input.entity_kind.clone(),
@@ -118,25 +106,30 @@ fn upsert_asset_entity_binding(
asset_kind: input.asset_kind.clone(),
owner_user_id: input.owner_user_id.clone(),
profile_id: input.profile_id.clone(),
created_at,
updated_at,
};
ctx.db.asset_entity_binding().insert(row);
AssetEntityBindingSnapshot {
binding_id: input.binding_id,
asset_object_id: input.asset_object_id,
entity_kind: input.entity_kind,
entity_id: input.entity_id,
slot: input.slot,
asset_kind: input.asset_kind,
owner_user_id: input.owner_user_id,
profile_id: input.profile_id,
created_at_micros: input.updated_at_micros,
updated_at_micros: input.updated_at_micros,
}
};
ctx.db
.asset_entity_binding()
.insert(build_asset_entity_binding_row(&snapshot));
snapshot
}
};
Ok(snapshot)
}
fn build_asset_entity_binding_row(snapshot: &AssetEntityBindingSnapshot) -> AssetEntityBinding {
AssetEntityBinding {
binding_id: snapshot.binding_id.clone(),
asset_object_id: snapshot.asset_object_id.clone(),
entity_kind: snapshot.entity_kind.clone(),
entity_id: snapshot.entity_id.clone(),
slot: snapshot.slot.clone(),
asset_kind: snapshot.asset_kind.clone(),
owner_user_id: snapshot.owner_user_id.clone(),
profile_id: snapshot.profile_id.clone(),
created_at: Timestamp::from_micros_since_unix_epoch(snapshot.created_at_micros),
updated_at: Timestamp::from_micros_since_unix_epoch(snapshot.updated_at_micros),
}
}

View File

@@ -91,7 +91,6 @@ pub(crate) fn upsert_asset_object(
)
.map_err(|error| error.to_string())?;
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
// 这里先保持最小可发布实现:查重语义已经冻结,后续再把实现优化回组合索引扫描。
let current = ctx
.db
@@ -105,7 +104,7 @@ pub(crate) fn upsert_asset_object(
.asset_object()
.asset_object_id()
.delete(&existing.asset_object_id);
let row = AssetObject {
let snapshot = AssetObjectUpsertSnapshot {
asset_object_id: existing.asset_object_id.clone(),
bucket: input.bucket.clone(),
object_key: input.object_key.clone(),
@@ -119,32 +118,16 @@ pub(crate) fn upsert_asset_object(
profile_id: input.profile_id.clone(),
entity_id: input.entity_id.clone(),
asset_kind: input.asset_kind.clone(),
created_at: existing.created_at,
updated_at,
};
ctx.db.asset_object().insert(row);
AssetObjectUpsertSnapshot {
asset_object_id: existing.asset_object_id,
bucket: input.bucket,
object_key: input.object_key,
access_policy: input.access_policy,
content_type: input.content_type,
content_length: input.content_length,
content_hash: input.content_hash,
version: input.version,
source_job_id: input.source_job_id,
owner_user_id: input.owner_user_id,
profile_id: input.profile_id,
entity_id: input.entity_id,
asset_kind: input.asset_kind,
created_at_micros: existing.created_at.to_micros_since_unix_epoch(),
updated_at_micros: input.updated_at_micros,
}
};
ctx.db
.asset_object()
.insert(build_asset_object_row(&snapshot));
snapshot
}
None => {
let created_at = updated_at;
let row = AssetObject {
let snapshot = AssetObjectUpsertSnapshot {
asset_object_id: input.asset_object_id.clone(),
bucket: input.bucket.clone(),
object_key: input.object_key.clone(),
@@ -158,28 +141,13 @@ pub(crate) fn upsert_asset_object(
profile_id: input.profile_id.clone(),
entity_id: input.entity_id.clone(),
asset_kind: input.asset_kind.clone(),
created_at,
updated_at,
};
ctx.db.asset_object().insert(row);
AssetObjectUpsertSnapshot {
asset_object_id: input.asset_object_id,
bucket: input.bucket,
object_key: input.object_key,
access_policy: input.access_policy,
content_type: input.content_type,
content_length: input.content_length,
content_hash: input.content_hash,
version: input.version,
source_job_id: input.source_job_id,
owner_user_id: input.owner_user_id,
profile_id: input.profile_id,
entity_id: input.entity_id,
asset_kind: input.asset_kind,
created_at_micros: input.updated_at_micros,
updated_at_micros: input.updated_at_micros,
}
};
ctx.db
.asset_object()
.insert(build_asset_object_row(&snapshot));
snapshot
}
};
@@ -244,3 +212,23 @@ fn object_key_to_legacy_image_src(object_key: &str) -> String {
}
format!("/{normalized}")
}
fn build_asset_object_row(snapshot: &AssetObjectUpsertSnapshot) -> AssetObject {
AssetObject {
asset_object_id: snapshot.asset_object_id.clone(),
bucket: snapshot.bucket.clone(),
object_key: snapshot.object_key.clone(),
access_policy: snapshot.access_policy,
content_type: snapshot.content_type.clone(),
content_length: snapshot.content_length,
content_hash: snapshot.content_hash.clone(),
version: snapshot.version,
source_job_id: snapshot.source_job_id.clone(),
owner_user_id: snapshot.owner_user_id.clone(),
profile_id: snapshot.profile_id.clone(),
entity_id: snapshot.entity_id.clone(),
asset_kind: snapshot.asset_kind.clone(),
created_at: Timestamp::from_micros_since_unix_epoch(snapshot.created_at_micros),
updated_at: Timestamp::from_micros_since_unix_epoch(snapshot.updated_at_micros),
}
}

View File

@@ -1,3 +1,7 @@
// 中文注释SpacetimeDB 绑定生成依赖根模块继续公开 re-export 各领域类型;
// 少数领域 helper 同名只影响 value namespace 导出,不影响 table / reducer 类型。
#![allow(ambiguous_glob_reexports)]
pub use module_ai::*;
pub use module_assets::*;
pub use module_big_fish::*;

View File

@@ -5,7 +5,8 @@ use spacetimedb_lib::sats::ser::serde::SerializeWrapper;
use std::collections::HashSet;
use crate::puzzle::{
puzzle_agent_message, puzzle_agent_session, puzzle_runtime_run, puzzle_work_profile,
puzzle_agent_message, puzzle_agent_session, puzzle_event, puzzle_leaderboard_entry,
puzzle_runtime_run, puzzle_work_profile,
};
const MIGRATION_SCHEMA_VERSION: u32 = 1;
@@ -140,7 +141,9 @@ macro_rules! migration_tables {
puzzle_agent_session,
puzzle_agent_message,
puzzle_work_profile,
puzzle_event,
puzzle_runtime_run,
puzzle_leaderboard_entry,
big_fish_creation_session,
big_fish_agent_message,
big_fish_asset_slot,

View File

@@ -18,7 +18,7 @@ use module_puzzle::{
};
use serde_json::from_str as json_from_str;
use serde_json::to_string as json_to_string;
use spacetimedb::{ProcedureContext, Table, Timestamp, TxContext};
use spacetimedb::{ProcedureContext, SpacetimeType, Table, Timestamp, TxContext};
/// 拼图 Agent session 真相表。
/// 当前只保存结构化字段与 JSON 草稿,不提前拆出更多编辑态子表。
@@ -84,6 +84,33 @@ pub struct PuzzleWorkProfileRow {
published_at: Option<Timestamp>,
}
/// 拼图创作事件类型。
///
/// 事件表只广播跨层订阅需要的轻量事实,作品真相仍以
/// `puzzle_work_profile` 和 `puzzle_agent_session` 为准。
#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)]
pub enum PuzzleEventKind {
WorkPublished,
}
#[spacetimedb::table(
accessor = puzzle_event,
public,
event,
index(accessor = by_puzzle_event_profile_id, btree(columns = [profile_id])),
index(accessor = by_puzzle_event_owner_user_id, btree(columns = [owner_user_id]))
)]
pub struct PuzzleEvent {
#[primary_key]
event_id: String,
profile_id: String,
work_id: String,
session_id: Option<String>,
owner_user_id: String,
event_kind: PuzzleEventKind,
occurred_at: Timestamp,
}
/// 运行态 run 快照表。
#[spacetimedb::table(
accessor = puzzle_runtime_run,
@@ -869,6 +896,7 @@ fn publish_puzzle_work_tx(
updated_at: Timestamp::from_micros_since_unix_epoch(input.published_at_micros),
},
);
emit_puzzle_work_published_event(ctx, &profile, input.published_at_micros);
Ok(profile)
}
@@ -1543,6 +1571,25 @@ fn upsert_puzzle_work_profile(ctx: &TxContext, profile: PuzzleWorkProfile) -> Re
Ok(())
}
fn emit_puzzle_work_published_event(
ctx: &TxContext,
profile: &PuzzleWorkProfile,
occurred_at_micros: i64,
) {
ctx.db.puzzle_event().insert(PuzzleEvent {
event_id: format!(
"pzevt_{}_{}_published",
profile.profile_id, occurred_at_micros
),
profile_id: profile.profile_id.clone(),
work_id: profile.work_id.clone(),
session_id: profile.source_session_id.clone(),
owner_user_id: profile.owner_user_id.clone(),
event_kind: PuzzleEventKind::WorkPublished,
occurred_at: Timestamp::from_micros_since_unix_epoch(occurred_at_micros),
});
}
fn insert_puzzle_runtime_run(
ctx: &TxContext,
run: &PuzzleRunSnapshot,