use crate::resource::Resource;
use crate::{MaaError, MaaResult, common, sys};
use std::ptr::NonNull;
use std::collections::HashMap;
use std::ffi::c_void;
use std::sync::Mutex;
use std::sync::Arc;
struct TaskerInner {
handle: NonNull<sys::MaaTasker>,
owns_handle: bool,
callbacks: Mutex<HashMap<sys::MaaSinkId, usize>>, event_sinks: Mutex<HashMap<sys::MaaSinkId, usize>>,
resource: Mutex<Option<Resource>>,
controller: Mutex<Option<crate::controller::Controller>>,
}
unsafe impl Send for TaskerInner {}
unsafe impl Sync for TaskerInner {}
#[derive(Clone)]
pub struct Tasker {
inner: Arc<TaskerInner>,
}
unsafe impl Send for Tasker {}
unsafe impl Sync for Tasker {}
impl Tasker {
pub fn new() -> MaaResult<Self> {
let handle = unsafe { sys::MaaTaskerCreate() };
if let Some(ptr) = NonNull::new(handle) {
Ok(Self {
inner: Arc::new(TaskerInner {
handle: ptr,
owns_handle: true,
callbacks: Mutex::new(HashMap::new()),
event_sinks: Mutex::new(HashMap::new()),
resource: Mutex::new(None),
controller: Mutex::new(None),
}),
})
} else {
Err(MaaError::NullPointer)
}
}
pub unsafe fn from_raw(ptr: *mut sys::MaaTasker, owns: bool) -> MaaResult<Self> {
if let Some(handle) = NonNull::new(ptr) {
Ok(Self {
inner: Arc::new(TaskerInner {
handle,
owns_handle: owns,
callbacks: Mutex::new(HashMap::new()),
event_sinks: Mutex::new(HashMap::new()),
resource: Mutex::new(None),
controller: Mutex::new(None),
}),
})
} else {
Err(MaaError::NullPointer)
}
}
pub fn bind_resource(&self, res: &Resource) -> MaaResult<()> {
let ret = unsafe { sys::MaaTaskerBindResource(self.inner.handle.as_ptr(), res.raw()) };
common::check_bool(ret)?;
*self.inner.resource.lock().unwrap() = Some(res.clone());
Ok(())
}
pub fn bind_controller(&self, ctrl: &crate::controller::Controller) -> MaaResult<()> {
let ret = unsafe { sys::MaaTaskerBindController(self.inner.handle.as_ptr(), ctrl.raw()) };
common::check_bool(ret)?;
*self.inner.controller.lock().unwrap() = Some(ctrl.clone());
Ok(())
}
pub fn get_recognition_detail(
&self,
reco_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::RecognitionDetail>> {
Self::fetch_recognition_detail(self.inner.handle.as_ptr(), reco_id)
}
pub fn get_action_detail(
&self,
act_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::ActionDetail>> {
Self::fetch_action_detail(self.inner.handle.as_ptr(), act_id)
}
pub fn get_wait_freezes_detail(
&self,
wf_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::WaitFreezesDetail>> {
Self::fetch_wait_freezes_detail(self.inner.handle.as_ptr(), wf_id)
}
pub fn get_node_detail(
&self,
node_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::NodeDetail>> {
Self::fetch_node_detail(self.inner.handle.as_ptr(), node_id)
}
pub fn get_task_detail(
&self,
task_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::TaskDetail>> {
Self::fetch_task_detail(self.inner.handle.as_ptr(), task_id)
}
pub(crate) fn fetch_recognition_detail(
handle: *mut sys::MaaTasker,
reco_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::RecognitionDetail>> {
let node_name = crate::buffer::MaaStringBuffer::new()?;
let algorithm = crate::buffer::MaaStringBuffer::new()?;
let mut hit = 0;
let mut box_rect = sys::MaaRect {
x: 0,
y: 0,
width: 0,
height: 0,
};
let detail = crate::buffer::MaaStringBuffer::new()?;
let raw = crate::buffer::MaaImageBuffer::new()?;
let draws = crate::buffer::MaaImageListBuffer::new()?;
let ret = unsafe {
sys::MaaTaskerGetRecognitionDetail(
handle,
reco_id,
node_name.raw(),
algorithm.raw(),
&mut hit,
&mut box_rect,
detail.raw(),
raw.raw(),
draws.raw(),
)
};
if ret == 0 {
return Ok(None);
}
let algorithm_str = algorithm.as_str().to_string();
let algorithm_enum = crate::common::AlgorithmEnum::from(algorithm_str);
let detail_val: serde_json::Value =
serde_json::from_str(detail.as_str()).unwrap_or(serde_json::Value::Null);
let mut sub_details = Vec::new();
if matches!(
algorithm_enum,
crate::common::AlgorithmEnum::And | crate::common::AlgorithmEnum::Or
) {
if let Some(arr) = detail_val.as_array() {
for item in arr {
if let Some(sub_id) = item.get("reco_id").and_then(|v| v.as_i64()) {
if let Ok(Some(sub)) = Self::fetch_recognition_detail(handle, sub_id) {
sub_details.push(sub);
}
}
}
}
}
Ok(Some(crate::common::RecognitionDetail {
node_name: node_name.as_str().to_string(),
algorithm: algorithm_enum,
hit: hit != 0,
box_rect: crate::common::Rect::from(box_rect),
detail: detail_val,
raw_image: raw.to_vec(),
draw_images: draws.to_vec_of_vec(),
sub_details,
}))
}
pub(crate) fn fetch_action_detail(
handle: *mut sys::MaaTasker,
act_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::ActionDetail>> {
let node_name = crate::buffer::MaaStringBuffer::new()?;
let action = crate::buffer::MaaStringBuffer::new()?;
let mut result_box = sys::MaaRect {
x: 0,
y: 0,
width: 0,
height: 0,
};
let mut success = 0;
let detail = crate::buffer::MaaStringBuffer::new()?;
let ret = unsafe {
sys::MaaTaskerGetActionDetail(
handle,
act_id,
node_name.raw(),
action.raw(),
&mut result_box,
&mut success,
detail.raw(),
)
};
if ret == 0 {
return Ok(None);
}
Ok(Some(crate::common::ActionDetail {
node_name: node_name.as_str().to_string(),
action: crate::common::ActionEnum::from(action.as_str().to_string()),
box_rect: crate::common::Rect::from(result_box),
success: success != 0,
detail: serde_json::from_str(detail.as_str()).unwrap_or(serde_json::Value::Null),
}))
}
pub(crate) fn fetch_wait_freezes_detail(
handle: *mut sys::MaaTasker,
wf_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::WaitFreezesDetail>> {
let name = crate::buffer::MaaStringBuffer::new()?;
let phase = crate::buffer::MaaStringBuffer::new()?;
let mut success = 0;
let mut elapsed_ms: sys::MaaSize = 0;
let mut reco_id_list_size: sys::MaaSize = 0;
let mut roi = sys::MaaRect {
x: 0,
y: 0,
width: 0,
height: 0,
};
let ret = unsafe {
sys::MaaTaskerGetWaitFreezesDetail(
handle,
wf_id,
name.raw(),
phase.raw(),
&mut success,
&mut elapsed_ms,
std::ptr::null_mut(),
&mut reco_id_list_size,
&mut roi,
)
};
if ret == 0 {
return Ok(None);
}
let mut reco_id_list = vec![0; reco_id_list_size as usize];
let reco_id_list_ptr = if reco_id_list.is_empty() {
std::ptr::null_mut()
} else {
reco_id_list.as_mut_ptr()
};
let ret = unsafe {
sys::MaaTaskerGetWaitFreezesDetail(
handle,
wf_id,
name.raw(),
phase.raw(),
&mut success,
&mut elapsed_ms,
reco_id_list_ptr,
&mut reco_id_list_size,
&mut roi,
)
};
if ret == 0 {
return Ok(None);
}
reco_id_list.truncate(reco_id_list_size as usize);
Ok(Some(crate::common::WaitFreezesDetail {
wf_id,
name: name.as_str().to_string(),
phase: phase.as_str().to_string(),
success: success != 0,
elapsed_ms,
reco_id_list,
roi: crate::common::Rect::from(roi),
}))
}
pub(crate) fn fetch_node_detail(
handle: *mut sys::MaaTasker,
node_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::NodeDetail>> {
let node_name = crate::buffer::MaaStringBuffer::new()?;
let mut reco_id = 0;
let mut act_id = 0;
let mut completed = 0;
let ret = unsafe {
sys::MaaTaskerGetNodeDetail(
handle,
node_id,
node_name.raw(),
&mut reco_id,
&mut act_id,
&mut completed,
)
};
if ret == 0 {
return Ok(None);
}
let recognition = if reco_id > 0 {
Self::fetch_recognition_detail(handle, reco_id)?
} else {
None
};
let action = if act_id > 0 {
Self::fetch_action_detail(handle, act_id)?
} else {
None
};
Ok(Some(crate::common::NodeDetail {
node_name: node_name.as_str().to_string(),
reco_id,
act_id,
completed: completed != 0,
recognition,
action,
}))
}
pub(crate) fn fetch_task_detail(
handle: *mut sys::MaaTasker,
task_id: crate::common::MaaId,
) -> MaaResult<Option<crate::common::TaskDetail>> {
let entry = crate::buffer::MaaStringBuffer::new()?;
let mut node_id_list_size: sys::MaaSize = 0;
let mut status: sys::MaaStatus = 0;
let ret = unsafe {
sys::MaaTaskerGetTaskDetail(
handle,
task_id,
entry.raw(),
std::ptr::null_mut(),
&mut node_id_list_size,
&mut status,
)
};
if ret == 0 {
return Ok(None);
}
let mut node_id_list = vec![0; node_id_list_size as usize];
let ret = unsafe {
sys::MaaTaskerGetTaskDetail(
handle,
task_id,
entry.raw(),
node_id_list.as_mut_ptr(),
&mut node_id_list_size,
&mut status,
)
};
if ret == 0 {
return Ok(None);
}
let mut nodes = Vec::with_capacity(node_id_list.len());
for &nid in &node_id_list {
nodes.push(Self::fetch_node_detail(handle, nid)?);
}
Ok(Some(crate::common::TaskDetail {
entry: entry.as_str().to_string(),
node_id_list,
status: crate::common::MaaStatus(status as i32),
nodes,
}))
}
pub fn post_task(
&self,
entry: &str,
pipeline_override: &str,
) -> MaaResult<crate::job::TaskJob<'static, crate::common::TaskDetail>> {
let c_entry = std::ffi::CString::new(entry)?;
let c_pipeline = std::ffi::CString::new(pipeline_override)?;
let id = unsafe {
sys::MaaTaskerPostTask(
self.inner.handle.as_ptr(),
c_entry.as_ptr(),
c_pipeline.as_ptr(),
)
};
let inner = self.inner.clone();
let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
crate::common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
});
let inner = self.inner.clone();
let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
crate::common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
});
let inner = self.inner.clone();
let get_fn =
move |task_id: crate::common::MaaId| -> MaaResult<Option<crate::common::TaskDetail>> {
Tasker::fetch_task_detail(inner.handle.as_ptr(), task_id)
};
let inner = self.inner.clone();
let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
let c_pipeline = std::ffi::CString::new(pipeline)?;
let ret = unsafe {
sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
};
Ok(ret != 0)
});
Ok(crate::job::TaskJob::new(
crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
override_fn,
))
}
pub fn post_task_json(
&self,
entry: &str,
pipeline_override: &serde_json::Value,
) -> MaaResult<crate::job::TaskJob<'static, crate::common::TaskDetail>> {
self.post_task(entry, &pipeline_override.to_string())
}
pub fn inited(&self) -> bool {
unsafe { sys::MaaTaskerInited(self.inner.handle.as_ptr()) != 0 }
}
#[inline]
pub fn raw(&self) -> *mut sys::MaaTasker {
self.inner.handle.as_ptr()
}
pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
where
F: Fn(&str, &str) + Send + Sync + 'static,
{
let (cb, arg) = crate::callback::EventCallback::new(callback);
let id = unsafe { sys::MaaTaskerAddSink(self.inner.handle.as_ptr(), cb, arg) };
if id > 0 {
self.inner
.callbacks
.lock()
.unwrap()
.insert(id, arg as usize);
Ok(id)
} else {
unsafe { crate::callback::EventCallback::drop_callback(arg) };
Err(MaaError::FrameworkError(0))
}
}
pub fn add_event_sink(
&self,
sink: Box<dyn crate::event_sink::EventSink>,
) -> MaaResult<sys::MaaSinkId> {
let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
let id = unsafe { sys::MaaTaskerAddSink(self.inner.handle.as_ptr(), cb, arg) };
if id > 0 {
self.inner
.event_sinks
.lock()
.unwrap()
.insert(id, arg as usize);
Ok(id)
} else {
unsafe { crate::callback::EventCallback::drop_sink(arg) };
Err(MaaError::FrameworkError(0))
}
}
pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
unsafe { sys::MaaTaskerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
} else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
}
}
pub fn clear_sinks(&self) {
unsafe { sys::MaaTaskerClearSinks(self.inner.handle.as_ptr()) };
let mut callbacks = self.inner.callbacks.lock().unwrap();
for (_, ptr) in callbacks.drain() {
unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
}
let mut event_sinks = self.inner.event_sinks.lock().unwrap();
for (_, ptr) in event_sinks.drain() {
unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
}
}
#[deprecated(since = "0.5.1", note = "Use add_sink() instead")]
pub fn register_callback<F>(&self, callback: F) -> MaaResult<crate::common::MaaId>
where
F: Fn(&str, &str) + Send + Sync + 'static,
{
self.add_sink(callback)
}
pub fn post_stop(&self) -> MaaResult<crate::common::MaaId> {
unsafe {
let id = sys::MaaTaskerPostStop(self.inner.handle.as_ptr());
Ok(id)
}
}
pub fn is_running(&self) -> bool {
unsafe { sys::MaaTaskerRunning(self.inner.handle.as_ptr()) != 0 }
}
pub fn running(&self) -> bool {
self.is_running()
}
pub fn stopping(&self) -> bool {
unsafe { sys::MaaTaskerStopping(self.inner.handle.as_ptr()) != 0 }
}
pub fn add_context_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
where
F: Fn(&str, &str) + Send + Sync + 'static,
{
let (cb, arg) = crate::callback::EventCallback::new(callback);
let id = unsafe { sys::MaaTaskerAddContextSink(self.inner.handle.as_ptr(), cb, arg) };
if id > 0 {
self.inner
.callbacks
.lock()
.unwrap()
.insert(id, arg as usize);
Ok(id)
} else {
unsafe { crate::callback::EventCallback::drop_callback(arg) };
Err(MaaError::FrameworkError(0))
}
}
pub fn add_context_event_sink(
&self,
sink: Box<dyn crate::event_sink::EventSink>,
) -> MaaResult<sys::MaaSinkId> {
let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
let id = unsafe { sys::MaaTaskerAddContextSink(self.inner.handle.as_ptr(), cb, arg) };
if id > 0 {
self.inner
.event_sinks
.lock()
.unwrap()
.insert(id, arg as usize);
Ok(id)
} else {
unsafe { crate::callback::EventCallback::drop_sink(arg) };
Err(MaaError::FrameworkError(0))
}
}
pub fn remove_context_sink(&self, sink_id: sys::MaaSinkId) {
unsafe { sys::MaaTaskerRemoveContextSink(self.inner.handle.as_ptr(), sink_id) };
if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
} else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
}
}
pub fn clear_context_sinks(&self) {
unsafe { sys::MaaTaskerClearContextSinks(self.inner.handle.as_ptr()) };
}
pub fn clear_cache(&self) -> MaaResult<()> {
let ret = unsafe { sys::MaaTaskerClearCache(self.inner.handle.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn override_pipeline(
&self,
task_id: crate::common::MaaId,
pipeline_override: &str,
) -> MaaResult<bool> {
let c_pipeline = std::ffi::CString::new(pipeline_override)?;
let ret = unsafe {
sys::MaaTaskerOverridePipeline(self.inner.handle.as_ptr(), task_id, c_pipeline.as_ptr())
};
Ok(ret != 0)
}
pub fn get_latest_node(&self, node_name: &str) -> MaaResult<Option<crate::common::MaaId>> {
let c_name = std::ffi::CString::new(node_name)?;
let mut node_id: crate::common::MaaId = 0;
let ret = unsafe {
sys::MaaTaskerGetLatestNode(self.inner.handle.as_ptr(), c_name.as_ptr(), &mut node_id)
};
if ret != 0 && node_id != 0 {
Ok(Some(node_id))
} else {
Ok(None)
}
}
pub fn bind(
&self,
resource: &Resource,
controller: &crate::controller::Controller,
) -> MaaResult<()> {
self.bind_resource(resource)?;
self.bind_controller(controller)
}
pub fn resource(&self) -> Option<crate::resource::ResourceRef<'_>> {
let ptr = unsafe { sys::MaaTaskerGetResource(self.inner.handle.as_ptr()) };
crate::resource::ResourceRef::from_ptr(ptr)
}
pub fn controller(&self) -> Option<crate::controller::ControllerRef<'_>> {
let ptr = unsafe { sys::MaaTaskerGetController(self.inner.handle.as_ptr()) };
crate::controller::ControllerRef::from_ptr(ptr)
}
pub fn resource_handle(&self) -> *mut sys::MaaResource {
unsafe { sys::MaaTaskerGetResource(self.inner.handle.as_ptr()) }
}
pub fn controller_handle(&self) -> *mut sys::MaaController {
unsafe { sys::MaaTaskerGetController(self.inner.handle.as_ptr()) }
}
pub fn post_recognition(
&self,
reco_type: &str,
reco_param: &str,
image: &crate::buffer::MaaImageBuffer,
) -> MaaResult<crate::job::TaskJob<'static, crate::common::RecognitionDetail>> {
let c_type = std::ffi::CString::new(reco_type)?;
let c_param = std::ffi::CString::new(reco_param)?;
let id = unsafe {
sys::MaaTaskerPostRecognition(
self.inner.handle.as_ptr(),
c_type.as_ptr(),
c_param.as_ptr(),
image.raw(),
)
};
let inner = self.inner.clone();
let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
});
let inner = self.inner.clone();
let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
});
let inner = self.inner.clone();
let get_fn = move |reco_id: common::MaaId| -> MaaResult<Option<common::RecognitionDetail>> {
Tasker::fetch_recognition_detail(inner.handle.as_ptr(), reco_id)
};
let inner = self.inner.clone();
let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
let c_pipeline = std::ffi::CString::new(pipeline)?;
let ret = unsafe {
sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
};
Ok(ret != 0)
});
Ok(crate::job::TaskJob::new(
crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
override_fn,
))
}
pub fn post_action(
&self,
action_type: &str,
action_param: &str,
box_rect: &common::Rect,
reco_detail: &str,
) -> MaaResult<crate::job::TaskJob<'static, crate::common::ActionDetail>> {
let c_type = std::ffi::CString::new(action_type)?;
let c_param = std::ffi::CString::new(action_param)?;
let c_detail = std::ffi::CString::new(reco_detail)?;
let maa_rect = sys::MaaRect {
x: box_rect.x,
y: box_rect.y,
width: box_rect.width,
height: box_rect.height,
};
let id = unsafe {
sys::MaaTaskerPostAction(
self.inner.handle.as_ptr(),
c_type.as_ptr(),
c_param.as_ptr(),
&maa_rect,
c_detail.as_ptr(),
)
};
let inner = self.inner.clone();
let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
});
let inner = self.inner.clone();
let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
});
let inner = self.inner.clone();
let get_fn = move |act_id: common::MaaId| -> MaaResult<Option<common::ActionDetail>> {
Tasker::fetch_action_detail(inner.handle.as_ptr(), act_id)
};
let inner = self.inner.clone();
let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
let c_pipeline = std::ffi::CString::new(pipeline)?;
let ret = unsafe {
sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
};
Ok(ret != 0)
});
Ok(crate::job::TaskJob::new(
crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
override_fn,
))
}
pub fn set_log_dir<P: AsRef<std::path::Path>>(path: P) -> MaaResult<()> {
let path_str = path.as_ref().to_string_lossy();
let c_path = std::ffi::CString::new(path_str.as_ref())?;
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_LogDir as i32,
c_path.as_ptr() as *mut _,
c_path.as_bytes().len() as u64,
)
};
common::check_bool(ret)
}
pub fn set_save_draw(save: bool) -> MaaResult<()> {
let val = if save { 1 } else { 0 };
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_SaveDraw as i32,
&val as *const _ as *mut _,
std::mem::size_of_val(&val) as u64,
)
};
common::check_bool(ret)
}
pub fn set_stdout_level(level: sys::MaaLoggingLevel) -> MaaResult<()> {
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_StdoutLevel as i32,
&level as *const _ as *mut _,
std::mem::size_of_val(&level) as u64,
)
};
common::check_bool(ret)
}
pub fn set_debug_mode(debug: bool) -> MaaResult<()> {
let val = if debug { 1 } else { 0 };
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_DebugMode as i32,
&val as *const _ as *mut _,
std::mem::size_of_val(&val) as u64,
)
};
common::check_bool(ret)
}
pub fn set_save_on_error(save: bool) -> MaaResult<()> {
let val = if save { 1 } else { 0 };
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_SaveOnError as i32,
&val as *const _ as *mut _,
std::mem::size_of_val(&val) as u64,
)
};
common::check_bool(ret)
}
pub fn set_draw_quality(quality: i32) -> MaaResult<()> {
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_DrawQuality as i32,
&quality as *const _ as *mut _,
std::mem::size_of_val(&quality) as u64,
)
};
common::check_bool(ret)
}
pub fn set_reco_image_cache_limit(limit: usize) -> MaaResult<()> {
let ret = unsafe {
sys::MaaGlobalSetOption(
sys::MaaGlobalOptionEnum_MaaGlobalOption_RecoImageCacheLimit as i32,
&limit as *const _ as *mut _,
std::mem::size_of_val(&limit) as u64,
)
};
common::check_bool(ret)
}
pub fn load_plugin<P: AsRef<std::path::Path>>(path: P) -> MaaResult<()> {
let path_str = path.as_ref().to_string_lossy();
let c_path = std::ffi::CString::new(path_str.as_ref())?;
let ret = unsafe { sys::MaaGlobalLoadPlugin(c_path.as_ptr()) };
common::check_bool(ret)
}
}
impl Drop for TaskerInner {
fn drop(&mut self) {
unsafe {
if self.owns_handle {
sys::MaaTaskerClearSinks(self.handle.as_ptr());
} else {
let callbacks_keys: Vec<_> =
self.callbacks.lock().unwrap().keys().copied().collect();
for id in callbacks_keys {
sys::MaaTaskerRemoveSink(self.handle.as_ptr(), id);
}
let event_sinks_keys: Vec<_> =
self.event_sinks.lock().unwrap().keys().copied().collect();
for id in event_sinks_keys {
sys::MaaTaskerRemoveSink(self.handle.as_ptr(), id);
}
}
let mut callbacks = self.callbacks.lock().unwrap();
for (_, ptr) in callbacks.drain() {
crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
}
let mut event_sinks = self.event_sinks.lock().unwrap();
for (_, ptr) in event_sinks.drain() {
crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
}
if self.owns_handle {
sys::MaaTaskerDestroy(self.handle.as_ptr());
}
}
}
}