1use crate::resource::Resource;
4use crate::{MaaError, MaaResult, common, sys};
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_wait_freezes_detail(
123 &self,
124 wf_id: crate::common::MaaId,
125 ) -> MaaResult<Option<crate::common::WaitFreezesDetail>> {
126 Self::fetch_wait_freezes_detail(self.inner.handle.as_ptr(), wf_id)
127 }
128
129 pub fn get_node_detail(
131 &self,
132 node_id: crate::common::MaaId,
133 ) -> MaaResult<Option<crate::common::NodeDetail>> {
134 Self::fetch_node_detail(self.inner.handle.as_ptr(), node_id)
135 }
136
137 pub fn get_task_detail(
139 &self,
140 task_id: crate::common::MaaId,
141 ) -> MaaResult<Option<crate::common::TaskDetail>> {
142 Self::fetch_task_detail(self.inner.handle.as_ptr(), task_id)
143 }
144
145 pub(crate) fn fetch_recognition_detail(
148 handle: *mut sys::MaaTasker,
149 reco_id: crate::common::MaaId,
150 ) -> MaaResult<Option<crate::common::RecognitionDetail>> {
151 let node_name = crate::buffer::MaaStringBuffer::new()?;
152 let algorithm = crate::buffer::MaaStringBuffer::new()?;
153 let mut hit = 0;
154 let mut box_rect = sys::MaaRect {
155 x: 0,
156 y: 0,
157 width: 0,
158 height: 0,
159 };
160 let detail = crate::buffer::MaaStringBuffer::new()?;
161 let raw = crate::buffer::MaaImageBuffer::new()?;
162 let draws = crate::buffer::MaaImageListBuffer::new()?;
163
164 let ret = unsafe {
165 sys::MaaTaskerGetRecognitionDetail(
166 handle,
167 reco_id,
168 node_name.raw(),
169 algorithm.raw(),
170 &mut hit,
171 &mut box_rect,
172 detail.raw(),
173 raw.raw(),
174 draws.raw(),
175 )
176 };
177
178 if ret == 0 {
179 return Ok(None);
180 }
181
182 let algorithm_str = algorithm.as_str().to_string();
183 let algorithm_enum = crate::common::AlgorithmEnum::from(algorithm_str);
184 let detail_val: serde_json::Value =
185 serde_json::from_str(detail.as_str()).unwrap_or(serde_json::Value::Null);
186
187 let mut sub_details = Vec::new();
188
189 if matches!(
190 algorithm_enum,
191 crate::common::AlgorithmEnum::And | crate::common::AlgorithmEnum::Or
192 ) {
193 if let Some(arr) = detail_val.as_array() {
195 for item in arr {
196 if let Some(sub_id) = item.get("reco_id").and_then(|v| v.as_i64()) {
197 if let Ok(Some(sub)) = Self::fetch_recognition_detail(handle, sub_id) {
198 sub_details.push(sub);
199 }
200 }
201 }
202 }
203 }
204
205 Ok(Some(crate::common::RecognitionDetail {
206 reco_id,
207 node_name: node_name.as_str().to_string(),
208 algorithm: algorithm_enum,
209 hit: hit != 0,
210 box_rect: crate::common::Rect::from(box_rect),
211 detail: detail_val,
212 raw_image: raw.to_vec(),
213 draw_images: draws.to_vec_of_vec(),
214 sub_details,
215 }))
216 }
217
218 pub(crate) fn fetch_action_detail(
219 handle: *mut sys::MaaTasker,
220 act_id: crate::common::MaaId,
221 ) -> MaaResult<Option<crate::common::ActionDetail>> {
222 let node_name = crate::buffer::MaaStringBuffer::new()?;
223 let action = crate::buffer::MaaStringBuffer::new()?;
224 let mut result_box = sys::MaaRect {
225 x: 0,
226 y: 0,
227 width: 0,
228 height: 0,
229 };
230 let mut success = 0;
231 let detail = crate::buffer::MaaStringBuffer::new()?;
232
233 let ret = unsafe {
234 sys::MaaTaskerGetActionDetail(
235 handle,
236 act_id,
237 node_name.raw(),
238 action.raw(),
239 &mut result_box,
240 &mut success,
241 detail.raw(),
242 )
243 };
244
245 if ret == 0 {
246 return Ok(None);
247 }
248
249 Ok(Some(crate::common::ActionDetail {
250 action_id: act_id,
251 node_name: node_name.as_str().to_string(),
252 action: crate::common::ActionEnum::from(action.as_str().to_string()),
253 box_rect: crate::common::Rect::from(result_box),
254 success: success != 0,
255 detail: serde_json::from_str(detail.as_str()).unwrap_or(serde_json::Value::Null),
256 }))
257 }
258
259 pub(crate) fn fetch_wait_freezes_detail(
260 handle: *mut sys::MaaTasker,
261 wf_id: crate::common::MaaId,
262 ) -> MaaResult<Option<crate::common::WaitFreezesDetail>> {
263 let name = crate::buffer::MaaStringBuffer::new()?;
264 let phase = crate::buffer::MaaStringBuffer::new()?;
265 let mut success = 0;
266 let mut elapsed_ms: sys::MaaSize = 0;
267 let mut reco_id_list_size: sys::MaaSize = 0;
268 let mut roi = sys::MaaRect {
269 x: 0,
270 y: 0,
271 width: 0,
272 height: 0,
273 };
274
275 let ret = unsafe {
276 sys::MaaTaskerGetWaitFreezesDetail(
277 handle,
278 wf_id,
279 name.raw(),
280 phase.raw(),
281 &mut success,
282 &mut elapsed_ms,
283 std::ptr::null_mut(),
284 &mut reco_id_list_size,
285 &mut roi,
286 )
287 };
288
289 if ret == 0 {
290 return Ok(None);
291 }
292
293 let mut reco_id_list = vec![0; reco_id_list_size as usize];
294 let reco_id_list_ptr = if reco_id_list.is_empty() {
295 std::ptr::null_mut()
296 } else {
297 reco_id_list.as_mut_ptr()
298 };
299
300 let ret = unsafe {
301 sys::MaaTaskerGetWaitFreezesDetail(
302 handle,
303 wf_id,
304 name.raw(),
305 phase.raw(),
306 &mut success,
307 &mut elapsed_ms,
308 reco_id_list_ptr,
309 &mut reco_id_list_size,
310 &mut roi,
311 )
312 };
313
314 if ret == 0 {
315 return Ok(None);
316 }
317
318 reco_id_list.truncate(reco_id_list_size as usize);
319
320 Ok(Some(crate::common::WaitFreezesDetail {
321 wf_id,
322 name: name.as_str().to_string(),
323 phase: phase.as_str().to_string(),
324 success: success != 0,
325 elapsed_ms,
326 reco_id_list,
327 roi: crate::common::Rect::from(roi),
328 }))
329 }
330
331 pub(crate) fn fetch_node_detail(
332 handle: *mut sys::MaaTasker,
333 node_id: crate::common::MaaId,
334 ) -> MaaResult<Option<crate::common::NodeDetail>> {
335 let node_name = crate::buffer::MaaStringBuffer::new()?;
336 let mut reco_id = 0;
337 let mut act_id = 0;
338 let mut completed = 0;
339
340 let ret = unsafe {
341 sys::MaaTaskerGetNodeDetail(
342 handle,
343 node_id,
344 node_name.raw(),
345 &mut reco_id,
346 &mut act_id,
347 &mut completed,
348 )
349 };
350
351 if ret == 0 {
352 return Ok(None);
353 }
354
355 let recognition = if reco_id > 0 {
359 Self::fetch_recognition_detail(handle, reco_id)?
360 } else {
361 None
362 };
363
364 let action = if act_id > 0 {
365 Self::fetch_action_detail(handle, act_id)?
366 } else {
367 None
368 };
369
370 Ok(Some(crate::common::NodeDetail {
371 node_name: node_name.as_str().to_string(),
372 reco_id,
373 act_id,
374 completed: completed != 0,
375 recognition,
376 action,
377 }))
378 }
379
380 pub(crate) fn fetch_task_detail(
381 handle: *mut sys::MaaTasker,
382 task_id: crate::common::MaaId,
383 ) -> MaaResult<Option<crate::common::TaskDetail>> {
384 let entry = crate::buffer::MaaStringBuffer::new()?;
385 let mut node_id_list_size: sys::MaaSize = 0;
386 let mut status: sys::MaaStatus = 0;
387
388 let ret = unsafe {
389 sys::MaaTaskerGetTaskDetail(
390 handle,
391 task_id,
392 entry.raw(),
393 std::ptr::null_mut(),
394 &mut node_id_list_size,
395 &mut status,
396 )
397 };
398
399 if ret == 0 {
400 return Ok(None);
401 }
402
403 let mut node_id_list = vec![0; node_id_list_size as usize];
404 let ret = unsafe {
405 sys::MaaTaskerGetTaskDetail(
406 handle,
407 task_id,
408 entry.raw(),
409 node_id_list.as_mut_ptr(),
410 &mut node_id_list_size,
411 &mut status,
412 )
413 };
414
415 if ret == 0 {
416 return Ok(None);
417 }
418
419 let mut nodes = Vec::with_capacity(node_id_list.len());
421 for &nid in &node_id_list {
422 nodes.push(Self::fetch_node_detail(handle, nid)?);
423 }
424
425 Ok(Some(crate::common::TaskDetail {
426 entry: entry.as_str().to_string(),
427 node_id_list,
428 status: crate::common::MaaStatus(status as i32),
429 nodes,
430 }))
431 }
432
433 pub fn post_task(
442 &self,
443 entry: &str,
444 pipeline_override: &str,
445 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::TaskDetail>> {
446 let c_entry = std::ffi::CString::new(entry)?;
447 let c_pipeline = std::ffi::CString::new(pipeline_override)?;
448 let id = unsafe {
449 sys::MaaTaskerPostTask(
450 self.inner.handle.as_ptr(),
451 c_entry.as_ptr(),
452 c_pipeline.as_ptr(),
453 )
454 };
455
456 let inner = self.inner.clone();
457 let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
458 crate::common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
459 });
460
461 let inner = self.inner.clone();
462 let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
463 crate::common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
464 });
465
466 let inner = self.inner.clone();
467 let get_fn =
468 move |task_id: crate::common::MaaId| -> MaaResult<Option<crate::common::TaskDetail>> {
469 Tasker::fetch_task_detail(inner.handle.as_ptr(), task_id)
470 };
471
472 let inner = self.inner.clone();
474 let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
475 let c_pipeline = std::ffi::CString::new(pipeline)?;
476 let ret = unsafe {
477 sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
478 };
479 Ok(ret != 0)
480 });
481
482 Ok(crate::job::TaskJob::new(
483 crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
484 override_fn,
485 ))
486 }
487
488 pub fn post_task_json(
500 &self,
501 entry: &str,
502 pipeline_override: &serde_json::Value,
503 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::TaskDetail>> {
504 self.post_task(entry, &pipeline_override.to_string())
505 }
506
507 pub fn inited(&self) -> bool {
509 unsafe { sys::MaaTaskerInited(self.inner.handle.as_ptr()) != 0 }
510 }
511
512 #[inline]
514 pub fn raw(&self) -> *mut sys::MaaTasker {
515 self.inner.handle.as_ptr()
516 }
517
518 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
529 where
530 F: Fn(&str, &str) + Send + Sync + 'static,
531 {
532 let (cb, arg) = crate::callback::EventCallback::new(callback);
533 let id = unsafe { sys::MaaTaskerAddSink(self.inner.handle.as_ptr(), cb, arg) };
534 if id > 0 {
535 self.inner
536 .callbacks
537 .lock()
538 .unwrap()
539 .insert(id, arg as usize);
540 Ok(id)
541 } else {
542 unsafe { crate::callback::EventCallback::drop_callback(arg) };
543 Err(MaaError::FrameworkError(0))
544 }
545 }
546
547 pub fn add_event_sink(
559 &self,
560 sink: Box<dyn crate::event_sink::EventSink>,
561 ) -> MaaResult<sys::MaaSinkId> {
562 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
563 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
564 let id = unsafe { sys::MaaTaskerAddSink(self.inner.handle.as_ptr(), cb, arg) };
565 if id > 0 {
566 self.inner
567 .event_sinks
568 .lock()
569 .unwrap()
570 .insert(id, arg as usize);
571 Ok(id)
572 } else {
573 unsafe { crate::callback::EventCallback::drop_sink(arg) };
574 Err(MaaError::FrameworkError(0))
575 }
576 }
577
578 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
583 unsafe { sys::MaaTaskerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
584 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
585 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
586 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
587 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
588 }
589 }
590
591 pub fn clear_sinks(&self) {
593 unsafe { sys::MaaTaskerClearSinks(self.inner.handle.as_ptr()) };
594 let mut callbacks = self.inner.callbacks.lock().unwrap();
595 for (_, ptr) in callbacks.drain() {
596 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
597 }
598 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
599 for (_, ptr) in event_sinks.drain() {
600 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
601 }
602 }
603
604 #[deprecated(since = "0.5.1", note = "Use add_sink() instead")]
605 pub fn register_callback<F>(&self, callback: F) -> MaaResult<crate::common::MaaId>
606 where
607 F: Fn(&str, &str) + Send + Sync + 'static,
608 {
609 self.add_sink(callback)
610 }
611
612 pub fn post_stop(&self) -> MaaResult<crate::common::MaaId> {
614 unsafe {
615 let id = sys::MaaTaskerPostStop(self.inner.handle.as_ptr());
616 Ok(id)
617 }
618 }
619
620 pub fn is_running(&self) -> bool {
622 unsafe { sys::MaaTaskerRunning(self.inner.handle.as_ptr()) != 0 }
623 }
624
625 pub fn running(&self) -> bool {
627 self.is_running()
628 }
629
630 pub fn stopping(&self) -> bool {
632 unsafe { sys::MaaTaskerStopping(self.inner.handle.as_ptr()) != 0 }
633 }
634
635 pub fn add_context_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
640 where
641 F: Fn(&str, &str) + Send + Sync + 'static,
642 {
643 let (cb, arg) = crate::callback::EventCallback::new(callback);
644 let id = unsafe { sys::MaaTaskerAddContextSink(self.inner.handle.as_ptr(), cb, arg) };
645 if id > 0 {
646 self.inner
647 .callbacks
648 .lock()
649 .unwrap()
650 .insert(id, arg as usize);
651 Ok(id)
652 } else {
653 unsafe { crate::callback::EventCallback::drop_callback(arg) };
654 Err(MaaError::FrameworkError(0))
655 }
656 }
657
658 pub fn add_context_event_sink(
668 &self,
669 sink: Box<dyn crate::event_sink::EventSink>,
670 ) -> MaaResult<sys::MaaSinkId> {
671 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
672 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
673 let id = unsafe { sys::MaaTaskerAddContextSink(self.inner.handle.as_ptr(), cb, arg) };
674 if id > 0 {
675 self.inner
676 .event_sinks
677 .lock()
678 .unwrap()
679 .insert(id, arg as usize);
680 Ok(id)
681 } else {
682 unsafe { crate::callback::EventCallback::drop_sink(arg) };
683 Err(MaaError::FrameworkError(0))
684 }
685 }
686
687 pub fn remove_context_sink(&self, sink_id: sys::MaaSinkId) {
689 unsafe { sys::MaaTaskerRemoveContextSink(self.inner.handle.as_ptr(), sink_id) };
690 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
691 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
692 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
693 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
694 }
695 }
696
697 pub fn clear_context_sinks(&self) {
699 unsafe { sys::MaaTaskerClearContextSinks(self.inner.handle.as_ptr()) };
700 }
702
703 pub fn clear_cache(&self) -> MaaResult<()> {
705 let ret = unsafe { sys::MaaTaskerClearCache(self.inner.handle.as_ptr()) };
706 crate::common::check_bool(ret)
707 }
708
709 pub fn override_pipeline(
715 &self,
716 task_id: crate::common::MaaId,
717 pipeline_override: &str,
718 ) -> MaaResult<bool> {
719 let c_pipeline = std::ffi::CString::new(pipeline_override)?;
720 let ret = unsafe {
721 sys::MaaTaskerOverridePipeline(self.inner.handle.as_ptr(), task_id, c_pipeline.as_ptr())
722 };
723 Ok(ret != 0)
724 }
725
726 pub fn get_latest_node(&self, node_name: &str) -> MaaResult<Option<crate::common::MaaId>> {
728 let c_name = std::ffi::CString::new(node_name)?;
729 let mut node_id: crate::common::MaaId = 0;
730 let ret = unsafe {
731 sys::MaaTaskerGetLatestNode(self.inner.handle.as_ptr(), c_name.as_ptr(), &mut node_id)
732 };
733 if ret != 0 && node_id != 0 {
734 Ok(Some(node_id))
735 } else {
736 Ok(None)
737 }
738 }
739
740 pub fn bind(
742 &self,
743 resource: &Resource,
744 controller: &crate::controller::Controller,
745 ) -> MaaResult<()> {
746 self.bind_resource(resource)?;
747 self.bind_controller(controller)
748 }
749
750 pub fn resource(&self) -> Option<crate::resource::ResourceRef<'_>> {
761 let ptr = unsafe { sys::MaaTaskerGetResource(self.inner.handle.as_ptr()) };
762 crate::resource::ResourceRef::from_ptr(ptr)
763 }
764
765 pub fn controller(&self) -> Option<crate::controller::ControllerRef<'_>> {
776 let ptr = unsafe { sys::MaaTaskerGetController(self.inner.handle.as_ptr()) };
777 crate::controller::ControllerRef::from_ptr(ptr)
778 }
779
780 pub fn resource_handle(&self) -> *mut sys::MaaResource {
784 unsafe { sys::MaaTaskerGetResource(self.inner.handle.as_ptr()) }
785 }
786
787 pub fn controller_handle(&self) -> *mut sys::MaaController {
791 unsafe { sys::MaaTaskerGetController(self.inner.handle.as_ptr()) }
792 }
793
794 pub fn post_recognition(
801 &self,
802 reco_type: &str,
803 reco_param: &str,
804 image: &crate::buffer::MaaImageBuffer,
805 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::RecognitionDetail>> {
806 let c_type = std::ffi::CString::new(reco_type)?;
807 let c_param = std::ffi::CString::new(reco_param)?;
808 let id = unsafe {
809 sys::MaaTaskerPostRecognition(
810 self.inner.handle.as_ptr(),
811 c_type.as_ptr(),
812 c_param.as_ptr(),
813 image.raw(),
814 )
815 };
816
817 let inner = self.inner.clone();
818 let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
819 common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
820 });
821
822 let inner = self.inner.clone();
823 let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
824 common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
825 });
826
827 let inner = self.inner.clone();
828 let get_fn = move |reco_id: common::MaaId| -> MaaResult<Option<common::RecognitionDetail>> {
829 Tasker::fetch_recognition_detail(inner.handle.as_ptr(), reco_id)
830 };
831
832 let inner = self.inner.clone();
834 let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
835 let c_pipeline = std::ffi::CString::new(pipeline)?;
836 let ret = unsafe {
837 sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
838 };
839 Ok(ret != 0)
840 });
841
842 Ok(crate::job::TaskJob::new(
843 crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
844 override_fn,
845 ))
846 }
847
848 pub fn post_action(
856 &self,
857 action_type: &str,
858 action_param: &str,
859 box_rect: &common::Rect,
860 reco_detail: &str,
861 ) -> MaaResult<crate::job::TaskJob<'static, crate::common::ActionDetail>> {
862 let c_type = std::ffi::CString::new(action_type)?;
863 let c_param = std::ffi::CString::new(action_param)?;
864 let c_detail = std::ffi::CString::new(reco_detail)?;
865 let maa_rect = sys::MaaRect {
866 x: box_rect.x,
867 y: box_rect.y,
868 width: box_rect.width,
869 height: box_rect.height,
870 };
871
872 let id = unsafe {
873 sys::MaaTaskerPostAction(
874 self.inner.handle.as_ptr(),
875 c_type.as_ptr(),
876 c_param.as_ptr(),
877 &maa_rect,
878 c_detail.as_ptr(),
879 )
880 };
881
882 let inner = self.inner.clone();
883 let status_fn: crate::job::StatusFn = Box::new(move |job_id| {
884 common::MaaStatus(unsafe { sys::MaaTaskerStatus(inner.handle.as_ptr(), job_id) })
885 });
886
887 let inner = self.inner.clone();
888 let wait_fn: crate::job::WaitFn = Box::new(move |job_id| {
889 common::MaaStatus(unsafe { sys::MaaTaskerWait(inner.handle.as_ptr(), job_id) })
890 });
891
892 let inner = self.inner.clone();
893 let get_fn = move |act_id: common::MaaId| -> MaaResult<Option<common::ActionDetail>> {
894 Tasker::fetch_action_detail(inner.handle.as_ptr(), act_id)
895 };
896
897 let inner = self.inner.clone();
899 let override_fn: crate::job::OverridePipelineFn = Box::new(move |job_id, pipeline| {
900 let c_pipeline = std::ffi::CString::new(pipeline)?;
901 let ret = unsafe {
902 sys::MaaTaskerOverridePipeline(inner.handle.as_ptr(), job_id, c_pipeline.as_ptr())
903 };
904 Ok(ret != 0)
905 });
906
907 Ok(crate::job::TaskJob::new(
908 crate::job::JobWithResult::new(id, status_fn, wait_fn, get_fn),
909 override_fn,
910 ))
911 }
912
913 pub fn set_log_dir<P: AsRef<std::path::Path>>(path: P) -> MaaResult<()> {
917 let path_str = path.as_ref().to_string_lossy();
918 let c_path = std::ffi::CString::new(path_str.as_ref())?;
919 let ret = unsafe {
920 sys::MaaGlobalSetOption(
921 sys::MaaGlobalOptionEnum_MaaGlobalOption_LogDir as i32,
922 c_path.as_ptr() as *mut _,
923 c_path.as_bytes().len() as u64,
924 )
925 };
926 common::check_bool(ret)
927 }
928
929 pub fn set_save_draw(save: bool) -> MaaResult<()> {
931 let val = if save { 1 } else { 0 };
932 let ret = unsafe {
933 sys::MaaGlobalSetOption(
934 sys::MaaGlobalOptionEnum_MaaGlobalOption_SaveDraw as i32,
935 &val as *const _ as *mut _,
936 std::mem::size_of_val(&val) as u64,
937 )
938 };
939 common::check_bool(ret)
940 }
941
942 pub fn set_stdout_level(level: sys::MaaLoggingLevel) -> MaaResult<()> {
944 let ret = unsafe {
945 sys::MaaGlobalSetOption(
946 sys::MaaGlobalOptionEnum_MaaGlobalOption_StdoutLevel as i32,
947 &level as *const _ as *mut _,
948 std::mem::size_of_val(&level) as u64,
949 )
950 };
951 common::check_bool(ret)
952 }
953
954 pub fn set_debug_mode(debug: bool) -> MaaResult<()> {
956 let val = if debug { 1 } else { 0 };
957 let ret = unsafe {
958 sys::MaaGlobalSetOption(
959 sys::MaaGlobalOptionEnum_MaaGlobalOption_DebugMode as i32,
960 &val as *const _ as *mut _,
961 std::mem::size_of_val(&val) as u64,
962 )
963 };
964 common::check_bool(ret)
965 }
966
967 pub fn set_save_on_error(save: bool) -> MaaResult<()> {
969 let val = if save { 1 } else { 0 };
970 let ret = unsafe {
971 sys::MaaGlobalSetOption(
972 sys::MaaGlobalOptionEnum_MaaGlobalOption_SaveOnError as i32,
973 &val as *const _ as *mut _,
974 std::mem::size_of_val(&val) as u64,
975 )
976 };
977 common::check_bool(ret)
978 }
979
980 pub fn set_draw_quality(quality: i32) -> MaaResult<()> {
982 let ret = unsafe {
983 sys::MaaGlobalSetOption(
984 sys::MaaGlobalOptionEnum_MaaGlobalOption_DrawQuality as i32,
985 &quality as *const _ as *mut _,
986 std::mem::size_of_val(&quality) as u64,
987 )
988 };
989 common::check_bool(ret)
990 }
991
992 pub fn set_reco_image_cache_limit(limit: usize) -> MaaResult<()> {
994 let ret = unsafe {
995 sys::MaaGlobalSetOption(
996 sys::MaaGlobalOptionEnum_MaaGlobalOption_RecoImageCacheLimit as i32,
997 &limit as *const _ as *mut _,
998 std::mem::size_of_val(&limit) as u64,
999 )
1000 };
1001 common::check_bool(ret)
1002 }
1003
1004 pub fn load_plugin<P: AsRef<std::path::Path>>(path: P) -> MaaResult<()> {
1006 let path_str = path.as_ref().to_string_lossy();
1007 let c_path = std::ffi::CString::new(path_str.as_ref())?;
1008 let ret = unsafe { sys::MaaGlobalLoadPlugin(c_path.as_ptr()) };
1009 common::check_bool(ret)
1010 }
1011}
1012
1013impl Drop for TaskerInner {
1014 fn drop(&mut self) {
1015 unsafe {
1016 if self.owns_handle {
1017 sys::MaaTaskerClearSinks(self.handle.as_ptr());
1018 } else {
1019 let callbacks_keys: Vec<_> =
1020 self.callbacks.lock().unwrap().keys().copied().collect();
1021 for id in callbacks_keys {
1022 sys::MaaTaskerRemoveSink(self.handle.as_ptr(), id);
1023 }
1024 let event_sinks_keys: Vec<_> =
1025 self.event_sinks.lock().unwrap().keys().copied().collect();
1026 for id in event_sinks_keys {
1027 sys::MaaTaskerRemoveSink(self.handle.as_ptr(), id);
1028 }
1029 }
1030
1031 let mut callbacks = self.callbacks.lock().unwrap();
1032 for (_, ptr) in callbacks.drain() {
1033 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
1034 }
1035 let mut event_sinks = self.event_sinks.lock().unwrap();
1036 for (_, ptr) in event_sinks.drain() {
1037 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
1038 }
1039
1040 if self.owns_handle {
1041 sys::MaaTaskerDestroy(self.handle.as_ptr());
1042 }
1043 }
1044 }
1045}