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