ego_types/
app.rs

1use std::fmt;
2use std::str::FromStr;
3
4use candid::{CandidType, Deserialize, Principal};
5use ic_cdk::api::call::RejectionCode;
6use serde::Serialize;
7
8#[derive(Clone, Debug, CandidType, Deserialize, Serialize, PartialEq)]
9pub struct EgoError {
10  pub code: u16,
11  pub msg: String,
12}
13
14impl EgoError {
15  pub fn new(code: u16, msg: &str) -> Self {
16    EgoError {
17      code,
18      msg: msg.to_string(),
19    }
20  }
21}
22
23impl From<std::string::String> for EgoError {
24  fn from(msg: String) -> Self {
25    EgoError { code: 255, msg }
26  }
27}
28
29impl From<(RejectionCode, std::string::String)> for EgoError {
30  fn from((code, msg): (RejectionCode, String)) -> Self {
31    EgoError {
32      code: code as u16,
33      msg,
34    }
35  }
36}
37
38pub type AppId = String;
39pub type WasmId = String;
40pub type FileId = String;
41
42#[derive(
43CandidType, Serialize, Deserialize, Clone, Copy, Debug, Default, Ord, PartialOrd, Eq, PartialEq,
44)]
45pub struct Version {
46  pub major: u32,
47  pub minor: u32,
48  pub patch: u32,
49}
50
51impl Version {
52  pub fn new(major: u32, minor: u32, patch: u32) -> Version {
53    Version {
54      major,
55      minor,
56      patch,
57    }
58  }
59
60  pub fn min() -> Version {
61    Version {
62      major: 0,
63      minor: 0,
64      patch: 0,
65    }
66  }
67}
68
69impl FromStr for Version {
70  type Err = String;
71
72  fn from_str(s: &str) -> Result<Self, Self::Err> {
73    let parts: Vec<_> = s.split('.').collect();
74    if parts.len() != 3 {
75      return Err(format!("Unable to parse version: {}", s));
76    }
77
78    let major = u32::from_str(parts[0]).map_err(|e| e.to_string())?;
79    let minor = u32::from_str(parts[1]).map_err(|e| e.to_string())?;
80    let patch = u32::from_str(parts[2]).map_err(|e| e.to_string())?;
81
82    Ok(Version {
83      major,
84      minor,
85      patch,
86    })
87  }
88}
89
90impl ToString for Version {
91  fn to_string(&self) -> String {
92    format!("{}.{}.{}", self.major, self.minor, self.patch)
93  }
94}
95
96#[derive(Clone, Debug, CandidType, Deserialize, Serialize, PartialEq)]
97pub enum Category {
98  System,
99  Vault,
100}
101
102#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
103pub struct App {
104  pub app_id: AppId,
105  pub name: String,
106  pub category: Category,
107  pub logo: String,
108  pub description: String,
109  pub current_version: Version,
110  pub price: f32,
111  pub app_hash: String,
112}
113
114impl App {
115  pub fn to_string(&self) -> String {
116    format!(
117      "app_id: {:?}, category: {:?}, current_version: {:?},",
118      self.app_id, self.category, self.current_version
119    )
120  }
121}
122
123impl App {
124  pub fn new(
125    app_id: AppId,
126    name: String,
127    category: Category,
128    logo: String,
129    description: String,
130    current_version: Version,
131    price: f32,
132  ) -> Self {
133    let data = &format!("{}|{}", app_id.clone(), current_version.to_string()).into_bytes();
134    let app_hash = get_md5(data);
135    App {
136      app_id,
137      name,
138      category,
139      logo,
140      description,
141      current_version,
142      price,
143      app_hash,
144    }
145  }
146
147  pub fn app_hash_update(&mut self) {
148    let data = &format!("{}|{}", self.app_id, self.current_version.to_string()).into_bytes();
149    self.app_hash = get_md5(data);
150  }
151}
152
153#[derive(CandidType, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
154pub enum CanisterType {
155  BACKEND,
156  ASSET,
157}
158
159impl fmt::Display for CanisterType {
160  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161    write!(f, "{:?}", self)
162  }
163}
164
165#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
166pub struct Canister {
167  pub canister_id: Principal,
168  pub canister_type: CanisterType,
169}
170
171impl Canister {
172  pub fn new(canister_id: Principal, canister_type: CanisterType) -> Self {
173    Canister {
174      canister_id,
175      canister_type,
176    }
177  }
178}
179
180#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
181pub struct UserApp {
182  pub app: App,
183  pub canister: Canister,
184  pub latest_version: Version,
185  pub wallet_id: Option<Principal>,
186}
187
188impl UserApp {
189  pub fn new(app: &App, canister: Canister, wallet_id: Option<Principal>) -> Self {
190    UserApp {
191      app: app.clone(),
192      latest_version: app.current_version.clone(),
193      canister,
194      wallet_id,
195    }
196  }
197}
198
199#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
200pub struct Wasm {
201  pub app_id: AppId,
202  pub version: Version,
203  pub canister_type: CanisterType,
204  /// when canister_type is ASSET, this will be the shared frontend canister id
205  /// when canister_type is BACKEND, this will be the ego_file canister id used to store the wasm datas
206  pub canister_id: Principal,
207}
208
209impl Wasm {
210  pub fn new(
211    app_id: AppId,
212    version: Version,
213    canister_type: CanisterType,
214    canister_id: Principal,
215  ) -> Self {
216    Wasm {
217      app_id,
218      version,
219      canister_type,
220      canister_id,
221    }
222  }
223
224  /// id of wasm, will be the same across different version
225  pub fn id(&self) -> WasmId {
226    format!("{}|{}", self.app_id.clone(), self.canister_type)
227  }
228
229  /// unique id of wasm file
230  pub fn fid(&self) -> FileId {
231    get_md5(
232      &format!(
233        "{}|{}|{}",
234        self.app_id.clone(),
235        self.canister_type,
236        self.version.to_string()
237      )
238        .into_bytes(),
239    )
240  }
241}
242
243#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
244pub struct CashFlow {
245  pub cash_flow_type: CashFlowType,
246  pub cycles: u128,
247  pub balance: u128,
248  // balance after the operation
249  pub created_at: u64,
250  pub operator: Principal,
251  pub comment: String,
252}
253
254#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq)]
255pub enum CashFlowType {
256  CHARGE,
257  RECHARGE,
258}
259
260impl CashFlow {
261  pub fn new(
262    cash_flow_type: CashFlowType,
263    cycles: u128,
264    balance: u128,
265    operator: Principal,
266    ts: u64,
267    comment: String,
268  ) -> Self {
269    CashFlow {
270      cash_flow_type,
271      cycles,
272      balance,
273      created_at: ts,
274      operator,
275      comment,
276    }
277  }
278}
279
280fn get_md5(data: &Vec<u8>) -> String {
281  let digest = md5::compute(data);
282  return format!("{:?}", digest);
283}