1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 use asset_common::{CallingInfo, Counter, OwnerType};
17 use asset_db_operator::{
18     database::{get_path, Database},
19     database_file_upgrade::construct_splited_db_name,
20     types::column,
21 };
22 use asset_definition::{log_throw_error, ErrCode, Extension, Result};
23 use asset_file_operator::de_operator::create_user_de_dir;
24 use asset_log::{loge, logi};
25 use asset_sdk::{
26     plugin_interface::{ExtDbMap, IAssetPlugin, IAssetPluginCtx},
27     Value,
28 };
29 use std::{
30     cell::RefCell,
31     sync::{Arc, Mutex},
32 };
33 
34 /// The asset_ext plugin.
35 #[derive(Default)]
36 pub struct AssetPlugin {
37     lib: RefCell<Option<libloading::Library>>,
38 }
39 
40 static ASSET_OLUGIN_LOCK: Mutex<()> = Mutex::new(());
41 
42 unsafe impl Sync for AssetPlugin {}
43 
44 impl AssetPlugin {
new() -> Self45     fn new() -> Self {
46         Self { lib: RefCell::new(None) }
47     }
48 
49     /// Get the instance of AssetPlugin.
get_instance() -> Arc<AssetPlugin>50     pub fn get_instance() -> Arc<AssetPlugin> {
51         static mut INSTANCE: Option<Arc<AssetPlugin>> = None;
52         let _guard = ASSET_OLUGIN_LOCK.lock().unwrap();
53         unsafe { INSTANCE.get_or_insert_with(|| Arc::new(AssetPlugin::new())).clone() }
54     }
55 
56     /// Load the plugin.
load_plugin(&self) -> Result<Box<dyn IAssetPlugin>>57     pub fn load_plugin(&self) -> Result<Box<dyn IAssetPlugin>> {
58         unsafe {
59             let _guard = ASSET_OLUGIN_LOCK.lock().unwrap();
60             if self.lib.borrow().is_none() {
61                 logi!("start to load asset_ext plugin.");
62                 match libloading::Library::new("libasset_ext_ffi.z.so") {
63                     Ok(lib) => *self.lib.borrow_mut() = Some(lib),
64                     Err(err) => {
65                         loge!("dlopen libasset_ext_ffi.z.so failed, err: {}", err);
66                         return log_throw_error!(ErrCode::InvalidArgument, "dlopen failed {}", err);
67                     },
68                 };
69             }
70 
71             let Some(ref lib) = *self.lib.borrow() else {
72                 return log_throw_error!(ErrCode::InvalidArgument, "unexpect error");
73             };
74 
75             let func = match lib
76                 .get::<libloading::Symbol<unsafe extern "C" fn() -> *mut dyn IAssetPlugin>>(b"_create_plugin")
77             {
78                 Ok(func) => func,
79                 Err(err) => {
80                     loge!("dlsym _create_plugin failed, err: {}", err);
81                     return log_throw_error!(ErrCode::InvalidArgument, "dlsym failed {}", err);
82                 },
83             };
84 
85             let plugin_ptr = func();
86             if plugin_ptr.is_null() {
87                 loge!("_create_plugin return null.");
88                 return log_throw_error!(ErrCode::InvalidArgument, "_create_plugin return null.");
89             }
90 
91             logi!("load asset_ext plugin success.");
92             Ok(Box::from_raw(plugin_ptr))
93         }
94     }
95 
96     /// Unload plugin.
unload_plugin(&self)97     pub fn unload_plugin(&self) {
98         let _guard = ASSET_OLUGIN_LOCK.lock().unwrap();
99         if self.lib.borrow().is_some() {
100             *self.lib.borrow_mut() = None;
101         }
102     }
103 }
104 
105 /// The asset_ext plugin context.
106 #[repr(C)]
107 pub struct AssetContext {
108     /// The asset databse's user id.
109     pub user_id: i32,
110     /// The asset databse's user id.
111     pub calling_info: CallingInfo,
112 }
113 
get_db_name(attributes: &ExtDbMap, is_ce: bool) -> std::result::Result<String, u32>114 fn get_db_name(attributes: &ExtDbMap, is_ce: bool) -> std::result::Result<String, u32> {
115     let owner = attributes.get_bytes_attr(&column::OWNER).map_err(|e| e.code as u32)?;
116     let owner_type = attributes.get_enum_attr::<OwnerType>(&column::OWNER_TYPE).map_err(|e| e.code as u32)?;
117     // use owner and owner type calculate db file name
118     construct_splited_db_name(owner_type, owner, is_ce).map_err(|e| e.code as u32)
119 }
120 
121 #[allow(dead_code)]
122 impl IAssetPluginCtx for AssetContext {
123     /// Initializes the plugin before usage.
init(&mut self, user_id: i32) -> std::result::Result<(), u32>124     fn init(&mut self, user_id: i32) -> std::result::Result<(), u32> {
125         create_user_de_dir(user_id).map_err(|e| e.code as u32)?;
126         self.user_id = user_id;
127         Ok(())
128     }
129 
130     /// Adds an asset to de db.
add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>131     fn add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
132         let db_name = get_db_name(attributes, false)?;
133         let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
134         db.insert_datas(attributes).map_err(|e| e.code as u32)
135     }
136 
137     /// Adds an asset to ce db.
ce_add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>138     fn ce_add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
139         let db_name = get_db_name(attributes, true)?;
140         let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
141         db.insert_datas(attributes).map_err(|e| e.code as u32)
142     }
143 
144     /// Adds an asset with replace to de db.
replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>145     fn replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
146         let db_name = get_db_name(attributes, false)?;
147         let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
148         db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
149     }
150 
151     /// Adds an asset with replace to ce db.
ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>152     fn ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
153         let db_name = get_db_name(attributes, true)?;
154         let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
155         db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
156     }
157 
158     /// Queries de db.
query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32>159     fn query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
160         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
161         let mut query_data = vec![];
162         for db_name in de_dbs {
163             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
164             query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
165         }
166         Ok(query_data)
167     }
168 
169     /// Queries ce db.
ce_query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32>170     fn ce_query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
171         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
172         let mut query_data = vec![];
173         for db_name in ce_dbs {
174             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
175             query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
176         }
177         Ok(query_data)
178     }
179 
180     /// Removes an asset from de db.
remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>181     fn remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
182         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
183         let mut total_remove_count = 0;
184         for db_name in de_dbs {
185             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
186             total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
187         }
188         Ok(total_remove_count)
189     }
190 
191     /// Removes an asset from ce db.
ce_remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>192     fn ce_remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
193         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
194         let mut total_remove_count = 0;
195         for db_name in ce_dbs {
196             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
197             total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
198         }
199         Ok(total_remove_count)
200     }
201 
202     /// Removes assets from de db with sepcific condition.
remove_with_specific_cond( &mut self, specific_cond: &str, condition_value: &[Value], ) -> std::result::Result<i32, u32>203     fn remove_with_specific_cond(
204         &mut self,
205         specific_cond: &str,
206         condition_value: &[Value],
207     ) -> std::result::Result<i32, u32> {
208         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
209         let mut total_remove_count = 0;
210         for db_name in de_dbs {
211             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
212             total_remove_count +=
213                 db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
214         }
215         Ok(total_remove_count)
216     }
217 
218     /// Removes assets from ce db with sepcific condition.
ce_remove_with_specific_cond( &mut self, specific_cond: &str, condition_value: &[Value], ) -> std::result::Result<i32, u32>219     fn ce_remove_with_specific_cond(
220         &mut self,
221         specific_cond: &str,
222         condition_value: &[Value],
223     ) -> std::result::Result<i32, u32> {
224         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
225         let mut total_remove_count = 0;
226         for db_name in ce_dbs {
227             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
228             total_remove_count +=
229                 db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
230         }
231         Ok(total_remove_count)
232     }
233 
234     /// Updates the attributes of an asset in de db.
update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32>235     fn update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
236         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
237         let mut total_update_count = 0;
238         for db_name in de_dbs {
239             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
240             total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
241         }
242         Ok(total_update_count)
243     }
244 
245     /// Updates the attributes of an asset in ce db.
ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32>246     fn ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
247         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
248         let mut total_update_count = 0;
249         for db_name in ce_dbs {
250             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
251             total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
252         }
253         Ok(total_update_count)
254     }
255 
256     /// Returns the storage path for de db.
get_storage_path(&self) -> String257     fn get_storage_path(&self) -> String {
258         get_path()
259     }
260 
261     /// Increase count
increase_count(&mut self)262     fn increase_count(&mut self) {
263         let counter = Counter::get_instance();
264         counter.lock().unwrap().increase_count();
265     }
266 
267     /// Decrease count
decrease_count(&mut self)268     fn decrease_count(&mut self) {
269         let counter = Counter::get_instance();
270         counter.lock().unwrap().decrease_count();
271     }
272 }
273