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