/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use asset_common::{CallingInfo, Counter, OwnerType}; use asset_db_operator::{ database::{get_path, Database}, database_file_upgrade::construct_splited_db_name, types::column, }; use asset_definition::{log_throw_error, ErrCode, Extension, Result}; use asset_file_operator::de_operator::create_user_de_dir; use asset_log::{loge, logi}; use asset_sdk::{ plugin_interface::{ExtDbMap, IAssetPlugin, IAssetPluginCtx}, Value, }; use std::{ cell::RefCell, sync::{Arc, Mutex}, }; /// The asset_ext plugin. #[derive(Default)] pub struct AssetPlugin { lib: RefCell>, } static ASSET_OLUGIN_LOCK: Mutex<()> = Mutex::new(()); unsafe impl Sync for AssetPlugin {} impl AssetPlugin { fn new() -> Self { Self { lib: RefCell::new(None) } } /// Get the instance of AssetPlugin. pub fn get_instance() -> Arc { static mut INSTANCE: Option> = None; let _guard = ASSET_OLUGIN_LOCK.lock().unwrap(); unsafe { INSTANCE.get_or_insert_with(|| Arc::new(AssetPlugin::new())).clone() } } /// Load the plugin. pub fn load_plugin(&self) -> Result> { unsafe { let _guard = ASSET_OLUGIN_LOCK.lock().unwrap(); if self.lib.borrow().is_none() { logi!("start to load asset_ext plugin."); match libloading::Library::new("libasset_ext_ffi.z.so") { Ok(lib) => *self.lib.borrow_mut() = Some(lib), Err(err) => { loge!("dlopen libasset_ext_ffi.z.so failed, err: {}", err); return log_throw_error!(ErrCode::InvalidArgument, "dlopen failed {}", err); }, }; } let Some(ref lib) = *self.lib.borrow() else { return log_throw_error!(ErrCode::InvalidArgument, "unexpect error"); }; let func = match lib .get:: *mut dyn IAssetPlugin>>(b"_create_plugin") { Ok(func) => func, Err(err) => { loge!("dlsym _create_plugin failed, err: {}", err); return log_throw_error!(ErrCode::InvalidArgument, "dlsym failed {}", err); }, }; let plugin_ptr = func(); if plugin_ptr.is_null() { loge!("_create_plugin return null."); return log_throw_error!(ErrCode::InvalidArgument, "_create_plugin return null."); } logi!("load asset_ext plugin success."); Ok(Box::from_raw(plugin_ptr)) } } /// Unload plugin. pub fn unload_plugin(&self) { let _guard = ASSET_OLUGIN_LOCK.lock().unwrap(); if self.lib.borrow().is_some() { *self.lib.borrow_mut() = None; } } } /// The asset_ext plugin context. #[repr(C)] pub struct AssetContext { /// The asset databse's user id. pub user_id: i32, /// The asset databse's user id. pub calling_info: CallingInfo, } fn get_db_name(attributes: &ExtDbMap, is_ce: bool) -> std::result::Result { let owner = attributes.get_bytes_attr(&column::OWNER).map_err(|e| e.code as u32)?; let owner_type = attributes.get_enum_attr::(&column::OWNER_TYPE).map_err(|e| e.code as u32)?; // use owner and owner type calculate db file name construct_splited_db_name(owner_type, owner, is_ce).map_err(|e| e.code as u32) } #[allow(dead_code)] impl IAssetPluginCtx for AssetContext { /// Initializes the plugin before usage. fn init(&mut self, user_id: i32) -> std::result::Result<(), u32> { create_user_de_dir(user_id).map_err(|e| e.code as u32)?; self.user_id = user_id; Ok(()) } /// Adds an asset to de db. fn add(&mut self, attributes: &ExtDbMap) -> std::result::Result { let db_name = get_db_name(attributes, false)?; let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?; db.insert_datas(attributes).map_err(|e| e.code as u32) } /// Adds an asset to ce db. fn ce_add(&mut self, attributes: &ExtDbMap) -> std::result::Result { let db_name = get_db_name(attributes, true)?; let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?; db.insert_datas(attributes).map_err(|e| e.code as u32) } /// Adds an asset with replace to de db. fn replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> { let db_name = get_db_name(attributes, false)?; let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?; db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32) } /// Adds an asset with replace to ce db. fn ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> { let db_name = get_db_name(attributes, true)?; let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?; db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32) } /// Queries de db. fn query(&mut self, attributes: &ExtDbMap) -> std::result::Result, u32> { let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut query_data = vec![]; for db_name in de_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?; query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?); } Ok(query_data) } /// Queries ce db. fn ce_query(&mut self, attributes: &ExtDbMap) -> std::result::Result, u32> { let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut query_data = vec![]; for db_name in ce_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?; query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?); } Ok(query_data) } /// Removes an asset from de db. fn remove(&mut self, attributes: &ExtDbMap) -> std::result::Result { let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut total_remove_count = 0; for db_name in de_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?; total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?; } Ok(total_remove_count) } /// Removes an asset from ce db. fn ce_remove(&mut self, attributes: &ExtDbMap) -> std::result::Result { let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut total_remove_count = 0; for db_name in ce_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?; total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?; } Ok(total_remove_count) } /// Removes assets from de db with sepcific condition. fn remove_with_specific_cond( &mut self, specific_cond: &str, condition_value: &[Value], ) -> std::result::Result { let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut total_remove_count = 0; for db_name in de_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?; total_remove_count += db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?; } Ok(total_remove_count) } /// Removes assets from ce db with sepcific condition. fn ce_remove_with_specific_cond( &mut self, specific_cond: &str, condition_value: &[Value], ) -> std::result::Result { let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut total_remove_count = 0; for db_name in ce_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?; total_remove_count += db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?; } Ok(total_remove_count) } /// Updates the attributes of an asset in de db. fn update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result { let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut total_update_count = 0; for db_name in de_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?; total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?; } Ok(total_update_count) } /// Updates the attributes of an asset in ce db. fn ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result { let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?; let mut total_update_count = 0; for db_name in ce_dbs { let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?; total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?; } Ok(total_update_count) } /// Returns the storage path for de db. fn get_storage_path(&self) -> String { get_path() } /// Increase count fn increase_count(&mut self) { let counter = Counter::get_instance(); counter.lock().unwrap().increase_count(); } /// Decrease count fn decrease_count(&mut self) { let counter = Counter::get_instance(); counter.lock().unwrap().decrease_count(); } }