1use num_traits::{FromPrimitive, ToPrimitive};
5use server::{AsScalar, FromScalar, WithAppId};
6use xous::{AppId, PID};
7
8use crate::error::{AppManagerError, LaunchError};
9
10#[derive(Debug, server::Message)]
11#[response(Result<PID, AppManagerError>)]
12pub struct LaunchAppBlocking(pub AppId);
13
14#[derive(Debug, server::Message)]
15#[response(Result<(), AppManagerError>)]
16pub struct RefreshInstalledApps;
17
18impl AsScalar<3> for AppManagerError {
19 fn as_scalar(&self) -> [u32; 3] { [self.to_u32().unwrap(), 0, 0] }
20}
21
22impl FromScalar<3> for AppManagerError {
23 fn from_scalar([e, ..]: [u32; 3]) -> Self {
24 AppManagerError::from_u32(e).unwrap_or(AppManagerError::InternalError)
25 }
26}
27
28#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
29#[event(AppEvent)]
30pub struct SubscribeAppEvents;
31
32#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
33pub enum AppEvent {
34 AppLaunched {
35 #[rkyv(with = WithAppId)]
36 app_id: AppId,
37 pid: PID,
38 launched_by: PID,
39 },
40
41 AppCrashed {
42 #[rkyv(with = WithAppId)]
43 app_id: AppId,
44 pid: PID,
45 launched_by: PID,
46 exit_code: u32,
47 panic_message: Option<String>,
48 },
49
50 LaunchError {
51 #[rkyv(with = WithAppId)]
52 app_id: AppId,
53 error: LaunchError,
54 },
55
56 AppSetChanged {
63 #[rkyv(with = rkyv::with::Map<WithAppId>)]
64 installed: Vec<AppId>,
65 #[rkyv(with = rkyv::with::Map<WithAppId>)]
66 removed: Vec<AppId>,
67 },
68}
69
70#[derive(Debug, server::Message)]
71pub struct LaunchApp(pub AppId);
72#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
73pub struct AppQrMatchRules {
74 #[rkyv(with = WithAppId)]
75 pub id: AppId,
76 pub rules_json: Vec<u8>,
77}
78
79#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
82pub struct InstalledAppPermissionSubgroup {
83 pub key: String,
84 pub label: String,
85 pub approved: bool,
86}
87
88#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
91pub struct InstalledAppPermissionGroup {
92 pub key: String,
93 pub label: String,
94 pub subgroups: Vec<InstalledAppPermissionSubgroup>,
95}
96
97#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
98pub struct InstalledAppInfo {
99 pub app_id: String,
100 pub name: String,
101 pub publisher: String,
102 pub can_launch: bool,
103 pub can_remove: bool,
104 pub version: String,
105 pub size_bytes: u64,
106 pub description: String,
107 pub basic_permissions: Vec<InstalledAppPermissionGroup>,
109 pub approvable_permissions: Vec<InstalledAppPermissionGroup>,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
114pub enum SetAppPermissionGrantResult {
115 Updated,
116 AppNotFound,
117 PermissionNotFound,
118 NotUserGrantable,
119 Unauthorized,
120 StorageUnavailable,
121 InternalError,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
125pub struct PermissionRequestInfo {
126 #[rkyv(with = WithAppId)]
127 pub app_id: AppId,
128 pub app_name: String,
129 pub subgroup: String,
131 pub label: String,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
136pub enum PermissionRequestInfoResult {
137 Prompt(PermissionRequestInfo),
138 AlreadyApproved,
139 Denied,
140 NotGrantable,
141 AppNotFound,
142 Unauthorized,
143 InternalError,
144}
145
146#[derive(
147 Debug, Clone, serde::Serialize, serde::Deserialize, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize,
148)]
149pub struct ThirdPartyCertificateInfo {
150 pub name: String,
151 pub company: String,
152 pub contact_email: String,
153 pub support_url: String,
154 pub public_key: String,
155 #[serde(default)]
156 pub not_before_unix_seconds: Option<u64>,
157 #[serde(default)]
158 pub not_after_unix_seconds: Option<u64>,
159 pub serial_number: String,
160 pub issuer: String,
161 pub subject: String,
162 pub basic_constraints: String,
163 pub key_usage: String,
164 pub extended_key_usage: String,
165}
166
167impl ThirdPartyCertificateInfo {
168 pub fn is_currently_valid(&self) -> bool {
171 let Ok(elapsed) = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) else {
172 return false;
173 };
174 let now = elapsed.as_secs();
175 matches!(
176 (self.not_before_unix_seconds, self.not_after_unix_seconds),
177 (Some(not_before), Some(not_after)) if not_before <= now && now <= not_after
178 )
179 }
180}
181
182#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
183pub enum ImportThirdPartyCertificateResult {
184 Imported(ThirdPartyCertificateInfo),
185 Invalid,
186}
187
188#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
189pub enum RemoveThirdPartyCertificateResult {
190 Removed,
191 NotFound,
192 AppRequiresKey(String),
193 InternalError,
194}
195
196#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
197pub enum RemoveInstalledAppResult {
198 Removed,
199 NotFound,
200 NotSideloaded,
201 Running,
202 InternalError,
203}
204
205#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
206#[response(Option<String>)]
207pub enum GetAppName {
208 ByAppId {
209 #[rkyv(with = WithAppId)]
210 id: AppId,
211 locale: String,
212 },
213
214 ByPid {
215 pid: PID,
216 locale: String,
217 },
218}
219
220impl GetAppName {
221 pub fn new_by_app_id(id: &AppId, locale: &str) -> Self {
222 Self::ByAppId { id: *id, locale: locale.to_string() }
223 }
224
225 pub fn new_by_pid(pid: PID, locale: &str) -> Self { Self::ByPid { pid, locale: locale.to_string() } }
226}
227
228#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
229#[response(Vec<AppQrMatchRules>)]
230pub struct GetQrMatchRules;
231
232#[derive(Debug, Clone, Default, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
235pub struct AppFilter {
236 pub is_flux: Option<bool>,
237 pub third_party: Option<bool>,
238}
239
240impl AppFilter {
241 pub fn standard_only() -> Self { Self { is_flux: Some(false), ..Default::default() } }
243
244 pub fn flux_only() -> Self { Self { is_flux: Some(true), ..Default::default() } }
246
247 pub fn third_party_only() -> Self { Self { third_party: Some(true), ..Default::default() } }
249}
250
251#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
252#[response(Vec<InstalledAppInfo>)]
253pub struct ListApps {
254 pub locale: String,
255 pub filter: AppFilter,
256}
257
258#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
262#[response(Option<Vec<u8>>)]
263pub struct GetAppIcon {
264 pub app_id: String,
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
270pub enum PermissionGrantDecision {
271 Allow,
273 Deny,
275 DenyForRun,
279}
280
281#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
282#[response(SetAppPermissionGrantResult)]
283pub struct SetAppPermissionGrant {
284 pub app_id: String,
285 pub subgroup: String,
287 pub decision: PermissionGrantDecision,
288}
289
290#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
291#[response(PermissionRequestInfoResult)]
292pub struct GetPermissionRequestInfo {
293 pub sender_app_id: [u8; 16],
296 pub server_sid: [u32; 4],
299 pub message_id: usize,
300 pub locale: String,
301}
302
303#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
304#[response(Vec<ThirdPartyCertificateInfo>)]
305pub struct GetThirdPartyCertificates;
306
307#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
308#[response(ImportThirdPartyCertificateResult)]
309pub struct ImportThirdPartyCertificate {
310 pub certificate_pem: Vec<u8>,
311}
312
313#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
314#[response(RemoveThirdPartyCertificateResult)]
315pub struct RemoveThirdPartyCertificate {
316 pub public_key: String,
317 pub locale: String,
318}
319
320#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
321#[response(RemoveInstalledAppResult)]
322pub struct RemoveInstalledApp {
323 #[rkyv(with = WithAppId)]
324 pub app_id: AppId,
325}