1use crate::resource::Resource;
4use crate::{common, sys, MaaError, MaaResult};
5use std::ptr::NonNull;
6
7use std::collections::HashMap;
8use std::ffi::c_void;
9use std::sync::Mutex;
10
11use std::sync::Arc;
19
20struct TaskerInner {
21 handle: NonNull<sys::MaaTasker>,
22 owns_handle: bool,
23 callbacks: Mutex<HashMap<sys::MaaSinkId, usize>>, event_sinks: Mutex<HashMap<sys::MaaSinkId, usize>>,
25 resource: Mutex<Option<Resource>>,
26 controller: Mutex<Option<crate::controller::Controller>>,
27}
28
29unsafe impl Send for TaskerInner {}
30unsafe impl Sync for TaskerInner {}
31
32#[derive(Clone)]
40pub struct Tasker {
41 inner: Arc<TaskerInner>,
42}
43
44unsafe impl Send for Tasker {}
45unsafe impl Sync for Tasker {}
46
47impl Tasker {
48 pub fn new() -> MaaResult<Self> {
50 let handle = unsafe { sys::MaaTaskerCreate() };
51 if let Some(ptr) = NonNull::new(handle) {
52 Ok(Self {
53 inner: Arc::new(TaskerInner {
54 handle: ptr,
55 owns_handle: true,
56 callbacks: Mutex::new(HashMap::new()),
57 event_sinks: Mutex::new(HashMap::new()),
58 resource: Mutex::new(None),
59 controller: Mutex::new(None),
60 }),
61 })
62 } else {
63 Err(MaaError::NullPointer)
64 }
65 }
66
67 pub unsafe fn from_raw(ptr: *mut sys::MaaTasker, owns: bool) -> MaaResult<Self> {
73 if let Some(handle) = NonNull::new(ptr) {
74 Ok(Self {
75 inner: Arc::new(TaskerInner {
76 handle,
77 owns_handle: owns,
78 callbacks: Mutex::new(HashMap::new()),
79 event_sinks: Mutex::new(HashMap::new()),
80 resource: Mutex::new(None),
81 controller: Mutex::new(None),
82 }),
83 })
84 } else {
85 Err(MaaError::NullPointer)
86 }
87 }
88
89 pub fn bind_resource(&self, res: &Resource) -> MaaResult<()> {
91 let ret = unsafe { sys::MaaTaskerBindResource(self.inner.handle.as_ptr(), res.raw()) };
92 common::check_bool(ret)?;
93 *self.inner.resource.lock().unwrap() = Some(res.clone());
94 Ok(())
95 }
96
97 pub fn bind_controller(&self, ctrl: &crate::controller::Controller) -> MaaResult<()> {
99 let ret = unsafe { sys::MaaTaskerBindController(self.inner.handle.as_ptr(), ctrl.raw()) };
100 common::check_bool(ret)?;
101 *self.inner.controller.lock().unwrap() = Some(ctrl.clone());
102 Ok(())
103 }
104
105 pub fn get_recognition_detail(
107 &self,
108 reco_id: crate::common::MaaId,
109 ) -> MaaResult<Option<crate::common::RecognitionDetail>> {
110 Self::fetch_recognition_detail(self.inner.handle.as_ptr(), reco_id)
111 }
112
113 pub fn get_action_detail(
115 &self,
116 act_id: crate::common::MaaId,
117 ) -> MaaResult<Option<crate::common::ActionDetail>> {
118 Self::fetch_action_detail(self.inner.handle.as_ptr(), act_id)
119 }
120
121 pub fn get_node_detail(
123 &self,
124 node_id: crate::common::MaaId,
125 ) -> MaaResult<Option<crate::common::NodeDetail>> {
126 Self::fetch_node_detail(self.inner.handle.as_ptr(), node_id)
127 }
128
129 pub fn get_task_detail(
131 &self,
132 task_id: crate::common::MaaId,
133 ) -> MaaResult<Option<crate::common::TaskDetail>> {
134 Self::fetch_task_detail(self.inner.handle.as_ptr(), task_id)
135 }
136
137 pub(crate) fn fetch_recognition_detail(
140 handle: *mut sys::MaaTasker,
141 reco_id: crate::common::MaaId,
142 ) -> MaaResult<Option<crate::common::RecognitionDetail>> {
143 let node_name = crate::buffer::MaaStringBuffer::new()?;
144 let algorithm = crate::buffer::MaaStringBuffer::new()?;
145 let mut hit = 0;
146 let mut box_rect = sys::MaaRect {
147 x: 0,
148 y: 0,
149 width: 0,
150 height: 0,
151 };
152 let detail = crate::buffer::MaaStringBuffer::new()?;
153 let raw = crate::buffer::MaaImageBuffer::new()?;
154 let draws = crate::buffer::MaaImageListBuffer::new()?;
155
156 let ret = unsafe {
157 sys::MaaTaskerGetRecognitionDetail(
158 handle,
159 reco_id,
160 node_name.raw(),
161 algorithm.raw(),
162 &mut hit,
163 &mut box_rect,
164 detail.raw(),
165 raw.raw(),
166 draws.raw(),
167 )
168 };
169
170 if ret == 0 {
171 return Ok(None);
172 }
173
174 let algorithm_str = algorithm.as_str().to_string();
175 let algorithm_enum = crate::common::AlgorithmEnum::from(algorithm_str);
176 let detail_val: serde_json::Value =
177 serde_json::from_str(detail.as_str()).unwrap_or(serde_json::Value::Null);
178
179 let mut sub_details = Vec::new();
180
181 if matches!(
182 algorithm_enum,
183 crate::common::AlgorithmEnum::And | crate::common::AlgorithmEnum::Or
184 ) {
185 if let Some(arr) = detail_val.as_array() {
187 for item in arr {
188 if let Some(sub_id) = item.get("reco_id").and_then(|v| v.as_i64()) {
189 if let Ok(Some(sub)) = Self::fetch_recognition_detail(handle, sub_id) {
190 sub_details.push(sub);
191 }
192 }
193 }
194 }
195 }
196
197 Ok(Some(crate::common::RecognitionDetail {
198 node_name: node_name.as_str().to_string(),
199 algorithm: algorithm_enum,
200 hit: hit != 0,
201 box_rect: crate::common::Rect::from(box_rect),
202 detail: detail_val,
203 raw_image: raw.to_vec(),
204 draw_images: draws.to_vec_of_vec(),
205 sub_details,
206 }))
207 }
208
209 pub(crate) fn fetch_action_detail(
210 handle: *mut sys::MaaTasker,
211 act_id: crate::common::MaaId,
212 ) -> MaaResult<Option<crate::common::ActionDetail>> {
213 let node_name = crate::buffer::MaaStringBuffer::new()?;
214 let action = crate::buffer::MaaStringBuffer::new()?;
215 let mut result_box = sys::MaaRect {
216 x: 0,
217 y: 0,
218 width: 0,
219 height: 0,
220 };
221 let mut success = 0;
222 let detail = crate::buffer::MaaStringBuffer::new()?;
223
224 let ret = unsafe {
225 sys::MaaTaskerGetActionDetail(
226 handle,
227 act_id,
228 node_name.raw(),
229 action.raw(),
230 &mut result_box,
231 &mut success,
232 detail.raw(),
233 )
234 };
235
236 if ret == 0 {
237 return Ok(None);
238 }
239
240 Ok(Some(crate::common::ActionDetail {
241 node_name: node_name.as_str().to_string(),
242 action: crate::common::ActionEnum::from(action.as_str().to_string()),
243 box_rect: crate::common::Rect::from(result_box),
244 success: success != 0,
245 detail: serde_json::from_str(detail.as_str()).unwrap_or(serde_json::Value::Null),
246 }))
247 }
248
249 pub(crate) fn fetch_node_detail(
250 handle: *mut sys::MaaTasker,
251 node_id: crate::common::MaaId,
252 ) -> MaaResult<Option<crate::common::NodeDetail>> {
253 let node_name = crate::buffer::MaaStringBuffer::new()?;
254 let mut reco_id = 0;
255 let mut act_id = 0;
256 let mut completed = 0;
257
258 let ret = unsafe {
259 sys::MaaTaskerGetNodeDetail(
260 handle,
261 node_id,
262 node_name.raw(),
263 &mut reco_id,
264 &mut act_id,
265 &mut completed,
266 )
267 };
268
269 if ret == 0 {
270 return Ok(None);
271 }
272
273 let recognition = if reco_id > 0 {
277 Self::fetch_recognition_detail(handle, reco_id)?
278 } else {
279 None
280 };
281
282 let action = if act_id > 0 {
283 Self::fetch_action_detail(handle, act_id)?
284 } else {
285 None
286 };
287
288 Ok(Some(crate::common::NodeDetail {
289 node_name: node_name.as_str().to_string(),
290 reco_id,
291 act_id,
292 completed: completed != 0,
293 recognition,
294 action,
295 }))
296 }
297
298 pub(crate) fn fetch_task_detail(
299 handle: *mut sys::MaaTasker,
300 task_id: crate::common::MaaId,
301 ) -> MaaResult<Option<crate::common::TaskDetail>> {
302 let entry = crate::buffer::MaaStringBuffer::new()?;
303 let mut node_id_list_size: sys::MaaSize = 0;
304 let mut status: sys::MaaStatus = 0;
305
306 let ret = unsafe {
307 sys::MaaTaskerGetTaskDetail(
308 handle,
309 task_id,
310 entry.raw(),
311 std::ptr::null_mut(),
312 &mut node_id_list_size,
313 &mut status,
314 )
315 };
316
317 if ret == 0 {
318 return Ok(None);
319 }
320
321 let mut node_id_list = vec![0; node_id_list_size as usize];
322 let ret = unsafe {
323 sys::MaaTaskerGetTaskDetail(
324 handle,
325 task_id,
326 entry.raw(),
327 node_id_list.as_mut_ptr(),
328 &mut node_id_list_size,
329 &mut status,
330 )
331 };
332
333 if ret == 0 {
334 return Ok(None);
335 }
336
337 let mut nodes = Vec::with_capacity(node_id_list.len());
339 for &nid in &node_id_list {
340 nodes.push(Self::fetch_node_detail(handle, nid)?);
341 }
342
343 Ok(Some(crate::common::TaskDetail {
344 entry: entry.as_str().to_string(),
345 node_id_list,
346 status: crate::common::MaaStatus(status as i32),
347 nodes,
348 }))
349 }
350
351 pub fn post_task(
360 &self,
361 entry: &str,
362 pipeline_override: &str,
363 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::TaskDetail>> {
364 let c_entry = std::ffi::CString::new(entry)?;
365 let c_pipeline = std::ffi::CString::new(pipeline_override)?;
366 let id = unsafe {
367 sys::MaaTaskerPostTask(
368 self.inner.handle.as_ptr(),
369 c_entry.as_ptr(),
370 c_pipeline.as_ptr(),
371 )
372 };
373
374 let inner = self.inner.clone();
375 let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
376 crate::common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
377 });
378
379 let inner = self.inner.clone();
380 let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
381 crate::common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
382 });
383
384 let inner = self.inner.clone();
385 let get_fn =
386 move |task_id: crate::common::MaaId| -> MaaResult<Option<crate::common::TaskDetail>> {
387 Tasker::fetch_task_detail(inner.handle.as_ptr(), task_id)
388 };
389
390 let inner = self.inner.clone();
392 let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
393 let c_pipeline = std::ffi::CString::new(pipeline)?;
394 let ret = unsafe {
395 sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
396 };
397 Ok(ret != 0)
398 });
399
400 Ok(crate::job::TaskJob::new(
401 crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
402 override_fn,
403 ))
404 }
405
406 pub fn post_task_json(
418 &self,
419 entry: &str,
420 pipeline_override: &serde_json::Value,
421 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::TaskDetail>> {
422 self.post_task(entry, &pipeline_override.to_string())
423 }
424
425 pub fn inited(&self) -> bool {
427 unsafe { sys::MaaTaskerInited(self.inner.handle.as_ptr()) != 0 }
428 }
429
430 #[inline]
432 pub fn raw(&self) -> *mut sys::MaaTasker {
433 self.inner.handle.as_ptr()
434 }
435
436 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
447 where
448 F: Fn(&str, &str) + Send + Sync + 'static,
449 {
450 let (cb, arg) = crate::callback::EventCallback::new(callback);
451 let id = unsafe { sys::MaaTaskerAddSink(self.inner.handle.as_ptr(), cb, arg) };
452 if id > 0 {
453 self.inner
454 .callbacks
455 .lock()
456 .unwrap()
457 .insert(id, arg as usize);
458 Ok(id)
459 } else {
460 unsafe { crate::callback::EventCallback::drop_callback(arg) };
461 Err(MaaError::FrameworkError(0))
462 }
463 }
464
465 pub fn add_event_sink(
477 &self,
478 sink: Box<dyn crate::event_sink::EventSink>,
479 ) -> MaaResult<sys::MaaSinkId> {
480 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
481 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
482 let id = unsafe { sys::MaaTaskerAddSink(self.inner.handle.as_ptr(), cb, arg) };
483 if id > 0 {
484 self.inner
485 .event_sinks
486 .lock()
487 .unwrap()
488 .insert(id, arg as usize);
489 Ok(id)
490 } else {
491 unsafe { crate::callback::EventCallback::drop_sink(arg) };
492 Err(MaaError::FrameworkError(0))
493 }
494 }
495
496 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
501 unsafe { sys::MaaTaskerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
502 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
503 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
504 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
505 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
506 }
507 }
508
509 pub fn clear_sinks(&self) {
511 unsafe { sys::MaaTaskerClearSinks(self.inner.handle.as_ptr()) };
512 let mut callbacks = self.inner.callbacks.lock().unwrap();
513 for (_, ptr) in callbacks.drain() {
514 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
515 }
516 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
517 for (_, ptr) in event_sinks.drain() {
518 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
519 }
520 }
521
522 #[deprecated(since = "0.5.1", note = "Use add_sink() instead")]
523 pub fn register_callback<F>(&self, callback: F) -> MaaResult<crate::common::MaaId>
524 where
525 F: Fn(&str, &str) + Send + Sync + 'static,
526 {
527 self.add_sink(callback)
528 }
529
530 pub fn post_stop(&self) -> MaaResult<crate::common::MaaId> {
532 unsafe {
533 let id = sys::MaaTaskerPostStop(self.inner.handle.as_ptr());
534 Ok(id)
535 }
536 }
537
538 pub fn is_running(&self) -> bool {
540 unsafe { sys::MaaTaskerRunning(self.inner.handle.as_ptr()) != 0 }
541 }
542
543 pub fn running(&self) -> bool {
545 self.is_running()
546 }
547
548 pub fn stopping(&self) -> bool {
550 unsafe { sys::MaaTaskerStopping(self.inner.handle.as_ptr()) != 0 }
551 }
552
553 pub fn add_context_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
558 where
559 F: Fn(&str, &str) + Send + Sync + 'static,
560 {
561 let (cb, arg) = crate::callback::EventCallback::new(callback);
562 let id = unsafe { sys::MaaTaskerAddContextSink(self.inner.handle.as_ptr(), cb, arg) };
563 if id > 0 {
564 self.inner
565 .callbacks
566 .lock()
567 .unwrap()
568 .insert(id, arg as usize);
569 Ok(id)
570 } else {
571 unsafe { crate::callback::EventCallback::drop_callback(arg) };
572 Err(MaaError::FrameworkError(0))
573 }
574 }
575
576 pub fn add_context_event_sink(
586 &self,
587 sink: Box<dyn crate::event_sink::EventSink>,
588 ) -> MaaResult<sys::MaaSinkId> {
589 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
590 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
591 let id = unsafe { sys::MaaTaskerAddContextSink(self.inner.handle.as_ptr(), cb, arg) };
592 if id > 0 {
593 self.inner
594 .event_sinks
595 .lock()
596 .unwrap()
597 .insert(id, arg as usize);
598 Ok(id)
599 } else {
600 unsafe { crate::callback::EventCallback::drop_sink(arg) };
601 Err(MaaError::FrameworkError(0))
602 }
603 }
604
605 pub fn remove_context_sink(&self, sink_id: sys::MaaSinkId) {
607 unsafe { sys::MaaTaskerRemoveContextSink(self.inner.handle.as_ptr(), sink_id) };
608 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
609 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
610 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
611 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
612 }
613 }
614
615 pub fn clear_context_sinks(&self) {
617 unsafe { sys::MaaTaskerClearContextSinks(self.inner.handle.as_ptr()) };
618 }
620
621 pub fn clear_cache(&self) -> MaaResult<()> {
623 let ret = unsafe { sys::MaaTaskerClearCache(self.inner.handle.as_ptr()) };
624 crate::common::check_bool(ret)
625 }
626
627 pub fn override_pipeline(
633 &self,
634 task_id: crate::common::MaaId,
635 pipeline_override: &str,
636 ) -> MaaResult<bool> {
637 let c_pipeline = std::ffi::CString::new(pipeline_override)?;
638 let ret = unsafe {
639 sys::MaaTaskerOverridePipeline(self.inner.handle.as_ptr(), task_id, c_pipeline.as_ptr())
640 };
641 Ok(ret != 0)
642 }
643
644 pub fn get_latest_node(&self, node_name: &str) -> MaaResult<Option<crate::common::MaaId>> {
646 let c_name = std::ffi::CString::new(node_name)?;
647 let mut node_id: crate::common::MaaId = 0;
648 let ret = unsafe {
649 sys::MaaTaskerGetLatestNode(self.inner.handle.as_ptr(), c_name.as_ptr(), &mut node_id)
650 };
651 if ret != 0 && node_id != 0 {
652 Ok(Some(node_id))
653 } else {
654 Ok(None)
655 }
656 }
657
658 pub fn bind(
660 &self,
661 resource: &Resource,
662 controller: &crate::controller::Controller,
663 ) -> MaaResult<()> {
664 self.bind_resource(resource)?;
665 self.bind_controller(controller)
666 }
667
668 pub fn resource(&self) -> Option<crate::resource::ResourceRef<'_>> {
679 let ptr = unsafe { sys::MaaTaskerGetResource(self.inner.handle.as_ptr()) };
680 crate::resource::ResourceRef::from_ptr(ptr)
681 }
682
683 pub fn controller(&self) -> Option<crate::controller::ControllerRef<'_>> {
694 let ptr = unsafe { sys::MaaTaskerGetController(self.inner.handle.as_ptr()) };
695 crate::controller::ControllerRef::from_ptr(ptr)
696 }
697
698 pub fn resource_handle(&self) -> *mut sys::MaaResource {
702 unsafe { sys::MaaTaskerGetResource(self.inner.handle.as_ptr()) }
703 }
704
705 pub fn controller_handle(&self) -> *mut sys::MaaController {
709 unsafe { sys::MaaTaskerGetController(self.inner.handle.as_ptr()) }
710 }
711
712 pub fn post_recognition(
719 &self,
720 reco_type: &str,
721 reco_param: &str,
722 image: &crate::buffer::MaaImageBuffer,
723 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::RecognitionDetail>> {
724 let c_type = std::ffi::CString::new(reco_type)?;
725 let c_param = std::ffi::CString::new(reco_param)?;
726 let id = unsafe {
727 sys::MaaTaskerPostRecognition(
728 self.inner.handle.as_ptr(),
729 c_type.as_ptr(),
730 c_param.as_ptr(),
731 image.raw(),
732 )
733 };
734
735 let inner = self.inner.clone();
736 let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
737 common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
738 });
739
740 let inner = self.inner.clone();
741 let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
742 common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
743 });
744
745 let inner = self.inner.clone();
746 let get_fn = move |reco_id: common::MaaId| -> MaaResult<Option<common::RecognitionDetail>> {
747 Tasker::fetch_recognition_detail(inner.handle.as_ptr(), reco_id)
748 };
749
750 let inner = self.inner.clone();
752 let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
753 let c_pipeline = std::ffi::CString::new(pipeline)?;
754 let ret = unsafe {
755 sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
756 };
757 Ok(ret != 0)
758 });
759
760 Ok(crate::job::TaskJob::new(
761 crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
762 override_fn,
763 ))
764 }
765
766 pub fn post_action(
774 &self,
775 action_type: &str,
776 action_param: &str,
777 box_rect: &common::Rect,
778 reco_detail: &str,
779 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::ActionDetail>> {
780 let c_type = std::ffi::CString::new(action_type)?;
781 let c_param = std::ffi::CString::new(action_param)?;
782 let c_detail = std::ffi::CString::new(reco_detail)?;
783 let maa_rect = sys::MaaRect {
784 x: box_rect.x,
785 y: box_rect.y,
786 width: box_rect.width,
787 height: box_rect.height,
788 };
789
790 let id = unsafe {
791 sys::MaaTaskerPostAction(
792 self.inner.handle.as_ptr(),
793 c_type.as_ptr(),
794 c_param.as_ptr(),
795 &maa_rect,
796 c_detail.as_ptr(),
797 )
798 };
799
800 let inner = self.inner.clone();
801 let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
802 common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
803 });
804
805 let inner = self.inner.clone();
806 let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
807 common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
808 });
809
810 let inner = self.inner.clone();
811 let get_fn = move |act_id: common::MaaId| -> MaaResult<Option<common::ActionDetail>> {
812 Tasker::fetch_action_detail(inner.handle.as_ptr(), act_id)
813 };
814
815 let inner = self.inner.clone();
817 let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
818 let c_pipeline = std::ffi::CString::new(pipeline)?;
819 let ret = unsafe {
820 sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
821 };
822 Ok(ret != 0)
823 });
824
825 Ok(crate::job::TaskJob::new(
826 crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
827 override_fn,
828 ))
829 }
830
831 pub fn set_log_dir<P: AsRef<std::path::Path>>(path: P) -> MaaResult<()> {
835 let path_str = path.as_ref().to_string_lossy();
836 let c_path = std::ffi::CString::new(path_str.as_ref())?;
837 let ret = unsafe {
838 sys::MaaGlobalSetOption(
839 sys::MaaGlobalOptionEnum_MaaGlobalOption_LogDir as i32,
840 c_path.as_ptr() as *mut _,
841 c_path.as_bytes().len() as u64,
842 )
843 };
844 common::check_bool(ret)
845 }
846
847 pub fn set_save_draw(save: bool) -> MaaResult<()> {
849 let val = if save { 1 } else { 0 };
850 let ret = unsafe {
851 sys::MaaGlobalSetOption(
852 sys::MaaGlobalOptionEnum_MaaGlobalOption_SaveDraw as i32,
853 &val as *const _ as *mut _,
854 std::mem::size_of_val(&val) as u64,
855 )
856 };
857 common::check_bool(ret)
858 }
859
860 pub fn set_stdout_level(level: sys::MaaLoggingLevel) -> MaaResult<()> {
862 let ret = unsafe {
863 sys::MaaGlobalSetOption(
864 sys::MaaGlobalOptionEnum_MaaGlobalOption_StdoutLevel as i32,
865 &level as *const _ as *mut _,
866 std::mem::size_of_val(&level) as u64,
867 )
868 };
869 common::check_bool(ret)
870 }
871
872 pub fn set_debug_mode(debug: bool) -> MaaResult<()> {
874 let val = if debug { 1 } else { 0 };
875 let ret = unsafe {
876 sys::MaaGlobalSetOption(
877 sys::MaaGlobalOptionEnum_MaaGlobalOption_DebugMode as i32,
878 &val as *const _ as *mut _,
879 std::mem::size_of_val(&val) as u64,
880 )
881 };
882 common::check_bool(ret)
883 }
884
885 pub fn set_save_on_error(save: bool) -> MaaResult<()> {
887 let val = if save { 1 } else { 0 };
888 let ret = unsafe {
889 sys::MaaGlobalSetOption(
890 sys::MaaGlobalOptionEnum_MaaGlobalOption_SaveOnError as i32,
891 &val as *const _ as *mut _,
892 std::mem::size_of_val(&val) as u64,
893 )
894 };
895 common::check_bool(ret)
896 }
897
898 pub fn set_draw_quality(quality: i32) -> MaaResult<()> {
900 let ret = unsafe {
901 sys::MaaGlobalSetOption(
902 sys::MaaGlobalOptionEnum_MaaGlobalOption_DrawQuality as i32,
903 &quality as *const _ as *mut _,
904 std::mem::size_of_val(&quality) as u64,
905 )
906 };
907 common::check_bool(ret)
908 }
909
910 pub fn set_reco_image_cache_limit(limit: usize) -> MaaResult<()> {
912 let ret = unsafe {
913 sys::MaaGlobalSetOption(
914 sys::MaaGlobalOptionEnum_MaaGlobalOption_RecoImageCacheLimit as i32,
915 &limit as *const _ as *mut _,
916 std::mem::size_of_val(&limit) as u64,
917 )
918 };
919 common::check_bool(ret)
920 }
921
922 pub fn load_plugin<P: AsRef<std::path::Path>>(path: P) -> MaaResult<()> {
924 let path_str = path.as_ref().to_string_lossy();
925 let c_path = std::ffi::CString::new(path_str.as_ref())?;
926 let ret = unsafe { sys::MaaGlobalLoadPlugin(c_path.as_ptr()) };
927 common::check_bool(ret)
928 }
929}
930
931impl Drop for TaskerInner {
932 fn drop(&mut self) {
933 unsafe {
934 sys::MaaTaskerClearSinks(self.handle.as_ptr());
935 let mut callbacks = self.callbacks.lock().unwrap();
936 for (_, ptr) in callbacks.drain() {
937 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
938 }
939 let mut event_sinks = self.event_sinks.lock().unwrap();
940 for (_, ptr) in event_sinks.drain() {
941 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
942 }
943 if self.owns_handle {
944 sys::MaaTaskerDestroy(self.handle.as_ptr())
945 }
946 }
947 }
948}