mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-06 17:59:11 +00:00
[OHOS.with ai] 将配置管理/配置分享/路由聚合/实例状态解析下沉至 Rust 内核,收敛职责并提升性能 (#2209)
* feat: add ohrs config store and startup error logging * feat: full ability core for ohos * feat: full ability core for ohos * feat: clean code --------- Co-authored-by: FrankHan <frankhan@FrankHans-Mac-mini.local>
This commit is contained in:
+544
-132
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,10 @@ edition = "2024"
|
|||||||
crate-type=["cdylib"]
|
crate-type=["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-trait = "0.1"
|
||||||
|
base64 = "0.22"
|
||||||
|
flate2 = "1.1"
|
||||||
|
gethostname = "1.1"
|
||||||
ohos-hilog-binding = {version = "*", features = ["redirect"]}
|
ohos-hilog-binding = {version = "*", features = ["redirect"]}
|
||||||
easytier = { path = "../../easytier" }
|
easytier = { path = "../../easytier" }
|
||||||
napi-derive-ohos = "1.1"
|
napi-derive-ohos = "1.1"
|
||||||
@@ -26,10 +30,16 @@ napi-ohos = { version = "1.1", default-features = false, features = [
|
|||||||
"web_stream",
|
"web_stream",
|
||||||
] }
|
] }
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.21.3"
|
||||||
|
ipnet = "2.10"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0.125"
|
serde_json = "1.0.125"
|
||||||
|
prost-reflect = { version = "0.14.5", default-features = false, features = ["derive"] }
|
||||||
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
||||||
tracing-subscriber = "0.3.19"
|
tracing-subscriber = "0.3.19"
|
||||||
tracing-core = "0.1.33"
|
tracing-core = "0.1.33"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
|
tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] }
|
||||||
|
url = "2.5"
|
||||||
uuid = { version = "1.5.0", features = [
|
uuid = { version = "1.5.0", features = [
|
||||||
"v4",
|
"v4",
|
||||||
"fast-rng",
|
"fast-rng",
|
||||||
|
|||||||
@@ -0,0 +1,331 @@
|
|||||||
|
use crate::config::storage::config_meta::{
|
||||||
|
delete_config_meta, get_config_meta, init_config_meta_store, list_config_meta_entries,
|
||||||
|
open_db, upsert_config_meta_in_tx,
|
||||||
|
};
|
||||||
|
use crate::config::types::stored_config::{ExportTomlResult, StoredConfigRecord};
|
||||||
|
use super::{field_store, import_export, legacy_migration, validation};
|
||||||
|
use easytier::common::config::ConfigLoader;
|
||||||
|
use easytier::proto::api::manage::NetworkConfig;
|
||||||
|
use ohos_hilog_binding::{hilog_debug, hilog_error};
|
||||||
|
use rusqlite::params;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
static CONFIG_ROOT_DIR: Mutex<Option<PathBuf>> = Mutex::new(None);
|
||||||
|
pub(crate) const CONFIG_DIR_NAME: &str = "easytier-configs";
|
||||||
|
pub(crate) const KERNEL_SOCKET_FILE_NAME: &str = "easytier-kernel.sock";
|
||||||
|
|
||||||
|
pub(crate) fn config_root_dir() -> Option<PathBuf> {
|
||||||
|
CONFIG_ROOT_DIR
|
||||||
|
.lock()
|
||||||
|
.ok()
|
||||||
|
.and_then(|guard| guard.as_ref().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn kernel_socket_path() -> Option<PathBuf> {
|
||||||
|
config_root_dir().map(|root| root.join(KERNEL_SOCKET_FILE_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn legacy_config_file_path(config_id: &str) -> Option<PathBuf> {
|
||||||
|
legacy_migration::legacy_config_file_path(&config_root_dir(), CONFIG_DIR_NAME, config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_config_store(root_dir: String) -> bool {
|
||||||
|
let root = PathBuf::from(root_dir);
|
||||||
|
let configs_dir = root.join(CONFIG_DIR_NAME);
|
||||||
|
if let Err(e) = std::fs::create_dir_all(&configs_dir) {
|
||||||
|
hilog_error!("[Rust] failed to create config dir {}: {}", configs_dir.display(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match CONFIG_ROOT_DIR.lock() {
|
||||||
|
Ok(mut guard) => {
|
||||||
|
*guard = Some(root.clone());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
hilog_error!("[Rust] failed to lock config root dir: {}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !init_config_meta_store(root.to_string_lossy().into_owned()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hilog_debug!("[Rust] initialized config repo at {}", configs_dir.display());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_legacy_file_if_needed(config_id: &str) -> Option<()> {
|
||||||
|
legacy_migration::migrate_legacy_file_if_needed(&config_root_dir(), CONFIG_DIR_NAME, config_id, save_config_record)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_config_record(
|
||||||
|
config_id: String,
|
||||||
|
display_name: String,
|
||||||
|
config_json: String,
|
||||||
|
) -> Option<StoredConfigRecord> {
|
||||||
|
let config = match validation::validate_config_json(&config_json, config_id.clone()) {
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(e) => {
|
||||||
|
hilog_error!("[Rust] save_config_record failed {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let normalized_json = match serde_json::to_string(&config) {
|
||||||
|
Ok(raw) => raw,
|
||||||
|
Err(e) => {
|
||||||
|
hilog_error!("[Rust] failed to serialize normalized config {}: {}", config_id, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = match validation::config_to_top_level_map(&config) {
|
||||||
|
Some(fields) => fields,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let conn = open_db()?;
|
||||||
|
let tx = conn.unchecked_transaction().ok()?;
|
||||||
|
let existing_meta = get_config_meta(&config_id);
|
||||||
|
let favorite = existing_meta.as_ref().map(|meta| meta.favorite).unwrap_or(false);
|
||||||
|
let temporary = existing_meta
|
||||||
|
.as_ref()
|
||||||
|
.map(|meta| meta.temporary)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let meta = upsert_config_meta_in_tx(&tx, config_id.clone(), display_name, favorite, temporary)?;
|
||||||
|
|
||||||
|
field_store::replace_config_fields(&tx, &config_id, fields)?;
|
||||||
|
|
||||||
|
tx.commit().ok()?;
|
||||||
|
|
||||||
|
if let Some(legacy_path) = legacy_config_file_path(&config_id) {
|
||||||
|
if legacy_path.exists() {
|
||||||
|
let _ = std::fs::remove_file(legacy_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(StoredConfigRecord {
|
||||||
|
meta,
|
||||||
|
config_json: normalized_json,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config_json(config_id: &str) -> Option<String> {
|
||||||
|
migrate_legacy_file_if_needed(config_id)?;
|
||||||
|
let object = field_store::load_config_map_from_db(config_id)?;
|
||||||
|
serde_json::to_string(&Value::Object(object)).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_config_record(config_id: &str) -> Option<StoredConfigRecord> {
|
||||||
|
let config_json = load_config_json(config_id)?;
|
||||||
|
let meta = get_config_meta(config_id)?;
|
||||||
|
Some(StoredConfigRecord { meta, config_json })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_config_field_value(config_id: &str, field: &str) -> Option<String> {
|
||||||
|
migrate_legacy_file_if_needed(config_id)?;
|
||||||
|
let conn = open_db()?;
|
||||||
|
conn.query_row(
|
||||||
|
"SELECT field_json FROM stored_config_fields
|
||||||
|
WHERE config_id = ?1 AND field_name = ?2",
|
||||||
|
params![config_id, field],
|
||||||
|
|row| row.get::<_, String>(0),
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_config_field_value(config_id: &str, field: &str, json_value: &str) -> bool {
|
||||||
|
if field.contains('.') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let raw = match load_config_json(config_id) {
|
||||||
|
Some(raw) => raw,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
let mut value = match serde_json::from_str::<Value>(&raw) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
let new_field_value = match serde_json::from_str::<Value>(json_value) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
let object = match value.as_object_mut() {
|
||||||
|
Some(object) => object,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
object.insert(field.to_string(), new_field_value);
|
||||||
|
|
||||||
|
let normalized = match serde_json::to_string(&value) {
|
||||||
|
Ok(raw) => raw,
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let display_name = get_config_meta(config_id)
|
||||||
|
.map(|meta| meta.display_name)
|
||||||
|
.unwrap_or_else(|| config_id.to_string());
|
||||||
|
|
||||||
|
save_config_record(config_id.to_string(), display_name, normalized).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_display_name(config_id: &str) -> Option<String> {
|
||||||
|
get_config_meta(config_id).map(|meta| meta.display_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_default_config_json() -> Option<String> {
|
||||||
|
crate::build_default_network_config_json().ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_config_record(config_id: String, display_name: String) -> Option<StoredConfigRecord> {
|
||||||
|
let raw = get_default_config_json()?;
|
||||||
|
let mut config = serde_json::from_str::<NetworkConfig>(&raw).ok()?;
|
||||||
|
config.instance_id = Some(config_id.clone());
|
||||||
|
let normalized_json = serde_json::to_string(&config).ok()?;
|
||||||
|
save_config_record(config_id, display_name, normalized_json)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_kernel_with_config_id(config_id: &str) -> bool {
|
||||||
|
let raw = match load_config_json(config_id) {
|
||||||
|
Some(raw) => raw,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
crate::run_network_instance_from_json(&raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_config_meta_json() -> String {
|
||||||
|
serde_json::to_string(&list_config_meta_entries().configs).unwrap_or_else(|_| "[]".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_config_record(config_id: &str) -> bool {
|
||||||
|
if let Some(path) = legacy_config_file_path(config_id) {
|
||||||
|
if path.exists() {
|
||||||
|
let _ = std::fs::remove_file(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let conn = match open_db() {
|
||||||
|
Some(conn) => conn,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
if let Err(e) = conn.execute(
|
||||||
|
"DELETE FROM stored_config_fields WHERE config_id = ?1",
|
||||||
|
params![config_id],
|
||||||
|
) {
|
||||||
|
hilog_error!("[Rust] failed to delete config fields {}: {}", config_id, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_config_meta(config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_config_toml(config_id: &str) -> Option<ExportTomlResult> {
|
||||||
|
let record = get_config_record(config_id)?;
|
||||||
|
import_export::export_config_toml_from_record(&record)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn import_toml_config(toml_text: String, display_name: Option<String>) -> Option<StoredConfigRecord> {
|
||||||
|
import_export::import_toml_to_record(toml_text, display_name, save_config_record)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rusqlite::params;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
fn test_root() -> String {
|
||||||
|
let unique = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos();
|
||||||
|
let dir = std::env::temp_dir().join(format!("easytier_ohrs_test_{}", unique));
|
||||||
|
dir.to_string_lossy().into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn save_get_export_delete_roundtrip() {
|
||||||
|
let root = test_root();
|
||||||
|
assert!(init_config_store(root.clone()));
|
||||||
|
|
||||||
|
let config_json = crate::build_default_network_config_json().expect("default config");
|
||||||
|
let saved = save_config_record(
|
||||||
|
"cfg-1".to_string(),
|
||||||
|
"test-config".to_string(),
|
||||||
|
config_json,
|
||||||
|
)
|
||||||
|
.expect("save config");
|
||||||
|
|
||||||
|
assert_eq!(saved.meta.config_id, "cfg-1");
|
||||||
|
assert_eq!(saved.meta.display_name, "test-config");
|
||||||
|
|
||||||
|
let loaded = get_config_record("cfg-1").expect("load config");
|
||||||
|
assert_eq!(loaded.meta.display_name, "test-config");
|
||||||
|
assert!(loaded.config_json.contains("cfg-1"));
|
||||||
|
|
||||||
|
let legacy_json_path = PathBuf::from(&root)
|
||||||
|
.join(CONFIG_DIR_NAME)
|
||||||
|
.join("cfg-1.json");
|
||||||
|
assert!(
|
||||||
|
!legacy_json_path.exists(),
|
||||||
|
"config should no longer be persisted as a per-config json file"
|
||||||
|
);
|
||||||
|
|
||||||
|
let conn = open_db().expect("db should be open");
|
||||||
|
let field_count: i64 = conn
|
||||||
|
.query_row(
|
||||||
|
"SELECT COUNT(*) FROM stored_config_fields WHERE config_id = ?1",
|
||||||
|
params!["cfg-1"],
|
||||||
|
|row| row.get(0),
|
||||||
|
)
|
||||||
|
.expect("count config fields");
|
||||||
|
assert!(field_count > 0, "config fields should be stored in sqlite");
|
||||||
|
|
||||||
|
let exported = export_config_toml("cfg-1").expect("export toml");
|
||||||
|
assert!(exported.toml_text.contains("instance_id"));
|
||||||
|
|
||||||
|
assert!(delete_config_record("cfg-1"));
|
||||||
|
assert!(get_config_record("cfg-1").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_config_field_updates_only_requested_top_level_field() {
|
||||||
|
let root = test_root();
|
||||||
|
assert!(init_config_store(root));
|
||||||
|
|
||||||
|
let config_json = crate::build_default_network_config_json().expect("default config");
|
||||||
|
save_config_record(
|
||||||
|
"cfg-field".to_string(),
|
||||||
|
"field-config".to_string(),
|
||||||
|
config_json,
|
||||||
|
)
|
||||||
|
.expect("save config");
|
||||||
|
|
||||||
|
let before_network_name = get_config_field_value("cfg-field", "network_name");
|
||||||
|
let before_instance_id = get_config_field_value("cfg-field", "instance_id")
|
||||||
|
.expect("instance id field should exist");
|
||||||
|
|
||||||
|
assert!(set_config_field_value(
|
||||||
|
"cfg-field",
|
||||||
|
"network_name",
|
||||||
|
"\"changed-network\""
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_config_field_value("cfg-field", "network_name"),
|
||||||
|
Some("\"changed-network\"".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_config_field_value("cfg-field", "instance_id"),
|
||||||
|
Some(before_instance_id)
|
||||||
|
);
|
||||||
|
assert_ne!(
|
||||||
|
get_config_field_value("cfg-field", "network_name"),
|
||||||
|
before_network_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,357 @@
|
|||||||
mod native_log;
|
mod config;
|
||||||
|
mod exports;
|
||||||
|
mod kernel_bridge;
|
||||||
|
mod platform;
|
||||||
|
mod runtime;
|
||||||
|
|
||||||
|
use config::services::schema_service::{
|
||||||
|
ConfigFieldMapping, NetworkConfigSchema,
|
||||||
|
get_network_config_field_mappings as build_network_config_field_mappings,
|
||||||
|
get_network_config_schema as build_network_config_schema,
|
||||||
|
};
|
||||||
|
use config::services::share_link_service::{
|
||||||
|
build_config_share_link as build_config_share_link_inner,
|
||||||
|
import_config_share_link as import_config_share_link_inner,
|
||||||
|
parse_config_share_link as parse_config_share_link_inner,
|
||||||
|
};
|
||||||
|
use config::storage::config_meta::get_config_display_name;
|
||||||
|
use config::types::stored_config::{KeyValuePair, SharedConfigLinkPayload};
|
||||||
|
use config::repository::{
|
||||||
|
create_config_record, delete_config_record, export_config_toml, get_config_field_value,
|
||||||
|
get_default_config_json, import_toml_config, init_config_store as init_repo_store,
|
||||||
|
list_config_meta_json, save_config_record, set_config_field_value, start_kernel_with_config_id,
|
||||||
|
};
|
||||||
|
use kernel_bridge::{
|
||||||
|
aggregate_requested_tun_routes,
|
||||||
|
start_local_socket_server as start_local_socket_server_inner,
|
||||||
|
stop_local_socket_server as stop_local_socket_server_inner,
|
||||||
|
};
|
||||||
|
use runtime::state::runtime_state::{
|
||||||
|
RuntimeAggregateState, TunAggregateState, clear_tun_attached, mark_tun_attached,
|
||||||
|
runtime_instance_from_running_info,
|
||||||
|
};
|
||||||
use easytier::common::config::{ConfigFileControl, ConfigLoader, TomlConfigLoader};
|
use easytier::common::config::{ConfigFileControl, ConfigLoader, TomlConfigLoader};
|
||||||
use easytier::common::constants::EASYTIER_VERSION;
|
use easytier::common::constants::EASYTIER_VERSION;
|
||||||
use easytier::instance_manager::NetworkInstanceManager;
|
use easytier::instance_manager::NetworkInstanceManager;
|
||||||
use easytier::proto::api::manage::NetworkConfig;
|
use easytier::proto::api::manage::NetworkConfig;
|
||||||
|
use easytier::proto::api::manage::NetworkingMethod;
|
||||||
|
use easytier::web_client::{WebClient, WebClientHooks, run_web_client};
|
||||||
use napi_derive_ohos::napi;
|
use napi_derive_ohos::napi;
|
||||||
use ohos_hilog_binding::{hilog_debug, hilog_error};
|
use ohos_hilog_binding::{hilog_error, hilog_info};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::format;
|
use std::format;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use tokio::runtime::{Builder, Runtime};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
static INSTANCE_MANAGER: once_cell::sync::Lazy<NetworkInstanceManager> =
|
pub(crate) static INSTANCE_MANAGER: once_cell::sync::Lazy<Arc<NetworkInstanceManager>> =
|
||||||
once_cell::sync::Lazy::new(NetworkInstanceManager::new);
|
once_cell::sync::Lazy::new(|| Arc::new(NetworkInstanceManager::new()));
|
||||||
|
static ASYNC_RUNTIME: once_cell::sync::Lazy<Runtime> = once_cell::sync::Lazy::new(|| {
|
||||||
|
Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("tokio runtime for easytier-ohrs")
|
||||||
|
});
|
||||||
|
static WEB_CLIENTS: once_cell::sync::Lazy<Mutex<HashMap<String, ManagedWebClient>>> =
|
||||||
|
once_cell::sync::Lazy::new(|| Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
#[napi(object)]
|
#[derive(Default)]
|
||||||
pub struct KeyValuePair {
|
struct TrackedWebClientHooks {
|
||||||
pub key: String,
|
instance_ids: Mutex<HashSet<Uuid>>,
|
||||||
pub value: String,
|
}
|
||||||
|
|
||||||
|
struct ManagedWebClient {
|
||||||
|
_client: WebClient,
|
||||||
|
hooks: Arc<TrackedWebClientHooks>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl WebClientHooks for TrackedWebClientHooks {
|
||||||
|
async fn post_run_network_instance(&self, id: &Uuid) -> Result<(), String> {
|
||||||
|
self.instance_ids
|
||||||
|
.lock()
|
||||||
|
.map_err(|err| err.to_string())?
|
||||||
|
.insert(*id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_remove_network_instances(&self, ids: &[Uuid]) -> Result<(), String> {
|
||||||
|
let mut guard = self.instance_ids.lock().map_err(|err| err.to_string())?;
|
||||||
|
for id in ids {
|
||||||
|
guard.remove(id);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_config_server_config(config: &NetworkConfig) -> bool {
|
||||||
|
matches!(
|
||||||
|
NetworkingMethod::try_from(config.networking_method.unwrap_or_default()).unwrap_or_default(),
|
||||||
|
NetworkingMethod::PublicServer
|
||||||
|
) && config
|
||||||
|
.public_server_url
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|url| !url.trim().is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_web_client(config_id: &str) -> bool {
|
||||||
|
let managed = match WEB_CLIENTS.lock() {
|
||||||
|
Ok(mut guard) => guard.remove(config_id),
|
||||||
|
Err(err) => {
|
||||||
|
hilog_error!("[Rust] stop_web_client lock failed {}", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(managed) = managed else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let tracked_ids = managed
|
||||||
|
.hooks
|
||||||
|
.instance_ids
|
||||||
|
.lock()
|
||||||
|
.map(|guard| guard.iter().copied().collect::<Vec<_>>())
|
||||||
|
.unwrap_or_default();
|
||||||
|
drop(managed);
|
||||||
|
|
||||||
|
if tracked_ids.is_empty() {
|
||||||
|
maybe_stop_local_socket_server();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = INSTANCE_MANAGER
|
||||||
|
.delete_network_instance(tracked_ids)
|
||||||
|
.map(|_| true)
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
hilog_error!("[Rust] stop config server instances failed {}: {}", config_id, err);
|
||||||
|
false
|
||||||
|
});
|
||||||
|
maybe_stop_local_socket_server();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_local_socket_server_started() -> bool {
|
||||||
|
start_local_socket_server_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_stop_local_socket_server() {
|
||||||
|
let no_local_instances = INSTANCE_MANAGER.list_network_instance_ids().is_empty();
|
||||||
|
let no_web_clients = WEB_CLIENTS.lock().map(|guard| guard.is_empty()).unwrap_or(false);
|
||||||
|
if no_local_instances && no_web_clients {
|
||||||
|
let _ = stop_local_socket_server_inner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_config_server_instance(config_id: &str, config: &NetworkConfig) -> bool {
|
||||||
|
if INSTANCE_MANAGER.list_network_instance_ids().iter().next().is_some() {
|
||||||
|
hilog_error!("[Rust] there is a running instance!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(config_server_url) = config.public_server_url.clone() else {
|
||||||
|
hilog_error!("[Rust] public_server_url missing for config server mode");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let hooks = Arc::new(TrackedWebClientHooks::default());
|
||||||
|
let secure_mode = config.secure_mode.as_ref().map(|mode| mode.enabled).unwrap_or(false);
|
||||||
|
let hostname = config.hostname.clone();
|
||||||
|
|
||||||
|
if !ensure_local_socket_server_started() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = ASYNC_RUNTIME.block_on(run_web_client(
|
||||||
|
&config_server_url,
|
||||||
|
None,
|
||||||
|
hostname,
|
||||||
|
secure_mode,
|
||||||
|
INSTANCE_MANAGER.clone(),
|
||||||
|
Some(hooks.clone()),
|
||||||
|
));
|
||||||
|
|
||||||
|
let client = match client {
|
||||||
|
Ok(client) => client,
|
||||||
|
Err(err) => {
|
||||||
|
hilog_error!("[Rust] start config server failed {}", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match WEB_CLIENTS.lock() {
|
||||||
|
Ok(mut guard) => {
|
||||||
|
guard.insert(
|
||||||
|
config_id.to_string(),
|
||||||
|
ManagedWebClient {
|
||||||
|
_client: client,
|
||||||
|
hooks,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
hilog_error!("[Rust] store config server client failed {}", err);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build_default_network_config_json() -> Result<String, String> {
|
||||||
|
let config = NetworkConfig::new_from_config(TomlConfigLoader::default())
|
||||||
|
.map_err(|e| format!("default_network_config failed {}", e))?;
|
||||||
|
serde_json::to_string(&config).map_err(|e| format!("default_network_config failed {}", e))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_toml_to_network_config_inner(toml_text: &str) -> Result<String, String> {
|
||||||
|
let config = NetworkConfig::new_from_config(TomlConfigLoader::new_from_str(toml_text).map_err(|e| e.to_string())?)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
serde_json::to_string(&config).map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_network_config_inner(cfg_json: &str) -> bool {
|
||||||
|
serde_json::from_str::<NetworkConfig>(cfg_json)
|
||||||
|
.ok()
|
||||||
|
.and_then(|cfg| cfg.gen_config().ok())
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn run_network_instance_from_json(cfg_json: &str) -> bool {
|
||||||
|
let config = match serde_json::from_str::<NetworkConfig>(cfg_json) {
|
||||||
|
Ok(cfg) => cfg,
|
||||||
|
Err(e) => {
|
||||||
|
hilog_error!("[Rust] parse config failed {}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_config_server_config(&config) {
|
||||||
|
let Some(config_id) = config.instance_id.as_deref() else {
|
||||||
|
hilog_error!("[Rust] config server config missing instance id");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
return run_config_server_instance(config_id, &config);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cfg = match config.gen_config() {
|
||||||
|
Ok(toml) => toml,
|
||||||
|
Err(e) => {
|
||||||
|
hilog_error!("[Rust] parse config failed {}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !INSTANCE_MANAGER.list_network_instance_ids().is_empty() {
|
||||||
|
hilog_error!("[Rust] there is a running instance!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ensure_local_socket_server_started() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inst_id = cfg.get_id();
|
||||||
|
if INSTANCE_MANAGER.list_network_instance_ids().contains(&inst_id) {
|
||||||
|
hilog_error!("[Rust] instance {} already exists", inst_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match INSTANCE_MANAGER.run_network_instance(cfg, false, ConfigFileControl::STATIC_CONFIG) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(err) => {
|
||||||
|
hilog_error!("[Rust] start_kernel failed for {}: {}", inst_id, err);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_instance_uuid(config_id: &str) -> Option<Uuid> {
|
||||||
|
match Uuid::parse_str(config_id) {
|
||||||
|
Ok(uuid) => Some(uuid),
|
||||||
|
Err(err) => {
|
||||||
|
hilog_error!("[Rust] invalid config_id {}: {}", config_id, err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn init_config_store(root_dir: String) -> bool {
|
||||||
|
exports::config_api::init_config_store(root_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn list_configs() -> String {
|
||||||
|
exports::config_api::list_configs()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn get_config_display_name_by_id(config_id: String) -> Option<String> {
|
||||||
|
get_config_display_name(&config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn save_config(config_id: String, display_name: String, config_json: String) -> bool {
|
||||||
|
exports::config_api::save_config(config_id, display_name, config_json)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn create_config(config_id: String, display_name: String) -> bool {
|
||||||
|
exports::config_api::create_config(config_id, display_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn rename_stored_config(config_id: String, display_name: String) -> bool {
|
||||||
|
config::storage::config_meta::set_config_display_name(config_id, display_name).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn delete_stored_config_meta(config_id: String) -> bool {
|
||||||
|
exports::config_api::delete_stored_config_meta(config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn get_config(config_id: String) -> Option<String> {
|
||||||
|
exports::config_api::get_config(config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn get_default_config() -> Option<String> {
|
||||||
|
exports::config_api::get_default_config()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn get_config_field(config_id: String, field: String) -> Option<String> {
|
||||||
|
exports::config_api::get_config_field(config_id, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn set_config_field(config_id: String, field: String, json_value: String) -> bool {
|
||||||
|
exports::config_api::set_config_field(config_id, field, json_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn import_toml(toml_text: String, display_name: Option<String>) -> Option<String> {
|
||||||
|
exports::config_api::import_toml(toml_text, display_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn export_toml(config_id: String) -> Option<String> {
|
||||||
|
exports::config_api::export_toml(config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn start_kernel(config_id: String) -> bool {
|
||||||
|
exports::runtime_api::start_kernel(config_id, start_kernel_with_config_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn stop_kernel(config_id: String) -> bool {
|
||||||
|
exports::runtime_api::stop_kernel(config_id, stop_web_client, parse_instance_uuid, maybe_stop_local_socket_server)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn stop_network_instance(config_ids: Vec<String>) -> bool {
|
||||||
|
exports::runtime_api::stop_network_instance(config_ids, stop_kernel)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
@@ -23,163 +359,95 @@ pub fn easytier_version() -> String {
|
|||||||
EASYTIER_VERSION.to_string()
|
EASYTIER_VERSION.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn set_tun_fd(inst_id: String, fd: i32) -> bool {
|
|
||||||
match Uuid::try_parse(&inst_id) {
|
|
||||||
Ok(uuid) => match INSTANCE_MANAGER.set_tun_fd(&uuid, fd) {
|
|
||||||
Ok(_) => {
|
|
||||||
hilog_debug!("[Rust] set tun fd {} to {}.", fd, inst_id);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] cant set tun fd {} to {}. {}", fd, inst_id, e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] cant covert {} to uuid. {}", inst_id, e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn default_network_config() -> String {
|
pub fn default_network_config() -> String {
|
||||||
match NetworkConfig::new_from_config(TomlConfigLoader::default()) {
|
get_default_config().unwrap_or_else(|| "{}".to_string())
|
||||||
Ok(result) => serde_json::to_string(&result).unwrap_or_else(|e| format!("ERROR {}", e)),
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] default_network_config failed {}", e);
|
|
||||||
format!("ERROR {}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn convert_toml_to_network_config(cfg_str: String) -> String {
|
pub fn convert_toml_to_network_config(toml_text: String) -> String {
|
||||||
match TomlConfigLoader::new_from_str(&cfg_str) {
|
convert_toml_to_network_config_inner(&toml_text)
|
||||||
Ok(cfg) => match NetworkConfig::new_from_config(cfg) {
|
.unwrap_or_else(|err| format!("ERROR: {err}"))
|
||||||
Ok(result) => serde_json::to_string(&result).unwrap_or_else(|e| format!("ERROR {}", e)),
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] convert_toml_to_network_config failed {}", e);
|
|
||||||
format!("ERROR {}", e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] convert_toml_to_network_config failed {}", e);
|
|
||||||
format!("ERROR {}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn parse_network_config(cfg_json: String) -> bool {
|
pub fn parse_network_config(cfg_json: String) -> bool {
|
||||||
match serde_json::from_str::<NetworkConfig>(&cfg_json) {
|
parse_network_config_inner(&cfg_json)
|
||||||
Ok(cfg) => match cfg.gen_config() {
|
|
||||||
Ok(toml) => {
|
|
||||||
hilog_debug!("[Rust] Convert to Toml {}", toml.dump());
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] parse config failed {}", e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] parse config failed {}", e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn run_network_instance(cfg_json: String) -> bool {
|
pub fn run_network_instance(cfg_json: String) -> bool {
|
||||||
let cfg = match serde_json::from_str::<NetworkConfig>(&cfg_json) {
|
run_network_instance_from_json(&cfg_json)
|
||||||
Ok(cfg) => match cfg.gen_config() {
|
|
||||||
Ok(toml) => toml,
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] parse config failed {}", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] parse config failed {}", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if INSTANCE_MANAGER.list_network_instance_ids().len() > 0 {
|
|
||||||
hilog_error!("[Rust] there is a running instance!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let inst_id = cfg.get_id();
|
|
||||||
if INSTANCE_MANAGER
|
|
||||||
.list_network_instance_ids()
|
|
||||||
.contains(&inst_id)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
INSTANCE_MANAGER
|
|
||||||
.run_network_instance(cfg, false, ConfigFileControl::STATIC_CONFIG)
|
|
||||||
.unwrap();
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn stop_network_instance(inst_names: Vec<String>) {
|
|
||||||
INSTANCE_MANAGER
|
|
||||||
.delete_network_instance(
|
|
||||||
inst_names
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|s| Uuid::parse_str(&s).ok())
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
hilog_debug!("[Rust] stop_network_instance");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn collect_network_infos() -> Vec<KeyValuePair> {
|
pub fn collect_network_infos() -> Vec<KeyValuePair> {
|
||||||
let mut result = Vec::new();
|
exports::runtime_api::collect_network_infos()
|
||||||
match INSTANCE_MANAGER.collect_network_infos_sync() {
|
|
||||||
Ok(map) => {
|
|
||||||
for (uuid, info) in map.iter() {
|
|
||||||
// convert value to json string
|
|
||||||
let value = match serde_json::to_string(&info) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] failed to serialize instance {} info: {}", uuid, e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
result.push(KeyValuePair {
|
|
||||||
key: uuid.clone().to_string(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn collect_running_network() -> Vec<String> {
|
pub fn set_tun_fd(config_id: String, fd: i32) -> bool {
|
||||||
INSTANCE_MANAGER
|
exports::runtime_api::set_tun_fd(config_id, fd, parse_instance_uuid)
|
||||||
.list_network_instance_ids()
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.map(|id| id.to_string())
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn is_running_network(inst_id: String) -> bool {
|
pub fn get_network_config_schema() -> NetworkConfigSchema {
|
||||||
match Uuid::try_parse(&inst_id) {
|
build_network_config_schema()
|
||||||
Ok(uuid) => INSTANCE_MANAGER.list_network_instance_ids().contains(&uuid),
|
}
|
||||||
Err(e) => {
|
|
||||||
hilog_error!("[Rust] cant covert {} to uuid. {}", inst_id, e);
|
#[napi]
|
||||||
false
|
pub fn get_network_config_field_mappings() -> Vec<ConfigFieldMapping> {
|
||||||
}
|
build_network_config_field_mappings()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exported_plain_object_schema_contains_core_networkconfig_metadata() {
|
||||||
|
let schema = get_network_config_schema();
|
||||||
|
assert_eq!(schema.name, "NetworkConfig");
|
||||||
|
assert_eq!(schema.node_kind, "schema");
|
||||||
|
assert!(schema
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.any(|field| field.name == "network_name"));
|
||||||
|
let secure_mode = schema
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.find(|field| field.name == "secure_mode")
|
||||||
|
.expect("secure_mode field");
|
||||||
|
assert!(secure_mode
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.any(|field| field.name == "enabled"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn get_runtime_snapshot() -> RuntimeAggregateState {
|
||||||
|
exports::runtime_api::get_runtime_snapshot()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_runtime_snapshot_inner() -> RuntimeAggregateState {
|
||||||
|
exports::runtime_api::get_runtime_snapshot_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn build_config_share_link(config_id: String, only_start: Option<bool>) -> Option<String> {
|
||||||
|
build_config_share_link_inner(&config_id, None, only_start.unwrap_or(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn parse_config_share_link(share_link: String) -> Option<SharedConfigLinkPayload> {
|
||||||
|
parse_config_share_link_inner(&share_link)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn import_config_share_link(
|
||||||
|
share_link: String,
|
||||||
|
display_name_override: Option<String>,
|
||||||
|
) -> Option<String> {
|
||||||
|
import_config_share_link_inner(&share_link, display_name_override)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
use napi_derive_ohos::napi;
|
|
||||||
use ohos_hilog_binding::{
|
|
||||||
LogOptions, hilog_debug, hilog_error, hilog_info, hilog_warn, set_global_options,
|
|
||||||
};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::panic;
|
|
||||||
use tracing::{Event, Subscriber};
|
|
||||||
use tracing_core::Level;
|
|
||||||
use tracing_subscriber::layer::{Context, Layer};
|
|
||||||
use tracing_subscriber::prelude::*;
|
|
||||||
|
|
||||||
static INITIALIZED: std::sync::Once = std::sync::Once::new();
|
|
||||||
fn panic_hook(info: &panic::PanicHookInfo) {
|
|
||||||
hilog_error!("RUST PANIC: {}", info);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn init_panic_hook() {
|
|
||||||
INITIALIZED.call_once(|| {
|
|
||||||
panic::set_hook(Box::new(panic_hook));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn hilog_global_options(domain: u32, tag: String) {
|
|
||||||
ohos_hilog_binding::forward_stdio_to_hilog();
|
|
||||||
set_global_options(LogOptions {
|
|
||||||
domain,
|
|
||||||
tag: Box::leak(tag.clone().into_boxed_str()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub fn init_tracing_subscriber() {
|
|
||||||
tracing_subscriber::registry()
|
|
||||||
.with(CallbackLayer {
|
|
||||||
callback: Box::new(tracing_callback),
|
|
||||||
})
|
|
||||||
.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tracing_callback(event: &Event, fields: HashMap<String, String>) {
|
|
||||||
let metadata = event.metadata();
|
|
||||||
#[cfg(target_env = "ohos")]
|
|
||||||
{
|
|
||||||
let loc = metadata.target().split("::").last().unwrap();
|
|
||||||
match *metadata.level() {
|
|
||||||
Level::TRACE => {
|
|
||||||
hilog_debug!("[{}] {:?}", loc, fields.values().collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
Level::DEBUG => {
|
|
||||||
hilog_debug!("[{}] {:?}", loc, fields.values().collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
Level::INFO => {
|
|
||||||
hilog_info!("[{}] {:?}", loc, fields.values().collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
Level::WARN => {
|
|
||||||
hilog_warn!("[{}] {:?}", loc, fields.values().collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
Level::ERROR => {
|
|
||||||
hilog_error!("[{}] {:?}", loc, fields.values().collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CallbackLayer {
|
|
||||||
callback: Box<dyn Fn(&Event, HashMap<String, String>) + Send + Sync>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Subscriber> Layer<S> for CallbackLayer {
|
|
||||||
fn on_event(&self, event: &Event, _ctx: Context<S>) {
|
|
||||||
// 使用 fmt::format::FmtSpan 提取字段值
|
|
||||||
let mut fields = HashMap::new();
|
|
||||||
let mut visitor = FieldCollector(&mut fields);
|
|
||||||
event.record(&mut visitor);
|
|
||||||
(self.callback)(event, fields);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FieldCollector<'a>(&'a mut HashMap<String, String>);
|
|
||||||
|
|
||||||
impl<'a> tracing::field::Visit for FieldCollector<'a> {
|
|
||||||
fn record_i64(&mut self, field: &tracing::field::Field, value: i64) {
|
|
||||||
self.0.insert(field.name().to_string(), value.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
|
|
||||||
self.0.insert(field.name().to_string(), value.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
|
|
||||||
self.0
|
|
||||||
.insert(field.name().to_string(), format!("{:?}", value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,5 +14,8 @@ pub mod web;
|
|||||||
pub mod tests;
|
pub mod tests;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
const DESCRIPTOR_POOL_BYTES: &[u8] =
|
pub const DESCRIPTOR_POOL_BYTES: &[u8] =
|
||||||
include_bytes!(concat!(env!("OUT_DIR"), "/file_descriptor_set.bin"));
|
include_bytes!(concat!(env!("OUT_DIR"), "/file_descriptor_set.bin"));
|
||||||
|
|
||||||
|
pub const ALL_DESCRIPTOR_BYTES: &[u8] =
|
||||||
|
include_bytes!(concat!(env!("OUT_DIR"), "/descriptors.bin"));
|
||||||
|
|||||||
Reference in New Issue
Block a user