Skip to main content

maa_framework/
agent_server.rs

1//! Agent server for hosting custom components.
2//!
3//! This module allows hosting custom recognition and action components
4//! in a separate process, which can be connected to by AgentClient.
5
6use crate::{MaaError, MaaResult, callback, common, sys};
7use std::ffi::CString;
8
9/// Static functions for AgentServer management.
10///
11/// AgentServer hosts custom recognitions and actions that can be
12/// accessed remotely by AgentClient instances.
13pub struct AgentServer;
14
15impl AgentServer {
16    #[inline]
17    fn mark_context() {
18        crate::mark_agent_server_context();
19    }
20
21    /// Register a custom recognition with the AgentServer.
22    ///
23    /// The recognition will be available to connected AgentClients.
24    pub fn register_custom_recognition(
25        name: &str,
26        reco: Box<dyn crate::custom::CustomRecognition>,
27    ) -> MaaResult<()> {
28        Self::mark_context();
29        let c_name = CString::new(name)?;
30        let reco_ptr = Box::into_raw(Box::new(reco));
31        let reco_ptr_void = reco_ptr as *mut std::ffi::c_void;
32
33        unsafe {
34            let ret = sys::MaaAgentServerRegisterCustomRecognition(
35                c_name.as_ptr(),
36                Some(crate::custom::custom_recognition_trampoline),
37                reco_ptr_void,
38            );
39            if ret == 0 {
40                let _ = Box::from_raw(reco_ptr);
41                return Err(MaaError::FrameworkError(0));
42            }
43        }
44
45        Ok(())
46    }
47
48    /// Register a custom action with the AgentServer.
49    ///
50    /// The action will be available to connected AgentClients.
51    pub fn register_custom_action(
52        name: &str,
53        action: Box<dyn crate::custom::CustomAction>,
54    ) -> MaaResult<()> {
55        Self::mark_context();
56        let c_name = CString::new(name)?;
57        let action_ptr = Box::into_raw(Box::new(action));
58        let action_ptr_void = action_ptr as *mut std::ffi::c_void;
59
60        unsafe {
61            let ret = sys::MaaAgentServerRegisterCustomAction(
62                c_name.as_ptr(),
63                Some(crate::custom::custom_action_trampoline),
64                action_ptr_void,
65            );
66            if ret == 0 {
67                let _ = Box::from_raw(action_ptr);
68                return Err(MaaError::FrameworkError(0));
69            }
70        }
71        Ok(())
72    }
73
74    /// Add a resource event sink.
75    pub fn add_resource_sink<F>(callback: F) -> MaaResult<sys::MaaSinkId>
76    where
77        F: Fn(&str, &str) + Send + Sync + 'static,
78    {
79        Self::mark_context();
80        let (cb, arg) = callback::EventCallback::new(callback);
81        let sink_id = unsafe { sys::MaaAgentServerAddResourceSink(cb, arg) };
82        if sink_id != 0 {
83            Ok(sink_id)
84        } else {
85            unsafe { callback::EventCallback::drop_callback(arg) };
86            Err(MaaError::FrameworkError(0))
87        }
88    }
89
90    /// Add a controller event sink.
91    pub fn add_controller_sink<F>(callback: F) -> MaaResult<sys::MaaSinkId>
92    where
93        F: Fn(&str, &str) + Send + Sync + 'static,
94    {
95        Self::mark_context();
96        let (cb, arg) = callback::EventCallback::new(callback);
97        let sink_id = unsafe { sys::MaaAgentServerAddControllerSink(cb, arg) };
98        if sink_id != 0 {
99            Ok(sink_id)
100        } else {
101            unsafe { callback::EventCallback::drop_callback(arg) };
102            Err(MaaError::FrameworkError(0))
103        }
104    }
105
106    /// Add a tasker event sink.
107    pub fn add_tasker_sink<F>(callback: F) -> MaaResult<sys::MaaSinkId>
108    where
109        F: Fn(&str, &str) + Send + Sync + 'static,
110    {
111        Self::mark_context();
112        let (cb, arg) = callback::EventCallback::new(callback);
113        let sink_id = unsafe { sys::MaaAgentServerAddTaskerSink(cb, arg) };
114        if sink_id != 0 {
115            Ok(sink_id)
116        } else {
117            unsafe { callback::EventCallback::drop_callback(arg) };
118            Err(MaaError::FrameworkError(0))
119        }
120    }
121
122    /// Add a context event sink.
123    pub fn add_context_sink<F>(callback: F) -> MaaResult<sys::MaaSinkId>
124    where
125        F: Fn(&str, &str) + Send + Sync + 'static,
126    {
127        Self::mark_context();
128        let (cb, arg) = callback::EventCallback::new(callback);
129        let sink_id = unsafe { sys::MaaAgentServerAddContextSink(cb, arg) };
130        if sink_id != 0 {
131            Ok(sink_id)
132        } else {
133            unsafe { callback::EventCallback::drop_callback(arg) };
134            Err(MaaError::FrameworkError(0))
135        }
136    }
137
138    /// Start the AgentServer.
139    ///
140    /// # Arguments
141    /// * `identifier` - Connection identifier for clients to connect to
142    pub fn start_up(identifier: &str) -> MaaResult<()> {
143        Self::mark_context();
144        let c_id = CString::new(identifier)?;
145        let ret = unsafe { sys::MaaAgentServerStartUp(c_id.as_ptr()) };
146        common::check_bool(ret)
147    }
148
149    /// Shut down the AgentServer.
150    pub fn shut_down() {
151        Self::mark_context();
152        unsafe { sys::MaaAgentServerShutDown() }
153    }
154
155    /// Block until the server shuts down.
156    pub fn join() {
157        Self::mark_context();
158        unsafe { sys::MaaAgentServerJoin() }
159    }
160
161    /// Detach the server to run in background.
162    pub fn detach() {
163        Self::mark_context();
164        unsafe { sys::MaaAgentServerDetach() }
165    }
166}