chore: bootstrap nana-story M0
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
use nana_domain::{
|
||||
AppInfo, DemoPackSummary, DOMAIN_SCHEMA_VERSION, PlayerView, ResourceBundle, ValidationIssue,
|
||||
validate_bundle,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
const DEMO_PLAYER_VIEW: &str = include_str!("../../fixtures/player-view/initial.json");
|
||||
const DEMO_BUNDLE: &str = include_str!("../../content/nana-demo/bundle.json");
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandError {
|
||||
code: &'static str,
|
||||
message: String,
|
||||
issues: Vec<ValidationIssue>,
|
||||
}
|
||||
|
||||
impl CommandError {
|
||||
fn parse(target: &str, error: &serde_json::Error) -> Self {
|
||||
Self {
|
||||
code: "invalid_embedded_json",
|
||||
message: format!("failed to parse embedded {target}: {error}"),
|
||||
issues: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_app_info() -> AppInfo {
|
||||
AppInfo {
|
||||
name: "听娜娜讲故事".to_owned(),
|
||||
version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
contract_version: DOMAIN_SCHEMA_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_demo_player_view() -> Result<PlayerView, CommandError> {
|
||||
serde_json::from_str(DEMO_PLAYER_VIEW)
|
||||
.map_err(|error| CommandError::parse("PlayerView fixture", &error))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_demo_pack_summary() -> Result<DemoPackSummary, CommandError> {
|
||||
let bundle: ResourceBundle = serde_json::from_str(DEMO_BUNDLE)
|
||||
.map_err(|error| CommandError::parse("content bundle", &error))?;
|
||||
let report = validate_bundle(&bundle);
|
||||
if !report.is_valid() {
|
||||
return Err(CommandError {
|
||||
code: "invalid_content_bundle",
|
||||
message: "the embedded content bundle failed domain validation".to_owned(),
|
||||
issues: report.issues,
|
||||
});
|
||||
}
|
||||
Ok(DemoPackSummary {
|
||||
id: bundle.id,
|
||||
display_name: bundle.display_name,
|
||||
revision: bundle.revision,
|
||||
characters: bundle.characters.len(),
|
||||
world_books: bundle.world_books.len(),
|
||||
personas: bundle.personas.len(),
|
||||
plot_modules: bundle.plot_modules.len(),
|
||||
item_specs: bundle.item_specs.len(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
get_app_info,
|
||||
get_demo_pack_summary,
|
||||
get_demo_player_view
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("failed to run nana-story");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{get_demo_pack_summary, get_demo_player_view};
|
||||
|
||||
#[test]
|
||||
fn embedded_player_view_is_valid() {
|
||||
let view = get_demo_player_view().expect("valid PlayerView fixture");
|
||||
assert_eq!(view.character_name, "娜娜");
|
||||
assert!(!view.beats.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embedded_content_bundle_is_valid() {
|
||||
let summary = get_demo_pack_summary().expect("valid demo bundle");
|
||||
assert_eq!(summary.characters, 1);
|
||||
assert_eq!(summary.plot_modules, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
nana_story_app_lib::run();
|
||||
}
|
||||
Reference in New Issue
Block a user