flame_rs/apis/
mod.rs

1/*
2Copyright 2023 The Flame Authors.
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6    http://www.apache.org/licenses/LICENSE-2.0
7Unless required by applicable law or agreed to in writing, software
8distributed under the License is distributed on an "AS IS" BASIS,
9WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10See the License for the specific language governing permissions and
11limitations under the License.
12*/
13
14pub(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    // Initialize tracing with a custom format
241    tracing_subscriber::fmt()
242        .with_env_filter(filter)
243        .with_timer(time_format)
244        .with_target(true)
245        .with_ansi(false)
246        // .with_thread_ids(true)
247        // .with_process_ids(true)
248        .init();
249
250    Ok(())
251}