use crate::errors::Error; use rocket::data::{Data, FromData, Outcome, ToByteUnit}; use rocket::request::Request; use std::default::Default; use std::ops::Deref; /// Contains the generated Chronicles of Darkness-related protocol /// buffer types. pub mod cofd { include!(concat!(env!("OUT_DIR"), "/models.proto.cofd.rs")); pub mod api { include!(concat!(env!("OUT_DIR"), "/models.proto.cofd.api.rs")); } // TODO these values are not available in tera templates, so how to // handle? pub(crate) trait DerivedStats { fn speed(&self) -> i32; } impl DerivedStats for CofdSheet { fn speed(&self) -> i32 { self.size + self.stamina } } } /// A struct wrapping a protobuf that allows it to be used as binary /// data submitted via POST using fetch API. Can automatically be /// dereferenced into its wrapped type. #[derive(Debug)] pub(crate) struct Proto(T) where T: prost::Message + Default; /// Converts the body of a POST request containing encoded protobuf /// data into the wrapped type. #[rocket::async_trait] impl FromData for Proto where T: prost::Message + Default, { type Error = crate::errors::Error; async fn from_data(_req: &Request<'_>, data: Data) -> Outcome { use rocket::http::Status; let bytes: Vec = match data.open(2.mebibytes()).stream_to_vec().await { Ok(read_bytes) => read_bytes, Err(e) => return Outcome::Failure((Status::new(422, "invalid protobuf"), e.into())), }; match T::decode(bytes.as_ref()) { Ok(decoded) => Outcome::Success(Proto(decoded)), Err(e) => Outcome::Failure((Status::new(422, "invalid protobuf"), e.into())), } } } impl Deref for Proto where T: prost::Message + Default, { type Target = T; fn deref(&self) -> &T { &self.0 } }