* Copyright (C) 2023 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 std::ffi::{CString, c_char, c_int, c_uint, c_longlong, c_ulonglong, c_void};
use crate::{EventType, WatchRule, QueryArg, QueryRule};
const MAX_LENGTH_OF_EVENT_DOMAIN: usize = 17;
const MAX_LENGTH_OF_EVENT_NAME: usize = 33;
const MAX_LENGTH_OF_EVENT_TAG: usize = 85;
const MAX_LENGTH_OF_TIME_ZONE: usize = 6;
const MAX_NUMBER_OF_EVENT_LIST: usize = 10;
const MAX_EVENT_LIST_LEN: usize = 339;
#[repr(C)]
#[derive(Copy, Clone)]
struct HiSysEventWatchRule {
pub domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN],
pub name: [u8; MAX_LENGTH_OF_EVENT_NAME],
pub tag: [u8; MAX_LENGTH_OF_EVENT_TAG],
pub rule_type: c_int,
pub event_type: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
struct HiSysEventQueryArg {
pub begin_time: c_longlong,
pub end_time: c_longlong,
pub max_events: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
struct HiSysEventQueryRuleWrapper {
pub domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN],
pub event_list: [u8; MAX_EVENT_LIST_LEN],
pub event_list_size: c_uint,
pub condition: *const c_char,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct HiSysEventRecord {
domain: [u8; MAX_LENGTH_OF_EVENT_DOMAIN],
event_name: [u8; MAX_LENGTH_OF_EVENT_NAME],
event_type: c_int,
time: c_ulonglong,
tz: [u8; MAX_LENGTH_OF_TIME_ZONE],
pid: c_longlong,
tid: c_longlong,
uid: c_longlong,
trace_id: c_ulonglong,
spand_id: c_ulonglong,
pspan_id: c_ulonglong,
trace_flag: c_int,
level: *const c_char,
tag: *const c_char,
json_str: *const c_char,
}
impl HiSysEventRecord {
pub fn get_domain(&self) -> String {
std::str::from_utf8(&self.domain).expect("need valid domain array")
.trim_end_matches(char::from(0)).to_string()
}
pub fn get_event_name(&self) -> String {
std::str::from_utf8(&self.event_name).expect("need valid event name array")
.trim_end_matches(char::from(0)).to_string()
}
pub fn get_event_type(&self) -> EventType {
match self.event_type {
1 => EventType::Fault,
2 => EventType::Statistic,
3 => EventType::Security,
4 => EventType::Behavior,
_ => EventType::Fault,
}
}
pub fn get_time(&self) -> u64 {
self.time
}
pub fn get_time_zone(&self) -> String {
std::str::from_utf8(&self.tz).expect("need valid time zone array")
.trim_end_matches(char::from(0)).to_string()
}
pub fn get_pid(&self) -> i64 {
self.pid
}
pub fn get_tid(&self) -> i64 {
self.tid
}
pub fn get_uid(&self) -> i64 {
self.uid
}
pub fn get_trace_id(&self) -> u64 {
self.trace_id
}
pub fn get_span_id(&self) -> u64 {
self.spand_id
}
pub fn get_parent_span_id(&self) -> u64 {
self.pspan_id
}
pub fn get_trace_flag(&self) -> i32 {
self.trace_flag
}
pub fn get_level(&self) -> String {
let level_arr = unsafe {
std::ffi::CString::from_raw(self.level as *mut std::ffi::c_char)
};
std::str::from_utf8(level_arr.to_bytes()).expect("need valid level pointer")
.trim_end_matches(char::from(0)).to_owned()
}
pub fn get_tag(&self) -> String {
let tag_arr = unsafe {
std::ffi::CString::from_raw(self.tag as *mut std::ffi::c_char)
};
let tag = std::str::from_utf8(tag_arr.to_bytes()).expect("need valid tag pointer")
.trim_end_matches(char::from(0));
String::from(tag)
}
pub fn get_json_str(&self) -> String {
let json_str_arr = unsafe {
std::ffi::CString::from_raw(self.json_str as *mut std::ffi::c_char)
};
let json_str = std::str::from_utf8(json_str_arr.to_bytes()).expect("need valid json str pointer")
.trim_end_matches(char::from(0));
String::from(json_str)
}
}
pub type OnQuery = unsafe extern "C" fn (
callback: *mut c_void,
records: *const HiSysEventRecord,
size: c_uint
);
pub type OnComplete = unsafe extern "C" fn (
callback: *mut c_void,
reason: c_int,
total: c_int
);
#[repr(C)]
struct HiSysEventRustQuerierC {
pub on_query_cb: *mut c_void,
pub on_query_wrapper_cb: OnQuery,
pub on_complete_cb: *mut c_void,
pub on_complete_wrapper_cb: OnComplete,
}
#[allow(dead_code)]
pub struct Querier {
native: *mut HiSysEventRustQuerierC,
on_query_callback: *mut c_void,
on_complete_callback: *mut c_void,
}
impl Querier {
pub fn new<F1, F2>(on_query_callback: F1, on_complete_callback: F2) -> Option<Self>
where
F1: Fn(&[HiSysEventRecord]) + Send + Sync + 'static,
F2: Fn(i32, i32) + Send + Sync + 'static,
{
let on_query_callback = Box::into_raw(Box::new(on_query_callback));
let on_complete_callback = Box::into_raw(Box::new(on_complete_callback));
let native = unsafe {
CreateRustEventQuerier(on_query_callback as *mut c_void, Self::on_query_callback::<F1>,
on_complete_callback as *mut c_void, Self::on_complete_callback::<F2>)
};
if native.is_null() {
None
} else {
Some(Self {
native,
on_query_callback: on_query_callback as *mut c_void,
on_complete_callback: on_complete_callback as *mut c_void,
})
}
}
unsafe extern "C" fn on_query_callback<F>(callback: *mut c_void, records: *const HiSysEventRecord,
size: c_uint)
where
F: Fn(&[HiSysEventRecord]) + Send + Sync + 'static,
{
let mut transalted_records: Vec<HiSysEventRecord> = vec![];
for i in 0..size {
let record_item = unsafe {
GetHiSysEventRecordByIndexWrapper(records, size, i as c_uint)
};
transalted_records.push(record_item);
}
let callback = (callback as *const F).as_ref().unwrap();
callback(transalted_records.as_slice());
}
unsafe extern "C" fn on_complete_callback<F>(callback: *mut c_void, reason: c_int,
total: c_int)
where
F: Fn(i32, i32) + Send + Sync + 'static,
{
let callback = (callback as *const F).as_ref().unwrap();
callback(reason, total);
}
pub fn try_to_recycle(&self) {
unsafe {
RecycleRustEventQuerier(self.as_raw())
}
}
}
unsafe impl AsRawPtr<HiSysEventRustQuerierC> for Querier {
fn as_raw(&self) -> *const HiSysEventRustQuerierC {
self.native
}
fn as_mut_raw(&mut self) -> *mut HiSysEventRustQuerierC {
self.native
}
}
pub(crate) fn query(query_arg: &QueryArg, query_rules: &[QueryRule], querier: &Querier) -> i32 {
let query_arg_wrapper = HiSysEventQueryArg {
begin_time: query_arg.begin_time as c_longlong,
end_time: query_arg.end_time as c_longlong,
max_events: query_arg.max_events as c_int,
};
let mut query_rules_wrapper: Vec<HiSysEventQueryRuleWrapper> = vec![];
for i in 0..query_rules.len() {
let condition_wrapper = CString::new(query_rules[i].condition).expect("Need a condition for query.");
query_rules_wrapper.push(HiSysEventQueryRuleWrapper {
domain: [0; MAX_LENGTH_OF_EVENT_DOMAIN],
event_list: [0; MAX_EVENT_LIST_LEN],
event_list_size: MAX_NUMBER_OF_EVENT_LIST as c_uint,
condition: condition_wrapper.as_ptr() as *const c_char,
});
crate::utils::trans_slice_to_array(query_rules[i].domain, &mut query_rules_wrapper[i].domain);
let src_len = query_rules[i].event_list.len();
let dest_len = query_rules_wrapper[i].event_list.len();
let total_cnt = if src_len <= dest_len {
src_len
} else {
dest_len
};
query_rules_wrapper[i].event_list_size = total_cnt as c_uint;
let src_str = query_rules[i].event_list.join("|");
let src_str = &src_str[..];
crate::utils::trans_slice_to_array(src_str, &mut query_rules_wrapper[i].event_list);
}
unsafe {
HiSysEventQueryWrapper(&query_arg_wrapper as *const HiSysEventQueryArg,
query_rules_wrapper.as_mut_ptr(),
query_rules.len() as c_uint,
querier.as_raw(),
)
}
}
pub type OnEvent = unsafe extern "C" fn (
callback: *mut c_void,
record: HiSysEventRecord
);
pub type OnServiceDied = unsafe extern "C" fn (
callback: *mut c_void,
);
#[repr(C)]
struct HiSysEventRustWatcherC {
pub on_event_cb: *mut c_void,
pub on_event_wrapper_cb: OnEvent,
pub on_service_died_cb: *mut c_void,
pub on_service_died_wrapper_cb: OnServiceDied,
}
#[allow(dead_code)]
pub struct Watcher {
native: *mut HiSysEventRustWatcherC,
on_event_callback: *mut c_void,
on_service_died_callback: *mut c_void,
}
impl Watcher {
pub fn new<F1, F2>(on_event_callback: F1, on_service_died_callback: F2) -> Option<Self>
where
F1: Fn(HiSysEventRecord) + Send + Sync + 'static,
F2: Fn() + Send + Sync + 'static,
{
let on_event_callback = Box::into_raw(Box::new(on_event_callback));
let on_service_died_callback = Box::into_raw(Box::new(on_service_died_callback));
let native = unsafe {
CreateRustEventWatcher(on_event_callback as *mut c_void, Self::on_event::<F1>,
on_service_died_callback as *mut c_void, Self::on_service_died::<F2>)
};
if native.is_null() {
None
} else {
Some(Self {
native,
on_event_callback: on_event_callback as *mut c_void,
on_service_died_callback: on_service_died_callback as *mut c_void,
})
}
}
unsafe extern "C" fn on_event<F>(callback: *mut c_void, record: HiSysEventRecord)
where
F: Fn(HiSysEventRecord) + Send + Sync + 'static,
{
let callback = (callback as *const F).as_ref().unwrap();
callback(record);
}
unsafe extern "C" fn on_service_died<F>(callback: *mut c_void)
where
F: Fn() + Send + Sync + 'static,
{
let callback = (callback as *const F).as_ref().unwrap();
callback();
}
pub fn try_to_recycle(&self) {
unsafe {
RecycleRustEventWatcher(self.as_raw())
}
}
}
unsafe impl AsRawPtr<HiSysEventRustWatcherC> for Watcher {
fn as_raw(&self) -> *const HiSysEventRustWatcherC {
self.native
}
fn as_mut_raw(&mut self) -> *mut HiSysEventRustWatcherC {
self.native
}
}
pub(crate) fn add_watcher(watcher: &Watcher, watch_rules: &[WatchRule]) -> i32 {
let mut watch_rules_wrapper: Vec<HiSysEventWatchRule> = vec![];
for i in 0..watch_rules.len() {
watch_rules_wrapper.push(HiSysEventWatchRule {
domain: [0; MAX_LENGTH_OF_EVENT_DOMAIN],
name: [0; MAX_LENGTH_OF_EVENT_NAME],
tag: [0; MAX_LENGTH_OF_EVENT_TAG],
rule_type: 0,
event_type: 0,
});
crate::utils::trans_slice_to_array(watch_rules[i].domain, &mut watch_rules_wrapper[i].domain);
crate::utils::trans_slice_to_array(watch_rules[i].name, &mut watch_rules_wrapper[i].name);
crate::utils::trans_slice_to_array(watch_rules[i].tag, &mut watch_rules_wrapper[i].tag);
watch_rules_wrapper[i].rule_type = watch_rules[i].rule_type as i32 as c_int;
watch_rules_wrapper[i].event_type = watch_rules[i].event_type as i32 as c_int;
}
unsafe {
HiSysEventAddWatcherWrapper(watcher.as_raw(),
watch_rules_wrapper.as_mut_ptr(),
watch_rules.len() as c_uint)
}
}
pub(crate) fn remove_watcher(watcher: &Watcher) -> i32 {
unsafe {
HiSysEventRemoveWatcherWrapper(watcher.as_raw())
}
}
unsafe trait AsRawPtr<T> {
fn as_raw(&self) -> *const T;
fn as_mut_raw(&mut self) -> *mut T;
}
extern "C" {
fn HiSysEventAddWatcherWrapper(watcher: *const HiSysEventRustWatcherC, rules: *const HiSysEventWatchRule,
rule_size: c_uint) -> c_int;
fn HiSysEventRemoveWatcherWrapper(watcher: *const HiSysEventRustWatcherC) -> c_int;
fn HiSysEventQueryWrapper(query_arg: *const HiSysEventQueryArg, rules: *const HiSysEventQueryRuleWrapper,
rule_size: c_uint, querier: *const HiSysEventRustQuerierC) -> c_int;
fn GetHiSysEventRecordByIndexWrapper(records: *const HiSysEventRecord, total: c_uint,
index: c_uint) -> HiSysEventRecord;
fn CreateRustEventWatcher(on_event_callback: *const c_void,
on_event_wrapper_callback: OnEvent,
on_service_died_callback: *const c_void,
on_service_died_wrapper_callback: OnServiceDied) -> *mut HiSysEventRustWatcherC;
fn RecycleRustEventWatcher(watcher: *const HiSysEventRustWatcherC);
fn CreateRustEventQuerier(on_query_callback: *const c_void,
on_query_wrapper_callback: OnQuery,
on_complete_callback: *const c_void,
on_complete_wrapper_callback: OnComplete) -> *mut HiSysEventRustQuerierC;
fn RecycleRustEventQuerier(querier: *const HiSysEventRustQuerierC);
}