MaaFw 2.1.0__py3-none-manylinux2014_x86_64.whl → 5.4.0b1__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
maa/event_sink.py ADDED
@@ -0,0 +1,103 @@
1
+ import ctypes
2
+ import json
3
+ from abc import ABC
4
+ from typing import Tuple
5
+ from enum import IntEnum
6
+
7
+ from .define import MaaEventCallback
8
+
9
+
10
+ # class NotificationEvent(IntEnum):
11
+ # ResourceLoading = 1
12
+ # ControllerAction = 2
13
+ # TaskerTask = 3
14
+ # TaskNextList = 4
15
+ # TaskRecognition = 5
16
+ # TaskAction = 6
17
+
18
+
19
+ class NotificationType(IntEnum):
20
+ """通知类型枚举 / Notification type enumeration
21
+
22
+ 用于标识事件回调的状态类型。
23
+ Used to identify the status type of event callbacks.
24
+
25
+ Attributes:
26
+ Unknown: 未知类型 / Unknown type
27
+ Starting: 开始 / Starting
28
+ Succeeded: 成功 / Succeeded
29
+ Failed: 失败 / Failed
30
+ """
31
+
32
+ Unknown = 0
33
+ Starting = 1
34
+ Succeeded = 2
35
+ Failed = 3
36
+
37
+
38
+ class EventSink(ABC):
39
+ """事件监听器基类 / Event sink base class
40
+
41
+ 用于接收 MaaFramework 各种事件回调的抽象基类。
42
+ 派生类包括 ResourceEventSink、ControllerEventSink、TaskerEventSink、ContextEventSink。
43
+ Abstract base class for receiving various event callbacks from MaaFramework.
44
+ Derived classes include ResourceEventSink, ControllerEventSink, TaskerEventSink, ContextEventSink.
45
+ """
46
+
47
+ def on_unknown_notification(self, instance, msg: str, details: dict):
48
+ """处理未知类型的通知 / Handle unknown notification
49
+
50
+ 当收到无法识别的通知时调用。
51
+ Called when an unrecognized notification is received.
52
+
53
+ Args:
54
+ instance: 相关实例对象 / Related instance object
55
+ msg: 消息类型 / Message type
56
+ details: 消息详情 / Message details
57
+ """
58
+ pass
59
+
60
+ def _on_raw_notification(self, handle: ctypes.c_void_p, msg: str, details: dict):
61
+ pass
62
+
63
+ @property
64
+ def c_callback(self) -> MaaEventCallback:
65
+ return self._c_sink_agent
66
+
67
+ @property
68
+ def c_callback_arg(self) -> ctypes.c_void_p:
69
+ return ctypes.c_void_p.from_buffer(ctypes.py_object(self))
70
+
71
+ @staticmethod
72
+ def _gen_c_param(
73
+ sink: "EventSink",
74
+ ) -> Tuple[MaaEventCallback, ctypes.c_void_p]:
75
+ return sink.c_callback, sink.c_callback_arg
76
+
77
+ @staticmethod
78
+ def _notification_type(message: str) -> NotificationType:
79
+ if message.endswith(".Starting"):
80
+ return NotificationType.Starting
81
+ elif message.endswith(".Succeeded"):
82
+ return NotificationType.Succeeded
83
+ elif message.endswith(".Failed"):
84
+ return NotificationType.Failed
85
+ else:
86
+ return NotificationType.Unknown
87
+
88
+ @staticmethod
89
+ @MaaEventCallback
90
+ def _c_sink_agent(
91
+ handle: ctypes.c_void_p,
92
+ msg: ctypes.c_char_p,
93
+ details_json: ctypes.c_char_p,
94
+ callback_arg: ctypes.c_void_p,
95
+ ):
96
+ if not callback_arg:
97
+ return
98
+
99
+ self: EventSink = ctypes.cast(callback_arg, ctypes.py_object).value
100
+
101
+ self._on_raw_notification(
102
+ handle, msg.decode(), json.loads(details_json.decode())
103
+ )
maa/job.py CHANGED
@@ -1,72 +1,131 @@
1
- from typing import Union
2
-
3
1
  from .define import *
4
2
 
5
3
 
6
- class Status:
7
- _status: MaaStatusEnum
8
-
9
- def __init__(self, status: Union[MaaStatus, MaaStatusEnum]):
10
- self._status = MaaStatusEnum(status)
11
-
12
- def done(self) -> bool:
13
- return self._status in [MaaStatusEnum.succeeded, MaaStatusEnum.failed]
14
-
15
- def succeeded(self) -> bool:
16
- return self._status == MaaStatusEnum.succeeded
17
-
18
- def failed(self) -> bool:
19
- return self._status == MaaStatusEnum.failed
20
-
21
- def pending(self) -> bool:
22
- return self._status == MaaStatusEnum.pending
23
-
24
- def running(self) -> bool:
25
- return self._status == MaaStatusEnum.running
4
+ class Job:
5
+ """异步作业句柄 / Asynchronous job handle
26
6
 
7
+ 用于跟踪和管理异步操作的状态,如资源加载、控制器连接等。
8
+ Used to track and manage the status of asynchronous operations
9
+ such as resource loading, controller connection, etc.
10
+ """
27
11
 
28
- class Job:
29
- job_id: MaaId
12
+ _job_id: MaaId
30
13
 
31
14
  def __init__(self, job_id: MaaId, status_func, wait_func):
32
- self.job_id = job_id
15
+ self._job_id = job_id
33
16
  self._status_func = status_func
34
17
  self._wait_func = wait_func
35
18
 
36
- def get_id(self) -> int:
37
- return int(self.job_id)
19
+ @property
20
+ def job_id(self) -> int:
21
+ """获取作业 ID / Get job ID
22
+
23
+ Returns:
24
+ int: 作业 ID / Job ID
25
+ """
26
+ return int(self._job_id)
38
27
 
39
28
  def wait(self) -> "Job":
40
- self._wait_func(self.job_id)
29
+ """等待作业完成 / Wait for job completion
30
+
31
+ 阻塞当前线程直到作业完成
32
+ Blocks the current thread until the job is done
33
+
34
+ Returns:
35
+ Job: 返回自身,支持链式调用 / Returns self for method chaining
36
+ """
37
+ self._wait_func(self._job_id)
41
38
  return self
42
39
 
40
+ @property
43
41
  def status(self) -> Status:
44
- return Status(self._status_func(self.job_id))
42
+ """获取作业状态 / Get job status
45
43
 
44
+ Returns:
45
+ Status: 作业状态 / Job status
46
+ """
47
+ return Status(self._status_func(self._job_id))
48
+
49
+ @property
46
50
  def done(self) -> bool:
47
- return self.status().done()
51
+ """判断作业是否已完成 / Check if job is done
52
+
53
+ Returns:
54
+ bool: 是否已完成(成功或失败) / Whether done (succeeded or failed)
55
+ """
56
+ return self.status.done
48
57
 
58
+ @property
49
59
  def succeeded(self) -> bool:
50
- return self.status().succeeded()
60
+ """判断作业是否成功 / Check if job succeeded
51
61
 
62
+ Returns:
63
+ bool: 是否成功 / Whether succeeded
64
+ """
65
+ return self.status.succeeded
66
+
67
+ @property
52
68
  def failed(self) -> bool:
53
- return self.status().failed()
69
+ """判断作业是否失败 / Check if job failed
70
+
71
+ Returns:
72
+ bool: 是否失败 / Whether failed
73
+ """
74
+ return self.status.failed
54
75
 
76
+ @property
55
77
  def pending(self) -> bool:
56
- return self.status().pending()
78
+ """判断作业是否等待中 / Check if job is pending
57
79
 
80
+ Returns:
81
+ bool: 是否等待中 / Whether pending
82
+ """
83
+ return self.status.pending
84
+
85
+ @property
58
86
  def running(self) -> bool:
59
- return self.status().running()
87
+ """判断作业是否运行中 / Check if job is running
88
+
89
+ Returns:
90
+ bool: 是否运行中 / Whether running
91
+ """
92
+ return self.status.running
60
93
 
61
94
 
62
95
  class JobWithResult(Job):
96
+ """带结果的异步作业句柄 / Asynchronous job handle with result
97
+
98
+ 继承自 Job,额外提供获取作业结果的功能。
99
+ Inherits from Job, additionally provides the ability to get job result.
100
+ """
101
+
63
102
  def __init__(self, job_id: MaaId, status_func, wait_func, get_func):
64
103
  super().__init__(job_id, status_func, wait_func)
65
104
  self._get_func = get_func
66
105
 
67
106
  def wait(self) -> "JobWithResult":
107
+ """等待作业完成 / Wait for job completion
108
+
109
+ Returns:
110
+ JobWithResult: 返回自身,支持链式调用 / Returns self for method chaining
111
+ """
68
112
  super().wait()
69
113
  return self
70
114
 
71
- def get(self):
72
- return self._get_func(self.job_id)
115
+ def get(self, wait: bool = False):
116
+ """获取作业结果 / Get job result
117
+
118
+ Args:
119
+ wait: 是否在获取结果前等待作业完成,默认为 False。建议先显式调用 wait()(或传入 wait=True),
120
+ 确保异步操作已完成后再获取结果 / Whether to wait for job completion before getting result,
121
+ default is False. It's recommended to call wait() first (or pass wait=True) to ensure the
122
+ async operation is finished before getting the result.
123
+
124
+ Returns:
125
+ 作业执行结果,类型取决于具体作业 / Job execution result, type depends on the specific job
126
+ """
127
+
128
+ if wait:
129
+ self.wait()
130
+
131
+ return self._get_func(self._job_id)
maa/library.py CHANGED
@@ -1,68 +1,197 @@
1
1
  import ctypes
2
- import ctypes.util
3
2
  import pathlib
4
3
  import platform
5
- from typing import Optional, Union
4
+ from typing import Optional
6
5
 
7
6
  from .define import *
8
7
 
9
8
 
10
9
  class Library:
10
+ """库加载管理器 / Library loading manager
11
11
 
12
- initialized = False
12
+ 管理 MaaFramework 各动态库的加载和访问。
13
+ Manages loading and access to MaaFramework dynamic libraries.
14
+ """
13
15
 
14
- @staticmethod
15
- def open(path: Union[pathlib.Path, str]) -> Optional[str]:
16
- platform_values = {
17
- "windows": ("MaaFramework.dll", "MaaToolkit.dll"),
18
- "darwin": ("libMaaFramework.dylib", "libMaaToolkit.dylib"),
19
- "linux": ("libMaaFramework.so", "libMaaToolkit.so"),
16
+ _is_agent_server: bool = False
17
+
18
+ _framework: Optional[ctypes.CDLL] = None
19
+ _toolkit: Optional[ctypes.CDLL] = None
20
+ _agent_client: Optional[ctypes.CDLL] = None
21
+ _agent_server: Optional[ctypes.CDLL] = None
22
+ _lib_type = None
23
+
24
+ @classmethod
25
+ def open(cls, path: pathlib.Path, agent_server: bool = False):
26
+ """打开并加载库 / Open and load libraries
27
+
28
+ Args:
29
+ path: 库文件所在目录 / Directory containing library files
30
+ agent_server: 是否以 AgentServer 模式加载 / Whether to load in AgentServer mode
31
+
32
+ Raises:
33
+ FileNotFoundError: 如果路径不存在
34
+ """
35
+ if cls._api_properties_initialized:
36
+ return
37
+
38
+ if not path.exists():
39
+ raise FileNotFoundError(f"`{path}` does not exist.")
40
+
41
+ WINDOWS = "windows"
42
+ MACOS = "darwin"
43
+ LINUX = "linux"
44
+
45
+ cls._is_agent_server = agent_server
46
+
47
+ if not cls.is_agent_server():
48
+ framework_library = {
49
+ WINDOWS: "MaaFramework.dll",
50
+ MACOS: "libMaaFramework.dylib",
51
+ LINUX: "libMaaFramework.so",
52
+ }
53
+ agent_client_library = {
54
+ WINDOWS: "MaaAgentClient.dll",
55
+ MACOS: "libMaaAgentClient.dylib",
56
+ LINUX: "libMaaAgentClient.so",
57
+ }
58
+ else:
59
+ agent_server_library = {
60
+ WINDOWS: "MaaAgentServer.dll",
61
+ MACOS: "libMaaAgentServer.dylib",
62
+ LINUX: "libMaaAgentServer.so",
63
+ }
64
+
65
+ toolkit_library = {
66
+ WINDOWS: "MaaToolkit.dll",
67
+ MACOS: "libMaaToolkit.dylib",
68
+ LINUX: "libMaaToolkit.so",
20
69
  }
21
70
 
22
71
  platform_type = platform.system().lower()
23
72
 
24
- if platform_type == "windows":
25
- lib_import = ctypes.WinDLL
73
+ if platform_type == WINDOWS:
74
+ cls._lib_type = ctypes.WinDLL
26
75
  else:
27
- lib_import = ctypes.CDLL
28
-
29
- try:
30
- Library.framework_libpath = (
31
- pathlib.Path(path) / platform_values[platform_type][0]
32
- )
33
- Library.framework = lib_import(str(Library.framework_libpath))
34
- except OSError:
35
- Library.framework_libpath = ctypes.util.find_library("MaaFramework")
36
- Library.framework = lib_import(str(Library.framework_libpath))
37
-
38
- try:
39
- Library.toolkit_libpath = (
40
- pathlib.Path(path) / platform_values[platform_type][1]
41
- )
42
- Library.toolkit = lib_import(str(Library.toolkit_libpath))
43
- except OSError:
44
- Library.toolkit_libpath = ctypes.util.find_library("MaaToolkit")
45
- Library.toolkit = lib_import(str(Library.toolkit_libpath))
46
-
47
- if not Library.framework or not Library.toolkit:
48
- Library.initialized = False
49
- return None
50
-
51
- Library._set_api_properties()
52
- Library.initialized = True
53
-
54
- return Library.version()
55
-
56
- @staticmethod
57
- def version() -> str:
58
- if not Library.initialized:
59
- raise RuntimeError(
60
- "Library not initialized, please call `library.open()` first."
61
- )
62
-
63
- return Library.framework.MaaVersion().decode()
64
-
65
- @staticmethod
66
- def _set_api_properties():
67
- Library.framework.MaaVersion.restype = ctypes.c_char_p
68
- Library.framework.MaaVersion.argtypes = []
76
+ cls._lib_type = ctypes.CDLL
77
+
78
+ if cls._lib_type is None:
79
+ raise
80
+
81
+ if not cls.is_agent_server():
82
+ cls.framework_libpath = path / framework_library[platform_type]
83
+ cls.agent_client_libpath = path / agent_client_library[platform_type]
84
+ else:
85
+ cls.agent_server_libpath = path / agent_server_library[platform_type]
86
+
87
+ cls.toolkit_libpath = path / toolkit_library[platform_type]
88
+
89
+ @classmethod
90
+ def framework(cls) -> Union["ctypes.CDLL", "ctypes.WinDLL"]:
91
+ """获取 MaaFramework 库 / Get MaaFramework library
92
+
93
+ Returns:
94
+ (ctypes.CDLL | ctypes.WinDLL): MaaFramework 动态库对象 / MaaFramework dynamic library object
95
+ """
96
+ if cls._lib_type is None:
97
+ raise RuntimeError("Library._lib_type is None!")
98
+
99
+ if not cls.is_agent_server():
100
+ if not cls._framework:
101
+ cls._framework = cls._lib_type(str(cls.framework_libpath))
102
+
103
+ if cls._framework is None:
104
+ raise RuntimeError("Library._framework is None!")
105
+
106
+ return cls._framework
107
+ else:
108
+ return cls.agent_server()
109
+
110
+ @classmethod
111
+ def toolkit(cls) -> Union["ctypes.CDLL", "ctypes.WinDLL"]:
112
+ """获取 MaaToolkit 库 / Get MaaToolkit library
113
+
114
+ Returns:
115
+ (ctypes.CDLL | ctypes.WinDLL): MaaFramework 动态库对象 / MaaFramework dynamic library object
116
+ """
117
+ if cls._lib_type is None:
118
+ raise RuntimeError("Library._lib_type is None!")
119
+
120
+ if not cls._toolkit:
121
+ cls._toolkit = cls._lib_type(str(cls.toolkit_libpath))
122
+
123
+ return cls._toolkit
124
+
125
+ @classmethod
126
+ def agent_client(cls) -> Union["ctypes.CDLL", "ctypes.WinDLL"]:
127
+ """获取 MaaAgentClient 库 / Get MaaAgentClient library
128
+
129
+ Returns:
130
+ (ctypes.CDLL | ctypes.WinDLL): MaaFramework 动态库对象 / MaaFramework dynamic library object
131
+
132
+ Raises:
133
+ ValueError: 如果在 AgentServer 模式下调用
134
+ """
135
+ if cls._lib_type is None:
136
+ raise RuntimeError("Library._lib_type is None!")
137
+
138
+ if cls.is_agent_server():
139
+ raise ValueError("Agent server is not available in the current context.")
140
+
141
+ if not cls._agent_client:
142
+ cls._agent_client = cls._lib_type(str(cls.agent_client_libpath))
143
+
144
+ return cls._agent_client
145
+
146
+ @classmethod
147
+ def agent_server(cls) -> Union["ctypes.CDLL", "ctypes.WinDLL"]:
148
+ """获取 MaaAgentServer 库 / Get MaaAgentServer library
149
+
150
+ Returns:
151
+ (ctypes.CDLL | ctypes.WinDLL): MaaAgentServer 动态库对象 / MaaAgentServer dynamic library object
152
+
153
+ Raises:
154
+ ValueError: 如果不在 AgentServer 模式下调用
155
+ """
156
+ if cls._lib_type is None:
157
+ raise RuntimeError("Library._lib_type is None!")
158
+
159
+ if not cls.is_agent_server():
160
+ raise ValueError("Agent client is not available in the current context.")
161
+
162
+ if not cls._agent_server:
163
+ cls._agent_server = cls._lib_type(str(cls.agent_server_libpath))
164
+
165
+ return cls._agent_server
166
+
167
+ @classmethod
168
+ def is_agent_server(cls) -> bool:
169
+ """判断是否为 AgentServer 模式 / Check if in AgentServer mode
170
+
171
+ Returns:
172
+ bool: 是否为 AgentServer 模式 / Whether in AgentServer mode
173
+ """
174
+ return cls._is_agent_server
175
+
176
+ @classmethod
177
+ def version(cls) -> str:
178
+ """获取 MaaFramework 版本 / Get MaaFramework version
179
+
180
+ Returns:
181
+ str: 版本字符串 / Version string
182
+ """
183
+ cls._set_api_properties()
184
+
185
+ return cls.framework().MaaVersion().decode()
186
+
187
+ _api_properties_initialized: bool = False
188
+
189
+ @classmethod
190
+ def _set_api_properties(cls):
191
+ if cls._api_properties_initialized:
192
+ return
193
+
194
+ cls._api_properties_initialized = True
195
+
196
+ cls.framework().MaaVersion.restype = ctypes.c_char_p
197
+ cls.framework().MaaVersion.argtypes = []