Skip to main content

thedes_dev/command/
script.rs

1use 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}