1pub(crate) mod flame {
15 tonic::include_proto!("flame");
16}
17use flame as rpc;
18
19use std::fmt::{Display, Formatter};
20use std::fs;
21use std::path::Path;
22
23use bytes::Bytes;
24use prost::Enumeration;
25use serde_derive::{Deserialize, Serialize};
26use thiserror::Error;
27use time::macros::format_description;
28use tonic::Status;
29use tracing_subscriber::filter::{FromEnvError, ParseError};
30use tracing_subscriber::fmt::time::LocalTime;
31
32pub type TaskID = String;
33pub type SessionID = String;
34pub type ApplicationID = String;
35
36type Message = Bytes;
37pub type TaskInput = Message;
38pub type TaskOutput = Message;
39pub type CommonData = Message;
40
41const DEFAULT_FLAME_CONF: &str = "flame-conf.yaml";
42const DEFAULT_CONTEXT_NAME: &str = "flame";
43const DEFAULT_FLAME_ENDPOINT: &str = "http://127.0.0.1:8080";
44
45#[macro_export]
46macro_rules! lock_ptr {
47 ( $mutex_arc:expr ) => {
48 $mutex_arc
49 .lock()
50 .map_err(|_| FlameError::Internal("mutex ptr".to_string()))
51 };
52}
53
54#[macro_export]
55macro_rules! new_ptr {
56 ( $mutex_arc:expr ) => {
57 Arc::new(Mutex::new($mutex_arc))
58 };
59}
60
61#[derive(Error, Debug, Clone)]
62pub enum FlameError {
63 #[error("'{0}' not found")]
64 NotFound(String),
65
66 #[error("{0}")]
67 Internal(String),
68
69 #[error("{0}")]
70 Network(String),
71
72 #[error("{0}")]
73 InvalidConfig(String),
74}
75
76impl From<ParseError> for FlameError {
77 fn from(value: ParseError) -> Self {
78 FlameError::InvalidConfig(value.to_string())
79 }
80}
81
82impl From<FromEnvError> for FlameError {
83 fn from(value: FromEnvError) -> Self {
84 FlameError::InvalidConfig(value.to_string())
85 }
86}
87
88#[derive(
89 Clone, Copy, Debug, PartialEq, Eq, Enumeration, strum_macros::Display, Serialize, Deserialize,
90)]
91pub enum SessionState {
92 Open = 0,
93 Closed = 1,
94}
95
96#[derive(
97 Clone, Copy, Debug, PartialEq, Eq, Enumeration, strum_macros::Display, Serialize, Deserialize,
98)]
99pub enum TaskState {
100 Pending = 0,
101 Running = 1,
102 Succeed = 2,
103 Failed = 3,
104}
105
106#[derive(
107 Clone, Copy, Debug, PartialEq, Eq, Enumeration, strum_macros::Display, Serialize, Deserialize,
108)]
109pub enum ApplicationState {
110 Enabled = 0,
111 Disabled = 1,
112}
113
114#[derive(
115 Clone, Copy, Debug, PartialEq, Eq, Enumeration, strum_macros::Display, Serialize, Deserialize,
116)]
117pub enum Shim {
118 Host = 0,
119 Wasm = 1,
120}
121
122#[derive(
123 Clone, Copy, Debug, PartialEq, Eq, Enumeration, strum_macros::Display, Serialize, Deserialize,
124)]
125pub enum ExecutorState {
126 Unknown = 0,
127 Void = 1,
128 Idle = 2,
129 Binding = 3,
130 Bound = 4,
131 Unbinding = 5,
132 Releasing = 6,
133 Released = 7,
134}
135
136impl From<FlameError> for Status {
137 fn from(value: FlameError) -> Self {
138 match value {
139 FlameError::NotFound(s) => Status::not_found(s),
140 FlameError::Internal(s) => Status::internal(s),
141 _ => Status::unknown(value.to_string()),
142 }
143 }
144}
145
146impl From<Status> for FlameError {
147 fn from(value: Status) -> Self {
148 FlameError::Network(value.message().to_string())
149 }
150}
151
152impl From<rpc::Shim> for Shim {
153 fn from(shim: rpc::Shim) -> Self {
154 match shim {
155 rpc::Shim::Host => Shim::Host,
156 rpc::Shim::Wasm => Shim::Wasm,
157 }
158 }
159}
160
161impl From<rpc::ApplicationState> for ApplicationState {
162 fn from(s: rpc::ApplicationState) -> Self {
163 match s {
164 rpc::ApplicationState::Disabled => Self::Disabled,
165 rpc::ApplicationState::Enabled => Self::Enabled,
166 }
167 }
168}
169
170impl From<rpc::ExecutorState> for ExecutorState {
171 fn from(s: rpc::ExecutorState) -> Self {
172 match s {
173 rpc::ExecutorState::ExecutorVoid => Self::Void,
174 rpc::ExecutorState::ExecutorIdle => Self::Idle,
175 rpc::ExecutorState::ExecutorBinding => Self::Binding,
176 rpc::ExecutorState::ExecutorBound => Self::Bound,
177 rpc::ExecutorState::ExecutorUnbinding => Self::Unbinding,
178 rpc::ExecutorState::ExecutorReleasing => Self::Releasing,
179 rpc::ExecutorState::ExecutorReleased => Self::Released,
180 rpc::ExecutorState::ExecutorUnknown => Self::Unknown,
181 }
182 }
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct FlameContext {
187 pub name: String,
188 pub endpoint: String,
189}
190
191impl Display for FlameContext {
192 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
193 write!(f, "name: {}, endpoint: {}", self.name, self.endpoint)
194 }
195}
196
197impl Default for FlameContext {
198 fn default() -> Self {
199 FlameContext {
200 name: DEFAULT_CONTEXT_NAME.to_string(),
201 endpoint: DEFAULT_FLAME_ENDPOINT.to_string(),
202 }
203 }
204}
205
206impl FlameContext {
207 pub fn from_file(fp: Option<String>) -> Result<Self, FlameError> {
208 let fp = match fp {
209 None => {
210 format!("{}/.flame/{}", env!("HOME", "."), DEFAULT_FLAME_CONF)
211 }
212 Some(path) => path,
213 };
214
215 if !Path::new(&fp).is_file() {
216 return Err(FlameError::InvalidConfig(format!("<{fp}> is not a file")));
217 }
218
219 let contents =
220 fs::read_to_string(fp.clone()).map_err(|e| FlameError::Internal(e.to_string()))?;
221 let ctx: FlameContext =
222 serde_yaml::from_str(&contents).map_err(|e| FlameError::Internal(e.to_string()))?;
223
224 tracing::debug!("Load FrameContext from <{fp}>: {ctx}");
225
226 Ok(ctx)
227 }
228}
229
230pub fn init_logger() -> Result<(), FlameError> {
231 let filter = tracing_subscriber::EnvFilter::try_from_default_env()?
232 .add_directive("h2=error".parse()?)
233 .add_directive("hyper_util=error".parse()?)
234 .add_directive("tower=error".parse()?);
235
236 let time_format = LocalTime::new(format_description!(
237 "[hour repr:24]:[minute]:[second]::[subsecond digits:3]"
238 ));
239
240 tracing_subscriber::fmt()
242 .with_env_filter(filter)
243 .with_timer(time_format)
244 .with_target(true)
245 .with_ansi(false)
246 .init();
249
250 Ok(())
251}