thedes_dev/command/
script.rs1use std::{collections::HashMap, path::Path};
2
3use serde::{Deserialize, Serialize};
4use tokio::fs;
5
6use crate::{CommandContext, Error, ErrorKind};
7
8use super::{Command, block::CommandBlock};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct ScriptTable {
13 scripts: HashMap<char, Script>,
14}
15
16impl ScriptTable {
17 pub const DEFAULT_PATH: &str = "thedes-cmd.json";
18
19 pub async fn read_from(path: impl AsRef<Path>) -> Result<Self, Error> {
20 let content = fs::read(path.as_ref())
21 .await
22 .map_err(Error::new_with_path(path.as_ref()))?;
23 let script = serde_json::from_slice(&content[..])
24 .map_err(Error::new_with_path(path.as_ref()))?;
25 Ok(script)
26 }
27
28 pub async fn read() -> Result<Self, Error> {
29 Self::read_from(Self::DEFAULT_PATH).await
30 }
31
32 pub async fn run_reading_from(
33 path: impl AsRef<Path>,
34 key: char,
35 context: &mut CommandContext<'_, '_>,
36 ) -> Result<(), Error> {
37 let table = Self::read_from(path.as_ref()).await?;
38 table.run(key, context).map_err(Error::with_path(path.as_ref()))?;
39 Ok(())
40 }
41
42 pub async fn run_reading(
43 key: char,
44 context: &mut CommandContext<'_, '_>,
45 ) -> Result<(), Error> {
46 Self::run_reading_from(Self::DEFAULT_PATH, key, context).await
47 }
48
49 pub fn run(
50 &self,
51 key: char,
52 context: &mut CommandContext,
53 ) -> Result<(), Error> {
54 match self.scripts.get(&key) {
55 Some(script) => {
56 if let Err(error) = script.run(context) {
57 tracing::error!("Development script failed");
58 tracing::error!("Error chain:");
59 for source in error.chain() {
60 tracing::error!("- {source}");
61 }
62 tracing::error!("Stack backtrace:");
63 tracing::error!("- {}", error.backtrace());
64 }
65 Ok(())
66 },
67 None => Err(Error::new(ErrorKind::UnknownKey(key))),
68 }
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
73#[serde(untagged)]
74enum Script {
75 Single(CommandBlock),
76 List(Vec<CommandBlock>),
77}
78
79impl Command for Script {
80 fn run(&self, context: &mut CommandContext) -> anyhow::Result<()> {
81 match self {
82 Self::Single(block) => block.run(context),
83 Self::List(list) => {
84 for block in list {
85 block.run(context)?
86 }
87 Ok(())
88 },
89 }
90 }
91}