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 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 pub fn id(&self) -> WasmId {
226 format!("{}|{}", self.app_id.clone(), self.canister_type)
227 }
228
229 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 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}