This commit is contained in:
Moritz Ruth 2024-03-05 23:35:51 +01:00
parent 13f307d387
commit 3e129bd3d6
Signed by: moritzruth
GPG key ID: C9BBAB79405EE56D
20 changed files with 1245 additions and 41 deletions

View file

@ -7,6 +7,5 @@ edition = "2021"
deckster_shared = { path = "../deckster_shared" }
thiserror = "1.0.56"
im = "15.1.0"
either = "1.9.0"
serde = { version = "1.0.196", default-features = false }
serde_json = "1.0.113"

View file

@ -2,7 +2,6 @@ use std::any::TypeId;
use std::io;
use std::io::BufRead;
use either::Either;
use serde::de::DeserializeOwned;
use thiserror::Error;
@ -24,41 +23,34 @@ pub trait DecksterHandler {
fn handle(&mut self, event: HandlerEvent);
}
enum Stage<I, H: DecksterHandler> {
Initialization(I),
Active(H),
}
pub fn run<
GlobalConfig: Clone + DeserializeOwned + 'static,
KeyConfig: Clone + DeserializeOwned + 'static,
KnobConfig: Clone + DeserializeOwned + 'static,
H: DecksterHandler,
I: FnOnce(InitialHandlerMessage<KeyConfig, KnobConfig>) -> Result<H, HandlerInitializationError>,
I: FnOnce(InitialHandlerMessage<GlobalConfig, KeyConfig, KnobConfig>) -> Result<H, HandlerInitializationError>,
>(
init_handler: I,
) -> Result<(), RunError> {
let mut handler: Either<H, I> = Either::Right(init_handler);
let mut stage: Stage<I, H> = Stage::Initialization(init_handler);
let requires_global_config = TypeId::of::<GlobalConfig>() != TypeId::of::<()>();
let supports_keys = TypeId::of::<KeyConfig>() != TypeId::of::<()>();
let supports_knobs = TypeId::of::<KnobConfig>() != TypeId::of::<()>();
let handle = io::stdin().lock();
for line in handle.lines() {
let line = line?;
let line = line.map_err(RunError::LineIo)?;
match handler {
Either::Left(mut h) => {
let event: HandlerEvent = serde_json::from_str(&line).map_err(|e| RunError::LineDeserialization {
line,
description: e.to_string(),
})?;
let should_stop = matches!(event, HandlerEvent::Stop);
h.handle(event);
handler = Either::Left(h);
if should_stop {
break;
}
}
Either::Right(init_handler) => {
let initial_message = serde_json::from_str::<InitialHandlerMessage<KeyConfig, KnobConfig>>(&line);
match stage {
Stage::Initialization(init_handler) => {
// TODO: Serialize the global config and each key/knob config separately for more specific error messages.
let initial_message = serde_json::from_str::<InitialHandlerMessage<GlobalConfig, KeyConfig, KnobConfig>>(&line);
match initial_message {
Ok(initial_message) => match init_handler(initial_message) {
@ -67,7 +59,7 @@ pub fn run<
"{}",
serde_json::to_string(&HandlerInitializationResultMessage::Ready).expect("serialization of a known value always works")
);
handler = Either::Left(h)
stage = Stage::Active(h)
}
Err(error) => {
println!(
@ -82,6 +74,7 @@ pub fn run<
"{}",
serde_json::to_string(&HandlerInitializationResultMessage::Error {
error: HandlerInitializationError::InvalidConfig {
requires_global_config,
supports_keys,
supports_knobs,
message: err.to_string().into_boxed_str(),
@ -93,6 +86,21 @@ pub fn run<
}
}
}
Stage::Active(mut h) => {
let event: HandlerEvent = serde_json::from_str(&line).map_err(|e| RunError::LineDeserialization {
line,
description: e.to_string(),
})?;
let should_stop = matches!(event, HandlerEvent::Stop);
h.handle(event);
stage = Stage::Active(h);
if should_stop {
break;
}
}
}
}

View file

@ -90,7 +90,8 @@ pub enum HandlerCommand {
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct InitialHandlerMessage<KeyConfig: Clone, KnobConfig: Clone> {
pub struct InitialHandlerMessage<GlobalConfig: Clone, KeyConfig: Clone, KnobConfig: Clone> {
pub global_config: GlobalConfig,
pub key_configs: HashMap<KeyPath, KeyConfig>,
pub knob_configs: HashMap<KnobPath, KnobConfig>,
}
@ -106,6 +107,7 @@ pub enum HandlerInitializationResultMessage {
pub enum HandlerInitializationError {
#[error("The provided handler config is invalid: {message}")]
InvalidConfig {
requires_global_config: bool,
supports_keys: bool,
supports_knobs: bool,
message: Box<str>,