1 // Copyright (C) 2023 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 std::sync::LazyLock;
15 use std::time::{SystemTime, UNIX_EPOCH};
16
17 use rdb::config::SecurityLevel;
18 use rdb::{OpenConfig, RdbStore};
19
20 use crate::service::notification_bar::NotificationDispatcher;
21
22 const DB_PATH: &str = if cfg!(test) {
23 "/data/test/notification.db"
24 } else {
25 "/data/service/el1/public/database/request/request.db"
26 };
27
28 const MILLIS_IN_A_WEEK: u64 = 7 * 24 * 60 * 60 * 1000;
29
30 pub(crate) static REQUEST_DB: LazyLock<RdbStore<'static>> = LazyLock::new(|| {
31 let mut config = OpenConfig::new(DB_PATH);
32 config.security_level(SecurityLevel::S1);
33 if cfg!(test) {
34 config.encrypt_status(false);
35 config.bundle_name("Test");
36 } else {
37 config.encrypt_status(true);
38 }
39 RdbStore::open(config).unwrap()
40 });
41
clear_database()42 pub(crate) fn clear_database() {
43 // rdb not support RETURNING expr.
44 let current_time = match SystemTime::now().duration_since(UNIX_EPOCH) {
45 Ok(duration) => duration,
46 Err(e) => {
47 error!("Failed to get current time: {}", e);
48 return;
49 }
50 }
51 .as_millis() as u64;
52
53 let task_ids = match REQUEST_DB.query::<u32>(
54 "SELECT task_id from request_task WHERE mtime < ?",
55 current_time - MILLIS_IN_A_WEEK,
56 ) {
57 Ok(rows) => rows,
58 Err(e) => {
59 error!("Failed to clear database: {}", e);
60 return;
61 }
62 };
63
64 for task_id in task_ids {
65 info!(
66 "clear {} info for have been overdue for more than a week.",
67 task_id
68 );
69 if let Err(e) = REQUEST_DB.execute("DELETE from request_task WHERE task_id = ?", task_id) {
70 error!("Failed to clear task {} info: {}", task_id, e);
71 }
72 NotificationDispatcher::get_instance().clear_task_info(task_id);
73 }
74 NotificationDispatcher::get_instance().clear_group_info();
75 }
76
77 #[test]
clear_database_test()78 fn clear_database_test() {
79 use request_utils::fastrand::fast_random;
80
81 let current_time = SystemTime::now()
82 .duration_since(UNIX_EPOCH)
83 .unwrap()
84 .as_millis() as u64;
85 let a_week_ago = current_time - MILLIS_IN_A_WEEK;
86
87 REQUEST_DB
88 .execute(
89 "CREATE TABLE IF NOT EXISTS request_task (task_id INTEGER PRIMARY KEY, mtime INTEGER)",
90 (),
91 )
92 .unwrap();
93 let mut task_ids = [
94 fast_random() as u32,
95 fast_random() as u32,
96 fast_random() as u32,
97 ];
98
99 task_ids.sort();
100 let sql = "INSERT INTO request_task (task_id, mtime) VALUES (?, ?)";
101 for task_id in task_ids.iter().take(2) {
102 REQUEST_DB.execute(sql, (*task_id, a_week_ago)).unwrap();
103 }
104 REQUEST_DB
105 .execute(sql, (task_ids[2], a_week_ago + 20000))
106 .unwrap();
107 let query: Vec<_> = REQUEST_DB
108 .query::<u32>("SELECT task_id from request_task", ())
109 .unwrap()
110 .collect();
111 for task_id in task_ids.iter() {
112 assert!(query.contains(task_id));
113 }
114
115 clear_database();
116 let query: Vec<_> = REQUEST_DB
117 .query::<u32>("SELECT task_id from request_task", ())
118 .unwrap()
119 .collect();
120 for task_id in task_ids.iter().take(2) {
121 assert!(!query.contains(task_id));
122 }
123 assert!(query.contains(&task_ids[2]));
124 }
125