• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2024 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use crate::database::REQUEST_DB;
15 use crate::service::notification_bar::NotificationConfig;
16 
17 const CREATE_TASK_CONFIG_TABLE: &str =
18     "CREATE TABLE IF NOT EXISTS task_config (task_id INTEGER PRIMARY KEY, display BOOLEAN)";
19 
20 const CREATE_GROUP_TABLE: &str =
21     "CREATE TABLE IF NOT EXISTS group_notification (task_id INTEGER PRIMARY KEY, group_id INTEGER)";
22 
23 const CREATE_GROUP_CONFIG_TABLE: &str =
24     "CREATE TABLE IF NOT EXISTS group_notification_config (group_id INTEGER PRIMARY KEY, gauge BOOLEAN, attach_able BOOLEAN, ctime INTEGER)";
25 
26 const CREATE_TASK_CONTENT_TABLE: &str =
27     "CREATE TABLE IF NOT EXISTS task_notification_content (task_id INTEGER PRIMARY KEY, title TEXT, text TEXT)";
28 
29 const CREATE_GROUP_CONTENT_TABLE: &str =
30     "CREATE TABLE IF NOT EXISTS group_notification_content (group_id INTEGER PRIMARY KEY, title TEXT, text TEXT)";
31 
32 const ALERT_GROUP_CONFIG_TABLE: &str =
33     "ALTER TABLE group_notification_config ADD COLUMN display BOOLEAN DEFAULT TRUE";
34 
35 use std::time::{SystemTime, UNIX_EPOCH};
36 
37 const MILLIS_IN_A_WEEK: u64 = 7 * 24 * 60 * 60 * 1000;
38 
39 pub(crate) struct NotificationDb {
40     inner: &'static rdb::RdbStore<'static>,
41 }
42 
43 #[derive(Default, Clone)]
44 pub(crate) struct CustomizedNotification {
45     pub title: Option<String>,
46     pub text: Option<String>,
47 }
48 
49 impl NotificationDb {
new() -> Self50     pub(crate) fn new() -> Self {
51         let me = Self { inner: &REQUEST_DB };
52         if let Err(e) = me.create_db() {
53             error!("Failed to create notification database: {}", e);
54             sys_event!(
55                 ExecFault,
56                 DfxCode::RDB_FAULT_04,
57                 &format!("Failed to create notification database: {}", e)
58             );
59         }
60 
61         me.update();
62         me
63     }
64 
create_db(&self) -> Result<(), i32>65     fn create_db(&self) -> Result<(), i32> {
66         self.inner.execute(CREATE_TASK_CONFIG_TABLE, ())?;
67         self.inner.execute(CREATE_GROUP_CONTENT_TABLE, ())?;
68         self.inner.execute(CREATE_GROUP_TABLE, ())?;
69         self.inner.execute(CREATE_TASK_CONTENT_TABLE, ())?;
70         self.inner.execute(CREATE_GROUP_CONFIG_TABLE, ())?;
71         Ok(())
72     }
73 
update(&self)74     fn update(&self) {
75         let _ = self.inner.execute(ALERT_GROUP_CONFIG_TABLE, ());
76     }
77 
clear_task_info(&self, task_id: u32)78     pub(crate) fn clear_task_info(&self, task_id: u32) {
79         let sqls = [
80             "DELETE FROM task_config WHERE task_id = ?",
81             "DELETE FROM task_notification_content WHERE task_id = ?",
82             "DELETE FROM group_notification WHERE task_id = ?",
83         ];
84         for sql in sqls.iter() {
85             if let Err(e) = self.inner.execute(sql, task_id) {
86                 error!("Failed to clear task {} notification info: {}", task_id, e);
87             }
88         }
89     }
90 
clear_group_info(&self, group_id: u32)91     pub(crate) fn clear_group_info(&self, group_id: u32) {
92         let sqls = [
93             "DELETE FROM group_notification WHERE group_id = ?",
94             "DELETE FROM group_notification_content WHERE group_id = ?",
95             "DELETE FROM group_notification_config WHERE group_id = ?",
96         ];
97         for sql in sqls.iter() {
98             if let Err(e) = self.inner.execute(sql, group_id) {
99                 error!(
100                     "Failed to clear group {} notification info: {}",
101                     group_id, e
102                 );
103             }
104         }
105     }
106 
clear_group_info_a_week_ago(&self)107     pub(crate) fn clear_group_info_a_week_ago(&self) {
108         let current_time = match SystemTime::now().duration_since(UNIX_EPOCH) {
109             Ok(duration) => duration,
110             Err(e) => {
111                 error!("Failed to get current time: {}", e);
112                 return;
113             }
114         }
115         .as_millis() as u64;
116         let group_ids = match self.inner.query::<u32>(
117             "SELECT group_id FROM group_notification_config WHERE ctime < ?",
118             current_time - MILLIS_IN_A_WEEK,
119         ) {
120             Ok(rows) => rows,
121             Err(e) => {
122                 error!("Failed to clear group info: {}", e);
123                 return;
124             }
125         };
126         for group_id in group_ids {
127             let mut count = match self.inner.query::<u32>(
128                 "SELECT COUNT(*) FROM group_notification WHERE group_id = ?",
129                 group_id,
130             ) {
131                 Ok(rows) => rows,
132                 Err(e) => {
133                     error!("Failed to clear group info: {}", e);
134                     continue;
135                 }
136             };
137             if !count.next().is_some_and(|x| x == 0) {
138                 continue;
139             }
140 
141             debug!(
142                 "clear group {} info for have been overdue for more than a week.",
143                 group_id
144             );
145             self.clear_group_info(group_id);
146         }
147     }
148 
check_group_notification_available(&self, group_id: &u32) -> bool149     pub(crate) fn check_group_notification_available(&self, group_id: &u32) -> bool {
150         let mut set = match self.inner.query::<bool>(
151             "SELECT display FROM group_notification_config WHERE group_id = ?",
152             group_id,
153         ) {
154             Ok(set) => set,
155             Err(e) => {
156                 error!("Failed to query group {} notification: {}", group_id, e);
157                 return true;
158             }
159         };
160         set.next().unwrap_or(true)
161     }
162 
check_task_notification_available(&self, task_id: &u32) -> bool163     pub(crate) fn check_task_notification_available(&self, task_id: &u32) -> bool {
164         if let Some(group) = self.query_task_gid(*task_id) {
165             return self.check_group_notification_available(&group);
166         }
167 
168         let mut set = match self
169             .inner
170             .query::<bool>("SELECT display FROM task_config WHERE task_id = ?", task_id)
171         {
172             Ok(set) => set,
173             Err(e) => {
174                 error!("Failed to query task {} notification: {}", task_id, e);
175                 return true;
176             }
177         };
178         set.next().unwrap_or(true)
179     }
180 
disable_task_notification(&self, task_id: u32)181     pub(crate) fn disable_task_notification(&self, task_id: u32) {
182         if let Err(e) = self.inner.execute(
183             "INSERT INTO task_config (task_id, display) VALUES (?, ?) ON CONFLICT(task_id) DO UPDATE SET display = excluded.display",
184             (task_id, false),
185         ) {
186             error!("Failed to update {} notification: {}", task_id, e);
187             sys_event!(ExecFault, DfxCode::RDB_FAULT_04, &format!("Failed to update {} notification: {}", task_id, e));
188         }
189     }
190 
update_task_group(&self, task_id: u32, group_id: u32)191     pub(crate) fn update_task_group(&self, task_id: u32, group_id: u32) {
192         if let Err(e) = self.inner.execute(
193             "INSERT INTO group_notification (task_id, group_id) VALUES (?, ?) ON CONFLICT(task_id) DO UPDATE SET group_id = excluded.group_id",
194             (task_id, group_id),
195         ) {
196             error!("Failed to update {} notification: {}", task_id, e);
197             sys_event!(ExecFault, DfxCode::RDB_FAULT_04, &format!("Failed to update {} notification: {}", task_id, e));
198         }
199     }
200 
query_group_tasks(&self, group_id: u32) -> Vec<u32>201     pub(crate) fn query_group_tasks(&self, group_id: u32) -> Vec<u32> {
202         let set = match self.inner.query::<u32>(
203             "SELECT task_id FROM group_notification WHERE group_id = ?",
204             group_id,
205         ) {
206             Ok(set) => set,
207             Err(e) => {
208                 error!("Failed to query group tasks: {}", e);
209                 sys_event!(
210                     ExecFault,
211                     DfxCode::RDB_FAULT_04,
212                     &format!("Failed to query group tasks: {}", e)
213                 );
214                 return Vec::new();
215             }
216         };
217         set.collect()
218     }
219 
query_task_gid(&self, task_id: u32) -> Option<u32>220     pub(crate) fn query_task_gid(&self, task_id: u32) -> Option<u32> {
221         let mut set = match self.inner.query::<u32>(
222             "SELECT group_id FROM group_notification WHERE task_id = ?",
223             task_id,
224         ) {
225             Ok(set) => set,
226             Err(e) => {
227                 error!("Failed to query task group id: {}", e);
228                 sys_event!(
229                     ExecFault,
230                     DfxCode::RDB_FAULT_04,
231                     &format!("Failed to query task group id: {}", e)
232                 );
233                 return None;
234             }
235         };
236         set.next()
237     }
238 
query_task_customized_notification( &self, task_id: u32, ) -> Option<CustomizedNotification>239     pub(crate) fn query_task_customized_notification(
240         &self,
241         task_id: u32,
242     ) -> Option<CustomizedNotification> {
243         let mut set = match self.inner.query::<(Option<String>, Option<String>)>(
244             "SELECT title, text FROM task_notification_content WHERE task_id = ?",
245             task_id,
246         ) {
247             Ok(set) => set,
248             Err(e) => {
249                 error!("Failed to query task customized notification: {}", e);
250                 sys_event!(
251                     ExecFault,
252                     DfxCode::RDB_FAULT_04,
253                     &format!("Failed to query task customized notification: {}", e)
254                 );
255                 return None;
256             }
257         };
258         set.next()
259             .map(|(title, text)| CustomizedNotification { title, text })
260     }
261 
update_task_customized_notification(&self, config: &NotificationConfig)262     pub(crate) fn update_task_customized_notification(&self, config: &NotificationConfig) {
263         if let Err(e) = self.inner.execute(
264             "INSERT INTO task_notification_content (task_id, title, text) VALUES (?, ?, ?) ON CONFLICT(task_id) DO UPDATE SET title = excluded.title, text = excluded.text",
265             (config.task_id, config.title.clone(), config.text.clone()),
266         ) {
267             error!("Failed to insert {} notification: {}", config.task_id, e);
268             sys_event!(ExecFault, DfxCode::RDB_FAULT_04, &format!("Failed to insert {} notification: {}", config.task_id, e));
269         }
270     }
271 
query_group_customized_notification( &self, group_id: u32, ) -> Option<CustomizedNotification>272     pub(crate) fn query_group_customized_notification(
273         &self,
274         group_id: u32,
275     ) -> Option<CustomizedNotification> {
276         let mut set = match self.inner.query::<(Option<String>, Option<String>)>(
277             "SELECT title, text FROM group_notification_content WHERE group_id = ?",
278             group_id,
279         ) {
280             Ok(set) => set,
281             Err(e) => {
282                 error!("Failed to query task customized notification: {}", e);
283                 sys_event!(
284                     ExecFault,
285                     DfxCode::RDB_FAULT_04,
286                     &format!("Failed to query task customized notification: {}", e)
287                 );
288                 return None;
289             }
290         };
291         set.next()
292             .map(|(title, text)| CustomizedNotification { title, text })
293     }
294 
update_group_customized_notification( &self, group_id: u32, title: Option<String>, text: Option<String>, )295     pub(crate) fn update_group_customized_notification(
296         &self,
297         group_id: u32,
298         title: Option<String>,
299         text: Option<String>,
300     ) {
301         if let Err(e) = self.inner.execute(
302             "INSERT INTO group_notification_content (group_id, title, text) VALUES (?, ?, ?) ON CONFLICT(group_id) DO UPDATE SET title = excluded.title, text = excluded.text",
303             (group_id, title, text),
304         ) {
305             error!("Failed to insert {} notification: {}", group_id, e);
306             sys_event!(ExecFault, DfxCode::RDB_FAULT_04, &format!("Failed to insert {} notification: {}", group_id, e));
307         }
308     }
309 
update_group_config( &self, group_id: u32, gauge: bool, ctime: u64, display: bool, )310     pub(crate) fn update_group_config(
311         &self,
312         group_id: u32,
313         gauge: bool,
314         ctime: u64,
315         display: bool,
316     ) {
317         if let Err(e) = self.inner.execute(
318             "INSERT INTO group_notification_config (group_id, gauge, attach_able, ctime, display) VALUES (?, ?, ?, ?, ?) ON CONFLICT(group_id) DO UPDATE SET gauge = excluded.gauge , ctime = excluded.ctime, display = excluded.display",
319             (group_id, gauge, true, ctime, display),
320         ) {
321             error!("Failed to update {} notification: {}", group_id, e);
322             sys_event!(ExecFault, DfxCode::RDB_FAULT_04, &format!("Failed to update {} notification: {}", group_id, e));
323         }
324     }
325 
contains_group(&self, group_id: u32) -> bool326     pub(crate) fn contains_group(&self, group_id: u32) -> bool {
327         let mut set = match self.inner.query::<u32>(
328             "SELECT group_id FROM group_notification_config where group_id = ?",
329             group_id,
330         ) {
331             Ok(set) => set,
332             Err(e) => {
333                 error!("Failed to query group {} notification: {}", group_id, e);
334                 return false;
335             }
336         };
337         set.row_count() == 1
338     }
339 
attach_able(&self, group_id: u32) -> bool340     pub(crate) fn attach_able(&self, group_id: u32) -> bool {
341         let mut set = match self.inner.query::<bool>(
342             "SELECT attach_able FROM group_notification_config where group_id = ?",
343             group_id,
344         ) {
345             Ok(set) => set,
346             Err(e) => {
347                 error!("Failed to query group {} notification: {}", group_id, e);
348                 return false;
349             }
350         };
351         set.next().unwrap_or(false)
352     }
353 
disable_attach_group(&self, group_id: u32)354     pub(crate) fn disable_attach_group(&self, group_id: u32) {
355         if let Err(e) = self.inner.execute(
356             " UPDATE group_notification_config SET attach_able = ? where group_id = ?",
357             (false, group_id),
358         ) {
359             error!("Failed to update {} notification: {}", group_id, e);
360             sys_event!(
361                 ExecFault,
362                 DfxCode::RDB_FAULT_04,
363                 &format!("Failed to update {} notification: {}", group_id, e)
364             );
365         }
366     }
367 
is_gauge(&self, group_id: u32) -> bool368     pub(crate) fn is_gauge(&self, group_id: u32) -> bool {
369         let mut set = match self.inner.query::<bool>(
370             "SELECT gauge FROM group_notification_config where group_id = ?",
371             group_id,
372         ) {
373             Ok(set) => set,
374             Err(e) => {
375                 error!("Failed to query group {} notification: {}", group_id, e);
376                 return false;
377             }
378         };
379         set.next().unwrap_or(false)
380     }
381 }
382 
383 #[cfg(test)]
384 mod ut_database {
385     include!("../../../tests/ut/service/notification_bar/ut_database.rs");
386 }
387