pymud 0.19.4__py3-none-any.whl → 0.20.0__py3-none-any.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.
pymud/session.py CHANGED
@@ -1,10 +1,15 @@
1
- import asyncio, logging, re, math, os, pickle, datetime, importlib, importlib.util, sysconfig
1
+ import asyncio, logging, re, math, os, pickle, datetime, importlib, importlib.util, sysconfig, time
2
2
  from collections.abc import Iterable
3
3
  from collections import OrderedDict
4
-
5
- from .extras import SessionBuffer, DotDict, Plugin
4
+ import logging, queue
5
+ from logging import FileHandler
6
+ from logging.handlers import QueueHandler, QueueListener
7
+ from wcwidth import wcswidth, wcwidth
8
+ from .logger import Logger
9
+ from .extras import SessionBuffer, DotDict
6
10
  from .protocol import MudClientProtocol
7
- from .objects import Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
11
+ from .modules import ModuleInfo
12
+ from .objects import BaseObject, Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
8
13
  from .settings import Settings
9
14
 
10
15
 
@@ -25,13 +30,14 @@ class Session:
25
30
 
26
31
  """
27
32
  #_esc_regx = re.compile("\x1b\\[[^mz]+[mz]")
28
- _esc_regx = re.compile("\x1b\\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
33
+ _esc_regx = re.compile(r"\x1b\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
29
34
 
30
35
  _sys_commands = (
31
36
  "help",
32
37
  "exit",
33
38
  "close",
34
39
  "connect", # 连接到服务器
40
+ "disconnect", # 从服务器断开连接
35
41
 
36
42
  "info", # 输出蓝色info
37
43
  "warning", # 输出黄色warning
@@ -73,6 +79,8 @@ class Session:
73
79
  "py", # 直接执行python语句
74
80
 
75
81
  "all", # 所有会话执行
82
+
83
+ "log", # 记录处置
76
84
  )
77
85
 
78
86
  _commands_alias = {
@@ -83,6 +91,7 @@ class Session:
83
91
  "var" : "variable",
84
92
  "rep" : "repeat",
85
93
  "con" : "connect",
94
+ "dis" : "disconnect",
86
95
  "wa" : "wait",
87
96
  "mess": "message",
88
97
  "action": "trigger",
@@ -96,7 +105,8 @@ class Session:
96
105
  def __init__(self, app, name, host, port, encoding = None, after_connect = None, loop = None, **kwargs):
97
106
  self.pyversion = sysconfig.get_python_version()
98
107
  self.loop = loop or asyncio.get_running_loop()
99
- self.log = logging.getLogger("pymud.Session")
108
+ self.syslog = logging.getLogger("pymud.Session")
109
+
100
110
  self.application = app
101
111
  self.name = name
102
112
  self._transport = None
@@ -132,8 +142,13 @@ class Session:
132
142
  self._status_maker = None # 创建状态窗口的函数(属性)
133
143
  self.display_line = ""
134
144
 
145
+ self._activetime = time.time()
146
+
135
147
  self.initialize()
136
148
 
149
+ self._loggers = dict()
150
+ self.log = self.getLogger(name)
151
+
137
152
  self.host = host
138
153
  self.port = port
139
154
  self.encoding = encoding or self.encoding
@@ -159,7 +174,6 @@ class Session:
159
174
  self.warning(f"自动从{file}中加载变量失败,错误消息为: {e}")
160
175
 
161
176
 
162
-
163
177
  if self._auto_script:
164
178
  self.info(f"即将自动加载以下模块:{self._auto_script}")
165
179
  self.load_module(self._auto_script)
@@ -167,6 +181,10 @@ class Session:
167
181
  if Settings.client["auto_connect"]:
168
182
  self.open()
169
183
 
184
+ def __del__(self):
185
+ self.clean()
186
+ self.closeLoggers()
187
+
170
188
  def initialize(self):
171
189
  "初始化Session有关对象。 **无需脚本调用。**"
172
190
  self._line_buffer = bytearray()
@@ -239,11 +257,6 @@ class Session:
239
257
  if self.connected:
240
258
  self.write_eof()
241
259
 
242
- # 两次保存,删掉一次
243
- # # 断开时自动保存变量数据
244
- # if Settings.client["var_autosave"]:
245
- # self.handle_save()
246
-
247
260
  def onDisconnected(self, protocol):
248
261
  "当从服务器连接断开时执行的操作。包括保存变量(若设置)、打印断开时间、执行自定义事件(若设置)等。"
249
262
  # 断开时自动保存变量数据
@@ -281,6 +294,15 @@ class Session:
281
294
 
282
295
  return dura
283
296
 
297
+ @property
298
+ def idletime(self) -> float:
299
+ "只读属性,返回当前会话空闲时间(即最后一次向服务器写入数据到现在的时间),以秒为单位。当服务器未连接时,返回-1"
300
+ idle = -1
301
+ if self._protocol and self._protocol.connected:
302
+ idle = time.time() - self._activetime
303
+
304
+ return idle
305
+
284
306
  @property
285
307
  def status_maker(self):
286
308
  """
@@ -340,6 +362,42 @@ class Session:
340
362
  def event_disconnected(self, event):
341
363
  self._events["disconnected"] = event
342
364
 
365
+ def getLogger(self, name, mode = 'a', encoding = 'utf-8', encoding_errors = 'ignore', raw = False) -> Logger:
366
+ """
367
+ 根据指定名称和参数获取并返回一个记录器。若指定名称不存在,则创建一个该名称记录器。
368
+
369
+ :param name: 指定的记录器名称
370
+ :param mode: 记录器的模式,可接受值为 a, w, n。 具体请参见 Logger 对象中 mode 参数
371
+ :param encoding: 记录文件的编码格式
372
+ :param encoding_errors: 编码错误的处理方式
373
+ :param raw: 是否以带ANSI标记的原始格式进行记录
374
+
375
+ :return 指定名称的记录器 Logger 对象
376
+ """
377
+ if name not in self.application.loggers.keys():
378
+ logger = Logger(name, mode, encoding, encoding_errors, raw)
379
+ self._loggers[name] = logger
380
+ self.application.loggers[name] = logger
381
+
382
+ else:
383
+ if name not in self._loggers.keys():
384
+ self.warning(f"其它会话中已存在一个名为 {name} 的记录器,将直接返回该记录器")
385
+
386
+ logger = self.application.loggers[name]
387
+ logger.mode = mode
388
+ logger.raw = raw
389
+
390
+ return logger
391
+
392
+ def closeLoggers(self):
393
+ "移除本会话所有相关Logger"
394
+ for name in self._loggers.keys():
395
+ if isinstance(self._loggers[name], Logger):
396
+ self._loggers[name].enabled = False
397
+
398
+ if name in self.application.loggers.keys():
399
+ self.application.loggers.pop(name)
400
+
343
401
  @property
344
402
  def modules(self) -> OrderedDict:
345
403
  """
@@ -484,6 +542,7 @@ class Session:
484
542
  :param newline: 是否额外增加换行符
485
543
  """
486
544
  self.buffer.insert_text(data)
545
+ self.log.log(data)
487
546
 
488
547
  if len(data) > 0 and (data[-1] == "\n"):
489
548
  self._line_count += 1
@@ -491,6 +550,7 @@ class Session:
491
550
  if newline:
492
551
  self.buffer.insert_text(self.newline_cli)
493
552
  self._line_count += 1
553
+ self.log.log(self.newline_cli)
494
554
 
495
555
  def clear_half(self):
496
556
  """
@@ -520,7 +580,7 @@ class Session:
520
580
  if self.connected:
521
581
  self._transport.write_eof()
522
582
  self.state = "DISCONNECTED"
523
- self.log.info(f"服务器断开连接! {self._protocol.__repr__}")
583
+ self.syslog.info(f"服务器断开连接! {self._protocol.__repr__}")
524
584
 
525
585
  def feed_gmcp(self, name, value) -> None:
526
586
  """
@@ -703,22 +763,48 @@ class Session:
703
763
  if self.seperator in line:
704
764
  lines = line.split(self.seperator)
705
765
  for ln in lines:
766
+ if Settings.client["echo_input"]:
767
+ self.writetobuffer(f"\x1b[32m{ln}\x1b[0m", True)
768
+ else:
769
+ self.log.log(f"\x1b[32m{ln}\x1b[0m\n")
770
+
706
771
  cmd = ln + self.newline
707
772
  self.write(cmd.encode(self.encoding, Settings.server["encoding_errors"]))
708
773
 
709
- if Settings.client["echo_input"]:
710
- self.writetobuffer(f"\x1b[32m{cmd}\x1b[0m")
711
-
712
774
  else:
775
+ if Settings.client["echo_input"]:
776
+ self.writetobuffer(f"\x1b[32m{line}\x1b[0m", True)
777
+ else:
778
+ self.log.log(f"\x1b[32m{line}\x1b[0m\n")
779
+
713
780
  cmd = line + self.newline
714
781
  self.write(cmd.encode(self.encoding, Settings.server["encoding_errors"]))
715
782
 
716
- #if Settings.client["echo_input"]:
717
- if Settings.client["echo_input"] and (len(cmd) > len(self.newline)): # 修改2023-12-3, 向服务器发送空回车时,不回显
718
- self.writetobuffer(f"\x1b[32m{cmd}\x1b[0m")
783
+ self._activetime = time.time()
719
784
 
720
- def exec(self, cmd: str, name = None, *args, **kwargs):
785
+ async def waitfor(self, line: str, awaitable, wait_time = 0.05) -> None:
721
786
  """
787
+ 调用writline向服务器中写入一行后,等待到可等待对象再返回。
788
+
789
+ :param line: 使用writeline写入的行
790
+ :param awaitable: 等待的可等待对象
791
+ :param wait_time: 写入行前等待的延时,单位为s。默认0.05
792
+
793
+ 由于异步的消息循环机制,如果在写入命令之后再创建可等待对象,则有可能服务器响应在可等待对象的创建之前
794
+ 此时使用await就无法等待到可等待对象的响应,会导致任务出错。
795
+ 一种解决方式是先创建可等待对象,然后写入命令,然后再等待可等待对象,但这种情况下需要写入三行代码,书写麻烦
796
+ 因此该函数是用于简化此类使用时的写法。
797
+
798
+ 示例:
799
+ await session.waitfor('a_cmd', self.create_task(a_tri.triggered()))
800
+ done, pending = await session.waitfor('a_cmd', asyncio.wait([self.create_task(a_tri.triggered()), self.create_task(b_tri.triggered())], return_when = 'FIRST_COMPLETED'))
801
+ """
802
+ await asyncio.sleep(wait_time)
803
+ self.writeline(line)
804
+ return await awaitable
805
+
806
+ def exec(self, cmd: str, name = None, *args, **kwargs):
807
+ r"""
722
808
  在名称为name的会话中使用exec_command执行MUD命令。当不指定name时,在当前会话中执行。
723
809
 
724
810
  - exec 与 writeline 都会向服务器写入数据。其差异在于,exec执行的内容,会先经过Alias处理和Command处理,实际向远程发送内容与cmd可以不一致。
@@ -733,7 +819,7 @@ class Session:
733
819
  示例:
734
820
  .. code:: Python
735
821
 
736
- session.addAlias(SimpleAlias(self.session, "^cb\s(\S+)\s(\S+)", "#3 get %1 from jinnang;#wa 250;combine gem;#wa 250;pack gem", id = "ali_combine"))
822
+ session.addAlias(SimpleAlias(self.session, r"^cb\s(\S+)\s(\S+)", "#3 get %1 from jinnang;#wa 250;combine gem;#wa 250;pack gem", id = "ali_combine"))
737
823
  session.exec("cb j1a")
738
824
  """
739
825
  name = name or self.name
@@ -754,12 +840,10 @@ class Session:
754
840
  name = name or self.name
755
841
  if name in self.application.sessions.keys():
756
842
  session = self.application.sessions[name]
757
- await session.exec_command_async(cmd, *args, **kwargs)
843
+ return await session.exec_command_async(cmd, *args, **kwargs)
758
844
  else:
759
845
  self.error(f"不存在名称为{name}的会话")
760
846
 
761
-
762
-
763
847
  def exec_code(self, cl: CodeLine, *args, **kwargs):
764
848
  """
765
849
  执行解析为CodeLine形式的MUD命令(必定为单个命令)。一般情况下,脚本中不应调用该方法,而应使用exec/exec_command。
@@ -833,6 +917,7 @@ class Session:
833
917
  :param args: 保留兼容与扩展性所需
834
918
  :param kwargs: 保留兼容与扩展性所需
835
919
  """
920
+
836
921
  if cl.length == 0:
837
922
  self.writeline("")
838
923
 
@@ -860,9 +945,9 @@ class Session:
860
945
  else:
861
946
  try:
862
947
  cb = CodeBlock(sess_cmd)
863
- await cb.async_execute(session, *args, **kwargs)
948
+ return await cb.async_execute(session, *args, **kwargs)
864
949
  except Exception as e:
865
- await session.exec_command_async(sess_cmd)
950
+ return await session.exec_command_async(sess_cmd)
866
951
 
867
952
  else:
868
953
  if cmd in self._commands_alias.keys():
@@ -879,7 +964,7 @@ class Session:
879
964
 
880
965
  else:
881
966
  cmdtext, code = cl.expand(self, *args, **kwargs)
882
- await self.exec_text_async(cmdtext)
967
+ return await self.exec_text_async(cmdtext)
883
968
 
884
969
  def exec_text(self, cmdtext: str):
885
970
  """
@@ -919,14 +1004,14 @@ class Session:
919
1004
 
920
1005
  异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
921
1006
  """
922
-
1007
+ result = None
923
1008
  isNotCmd = True
924
1009
  for command in self._commands.values():
925
1010
  if isinstance(command, Command) and command.enabled:
926
1011
  state = command.match(cmdtext)
927
1012
  if state.result == Command.SUCCESS:
928
1013
  # 命令的任务名称采用命令id,以便于后续查错
929
- await self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
1014
+ result = await self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
930
1015
  isNotCmd = False
931
1016
  break
932
1017
 
@@ -944,6 +1029,8 @@ class Session:
944
1029
  if notAlias:
945
1030
  self.writeline(cmdtext)
946
1031
 
1032
+ return result
1033
+
947
1034
  def exec_command(self, line: str, *args, **kwargs) -> None:
948
1035
  """
949
1036
  在当前会话中执行MUD命令。多个命令可以用分隔符隔开。
@@ -994,15 +1081,18 @@ class Session:
994
1081
  """
995
1082
 
996
1083
  ## 以下为函数执行本体
1084
+ result = None
997
1085
  if (not "#" in line) and (not "@" in line) and (not "%" in line):
998
1086
  cmds = line.split(self.seperator)
999
1087
  for cmd in cmds:
1000
- await self.exec_text_async(cmd)
1088
+ result = await self.exec_text_async(cmd)
1001
1089
  if Settings.client["interval"] > 0:
1002
1090
  await asyncio.sleep(Settings.client["interval"] / 1000.0)
1003
1091
  else:
1004
1092
  cb = CodeBlock(line)
1005
- await cb.async_execute(self)
1093
+ result = await cb.async_execute(self)
1094
+
1095
+ return result
1006
1096
 
1007
1097
  def write_eof(self) -> None:
1008
1098
  """
@@ -1066,50 +1156,212 @@ class Session:
1066
1156
 
1067
1157
  return counts
1068
1158
 
1069
- def _addObjects(self, objs: dict, cls: type):
1070
- if cls == Alias:
1071
- self._aliases.update(objs)
1072
- elif cls == Command:
1073
- self._commands.update(objs)
1074
- elif cls == Trigger:
1075
- self._triggers.update(objs)
1076
- elif cls == Timer:
1077
- self._timers.update(objs)
1078
- elif cls == GMCPTrigger:
1079
- self._gmcp.update(objs)
1080
-
1081
- def _addObject(self, obj, cls: type):
1082
- #if type(obj) == cls:
1083
- if isinstance(obj, cls):
1084
- if cls == Alias:
1085
- self._aliases[obj.id] = obj
1086
- elif cls == Command:
1087
- self._commands[obj.id] = obj
1088
- elif cls == Trigger:
1089
- self._triggers[obj.id] = obj
1090
- elif cls == Timer:
1091
- self._timers[obj.id] = obj
1092
- elif cls == GMCPTrigger:
1093
- self._gmcp[obj.id] = obj
1159
+ # def _addObjects(self, objs: dict, cls: type):
1160
+ # if cls == Alias:
1161
+ # self._aliases.update(objs)
1162
+ # elif cls == Command:
1163
+ # self._commands.update(objs)
1164
+ # elif cls == Trigger:
1165
+ # self._triggers.update(objs)
1166
+ # elif cls == Timer:
1167
+ # self._timers.update(objs)
1168
+ # elif cls == GMCPTrigger:
1169
+ # self._gmcp.update(objs)
1170
+
1171
+ def _addObjects(self, objs):
1172
+ if isinstance(objs, list) or isinstance(objs, tuple):
1173
+ for item in objs:
1174
+ self._addObject(item)
1175
+
1176
+ elif isinstance(objs, dict):
1177
+ for key, item in objs.items():
1178
+ if isinstance(item, BaseObject):
1179
+ if key != item.id:
1180
+ self.warning(f'对象 {item} 字典键值 {key} 与其id {item.id} 不一致,将丢弃键值,以其id添加到会话中...')
1181
+
1182
+ self._addObject(item)
1183
+
1184
+ # def _addObject(self, obj, cls: type):
1185
+ # #if type(obj) == cls:
1186
+ # if isinstance(obj, cls):
1187
+ # if cls == Alias:
1188
+ # self._aliases[obj.id] = obj
1189
+ # elif cls == Command:
1190
+ # self._commands[obj.id] = obj
1191
+ # elif cls == Trigger:
1192
+ # self._triggers[obj.id] = obj
1193
+ # elif cls == Timer:
1194
+ # self._timers[obj.id] = obj
1195
+ # elif cls == GMCPTrigger:
1196
+ # self._gmcp[obj.id] = obj
1197
+
1198
+ def _addObject(self, obj):
1199
+ if isinstance(obj, Alias):
1200
+ self._aliases[obj.id] = obj
1201
+ elif isinstance(obj, Command):
1202
+ self._commands[obj.id] = obj
1203
+ elif isinstance(obj, Trigger):
1204
+ self._triggers[obj.id] = obj
1205
+ elif isinstance(obj, Timer):
1206
+ self._timers[obj.id] = obj
1207
+ elif isinstance(obj, GMCPTrigger):
1208
+ self._gmcp[obj.id] = obj
1209
+
1210
+ def addObject(self, obj: BaseObject):
1211
+ """
1212
+ 向会话中增加单个对象,可直接添加 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类
1213
+
1214
+ :param obj: 特定对象本身,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
1215
+
1216
+ 示例:
1217
+ .. code:: Python
1218
+
1219
+ class Configuration:
1220
+ def __init__(self, session):
1221
+ self.session = session
1222
+
1223
+ self.session.addObject(SimpleAlias(session, r'^gta$', 'get all'),)
1224
+ self.session.addObject(SimpleTrigger(session, r'^[> ]*你嘻嘻地笑了起来.+', 'haha'))
1225
+ self.session.addObject(SimpleTimer(session, 'xixi', timeout = 10))
1226
+
1227
+ """
1228
+ self._addObject(obj)
1229
+
1230
+ def addObjects(self, objs):
1231
+ """
1232
+ 向会话中增加多个对象,可直接添加 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类的元组、列表或者字典(保持兼容性)
1233
+
1234
+ :param objs: 多个特定对象组成的元组、列表或者字典,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
1235
+
1236
+ 示例:
1237
+ .. code:: Python
1238
+
1239
+ class Configuration:
1240
+ def __init__(self, session):
1241
+ self.session = session
1242
+
1243
+ self.objs = [
1244
+ SimpleAlias(session, r'^gta$', 'get all;xixi'),
1245
+ SimpleTrigger(session, r'^[> ]*你嘻嘻地笑了起来.+', 'haha'),
1246
+ SimpleTimer(session, 'xixi', timeout = 10)
1247
+ ]
1248
+
1249
+ self.session.addObjects(self.objs)
1250
+
1251
+ """
1252
+ self._addObjects(objs)
1094
1253
 
1095
1254
  def _delObject(self, id, cls: type):
1096
1255
  if cls == Alias:
1097
1256
  self._aliases.pop(id, None)
1098
1257
  elif cls == Command:
1099
- self._commands.pop(id, None)
1258
+ cmd = self._commands.pop(id, None)
1259
+ if isinstance(cmd, Command):
1260
+ cmd.reset()
1261
+ cmd.unload()
1262
+ cmd.__unload__()
1263
+
1100
1264
  elif cls == Trigger:
1101
1265
  self._triggers.pop(id, None)
1102
1266
  elif cls == Timer:
1103
- self._timers.pop(id, None)
1267
+ timer = self._timers.pop(id, None)
1268
+ if isinstance(timer, Timer):
1269
+ timer.enabled = False
1104
1270
  elif cls == GMCPTrigger:
1105
1271
  self._gmcp.pop(id, None)
1106
1272
 
1273
+
1107
1274
  def _delObjects(self, ids: Iterable, cls: type):
1108
1275
  "删除多个指定元素"
1109
1276
  for id in ids:
1110
1277
  self._delObject(id, cls)
1111
1278
 
1112
- def addAliases(self, alis: dict):
1279
+ def delObject(self, obj):
1280
+ """
1281
+ 从会话中移除一个对象,可直接删除 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类本身
1282
+
1283
+ ** 注 ** 现在 delObject 和 delObjects 使用结果相同,都可以清除单个对象、对个对象的list, tuple或dict, 可以有效防止代码写错
1284
+
1285
+ :param obj: 要删除的多个特定对象组成的元组、列表或者字典,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
1286
+
1287
+ 示例:
1288
+ .. code:: Python
1289
+
1290
+ class Configuration:
1291
+ def __init__(self, session):
1292
+ self.session = session
1293
+
1294
+ ali = SimpleAlias(session, r'^gta$', 'get all', id = 'my_ali1')
1295
+
1296
+ # 以下几种方式均可将该别名添加到会话
1297
+ session.addObject(ali)
1298
+ session.addAlias(ali)
1299
+
1300
+ # 以下三种方式均可以删除该别名
1301
+ session.delObject(ali)
1302
+ session.delAlias(ali)
1303
+ session.delAlias("my_ali1")
1304
+
1305
+ """
1306
+ if isinstance(obj, Alias):
1307
+ self._aliases.pop(obj.id, None)
1308
+ elif isinstance(obj, Command):
1309
+ obj.reset()
1310
+ obj.unload()
1311
+ obj.__unload__()
1312
+ self._commands.pop(obj.id, None)
1313
+ elif isinstance(obj, Trigger):
1314
+ self._triggers.pop(obj.id, None)
1315
+ elif isinstance(obj, Timer):
1316
+ obj.enabled = False
1317
+ self._timers.pop(obj.id, None)
1318
+ elif isinstance(obj, GMCPTrigger):
1319
+ self._gmcp.pop(obj.id, None)
1320
+
1321
+ elif isinstance(obj, (list, tuple, dict)):
1322
+ self.delObjects(obj)
1323
+
1324
+ def delObjects(self, objs):
1325
+ """
1326
+ 从会话中移除一组对象,可直接删除多个 Alias, Trigger, GMCPTrigger, Command, Timer
1327
+
1328
+ ** 注 ** 现在 delObject 和 delObjects 使用结果相同,都可以清除单个对象、对个对象的list, tuple或dict, 可以有效防止代码写错
1329
+
1330
+ :param objs: 要删除的一组对象的元组、列表或者字典(保持兼容性),其中对象可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类
1331
+
1332
+ 示例:
1333
+
1334
+ .. code:: Python
1335
+
1336
+ class Configuration:
1337
+ def __init__(self, session):
1338
+ self.session = session
1339
+
1340
+ self.objs = [
1341
+ SimpleAlias(session, r'^gta$', 'get all;xixi'),
1342
+ SimpleTrigger(session, r'^[> ]*你嘻嘻地笑了起来.+', 'haha'),
1343
+ SimpleTimer(session, 'xixi', timeout = 10)
1344
+ ]
1345
+
1346
+ self.session.addObjects(self.objs)
1347
+
1348
+ def __unload__(self):
1349
+ "卸载本模块时,删除所有本模块添加的对象"
1350
+ self.session.delObjects(self.objs)
1351
+
1352
+ """
1353
+ if isinstance(objs, list) or isinstance(objs, tuple):
1354
+ for item in objs:
1355
+ self.delObject(item)
1356
+
1357
+ elif isinstance(objs, dict):
1358
+ for key, item in objs.items():
1359
+ self.delObject(item)
1360
+
1361
+ elif isinstance(objs, BaseObject):
1362
+ self.delObject(objs)
1363
+
1364
+ def addAliases(self, alis):
1113
1365
  """
1114
1366
  向会话中增加多个别名
1115
1367
 
@@ -1130,55 +1382,55 @@ class Session:
1130
1382
  self._aliases['my_ali2'] = SimpleAlias(self.session, "s", "south", id = "my_ali2")
1131
1383
  self.session.addAliases(self._aliases)
1132
1384
  """
1133
- self._addObjects(alis, Alias)
1385
+ self._addObjects(alis)
1134
1386
 
1135
- def addCommands(self, cmds: dict):
1387
+ def addCommands(self, cmds):
1136
1388
  """
1137
1389
  向会话中增加多个命令。使用方法与 addAliases 类似。
1138
1390
 
1139
1391
  :param cmds: 多个命令的字典。字典 key 应为每个命令的 id。
1140
1392
  """
1141
- self._addObjects(cmds, Command)
1393
+ self._addObjects(cmds)
1142
1394
 
1143
- def addTriggers(self, tris: dict):
1395
+ def addTriggers(self, tris):
1144
1396
  """
1145
1397
  向会话中增加多个触发器。使用方法与 addAliases 类似。
1146
1398
 
1147
1399
  :param tris: 多个触发器的字典。字典 key 应为每个触发器的 id。
1148
1400
  """
1149
- self._addObjects(tris, Trigger)
1401
+ self._addObjects(tris)
1150
1402
 
1151
- def addGMCPs(self, gmcps: dict):
1403
+ def addGMCPs(self, gmcps):
1152
1404
  """
1153
1405
  向会话中增加多个GMCPTrigger。使用方法与 addAliases 类似。
1154
1406
 
1155
1407
  :param gmcps: 多个GMCPTrigger的字典。字典 key 应为每个GMCPTrigger的 id。
1156
1408
  """
1157
- self._addObjects(gmcps, GMCPTrigger)
1409
+ self._addObjects(gmcps)
1158
1410
 
1159
- def addTimers(self, tis: dict):
1411
+ def addTimers(self, tis):
1160
1412
  """
1161
1413
  向会话中增加多个定时器。使用方法与 addAliases 类似。
1162
1414
 
1163
1415
  :param tis: 多个定时器的字典。字典 key 应为每个定时器的 id。
1164
1416
  """
1165
- self._addObjects(tis, Timer)
1417
+ self._addObjects(tis)
1166
1418
 
1167
- def addAlias(self, ali: Alias):
1419
+ def addAlias(self, ali):
1168
1420
  """
1169
1421
  向会话中增加一个别名。
1170
1422
 
1171
1423
  :param ali: 要增加的别名对象,应为 Alias 类型或其子类
1172
1424
  """
1173
- self._addObject(ali, Alias)
1425
+ self._addObject(ali)
1174
1426
 
1175
- def addCommand(self, cmd: Command):
1427
+ def addCommand(self, cmd):
1176
1428
  """
1177
1429
  向会话中增加一个命令。
1178
1430
 
1179
1431
  :param cmd: 要增加的命令对象,应为 Command 类型或其子类
1180
1432
  """
1181
- self._addObject(cmd, Command)
1433
+ self._addObject(cmd)
1182
1434
 
1183
1435
  def addTrigger(self, tri: Trigger):
1184
1436
  """
@@ -1186,7 +1438,7 @@ class Session:
1186
1438
 
1187
1439
  :param tri: 要增加的触发器对象,应为 Trigger 类型或其子类
1188
1440
  """
1189
- self._addObject(tri, Trigger)
1441
+ self._addObject(tri)
1190
1442
 
1191
1443
  def addTimer(self, ti: Timer):
1192
1444
  """
@@ -1194,7 +1446,7 @@ class Session:
1194
1446
 
1195
1447
  :param ti: 要增加的定时器对象,应为 Timer 类型或其子类
1196
1448
  """
1197
- self._addObject(ti, Timer)
1449
+ self._addObject(ti)
1198
1450
 
1199
1451
  def addGMCP(self, gmcp: GMCPTrigger):
1200
1452
  """
@@ -1203,7 +1455,7 @@ class Session:
1203
1455
  :param gmcp: 要增加的GMCP触发器对象,应为 GMCPTrigger 类型或其子类
1204
1456
  """
1205
1457
 
1206
- self._addObject(gmcp, GMCPTrigger)
1458
+ self._addObject(gmcp)
1207
1459
 
1208
1460
  def delAlias(self, ali):
1209
1461
  """
@@ -1322,7 +1574,7 @@ class Session:
1322
1574
  for ti in ti_s:
1323
1575
  self.delTimer(ti)
1324
1576
 
1325
- def delGMCP(self, gmcp: GMCPTrigger):
1577
+ def delGMCP(self, gmcp):
1326
1578
  """
1327
1579
  从会话中移除一个GMCP触发器,可接受 GMCPTrigger 对象或其的id。使用方法与 delAlias 类似
1328
1580
 
@@ -1604,7 +1856,8 @@ class Session:
1604
1856
  - #session
1605
1857
  '''
1606
1858
 
1607
- self.application.close_session()
1859
+ #self.application.close_session()
1860
+ self.application.act_close_session()
1608
1861
 
1609
1862
  async def handle_wait(self, code: CodeLine = None, *args, **kwargs):
1610
1863
  '''
@@ -1637,6 +1890,7 @@ class Session:
1637
1890
  该函数不应该在代码中直接调用。
1638
1891
 
1639
1892
  相关命令:
1893
+ - #disconnect
1640
1894
  - #close
1641
1895
  - #exit
1642
1896
  '''
@@ -1658,6 +1912,18 @@ class Session:
1658
1912
 
1659
1913
  self.info("已经与服务器连接了 {}".format(time_msg))
1660
1914
 
1915
+ def handle_disconnect(self, code: CodeLine = None, *args, **kwargs):
1916
+ '''
1917
+ 嵌入命令 #disconnect / #dis 的执行函数,断开到远程服务器的连接(仅当远程服务器已连接时有效)。
1918
+ 该函数不应该在代码中直接调用。
1919
+
1920
+ 相关命令:
1921
+ - #connect
1922
+ - #close
1923
+ '''
1924
+
1925
+ self.disconnect()
1926
+
1661
1927
  def handle_variable(self, code: CodeLine = None, *args, **kwargs):
1662
1928
  '''
1663
1929
  嵌入命令 #variable / #var 的执行函数,操作会话变量。
@@ -1696,7 +1962,7 @@ class Session:
1696
1962
  else:
1697
1963
  vars_simple[k] = v
1698
1964
 
1699
- width = self.application.get_width()
1965
+ width = self.application.get_width() - 2 # 保留2个字符,防止 > 导致换行
1700
1966
 
1701
1967
  title = f" VARIABLE LIST IN SESSION {self.name} "
1702
1968
  left = (width - len(title)) // 2
@@ -1704,6 +1970,7 @@ class Session:
1704
1970
  self.writetobuffer("="*left + title + "="*right, newline = True)
1705
1971
 
1706
1972
  # print vars in simple, 每个变量占40格,一行可以多个变量
1973
+ # 这里可以考虑调整一下,默认40, 但如果一个变量值太长,则选择占两个位置
1707
1974
  var_count = len(vars_simple)
1708
1975
  var_per_line = (width - 2) // 40
1709
1976
  lines = math.ceil(var_count / var_per_line)
@@ -1719,14 +1986,18 @@ class Session:
1719
1986
  self.writetobuffer(" " * left_space)
1720
1987
  line_vars = var_keys[start:end]
1721
1988
  for var in line_vars:
1722
- self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
1989
+ repr = vars_simple[var].__repr__()
1990
+ vwidth = 22 - (wcswidth(repr) - len(repr))
1991
+ self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
1992
+ #self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
1723
1993
 
1724
1994
  self.writetobuffer("", newline = True)
1725
1995
 
1726
1996
  # print vars in complex, 每个变量占1行
1727
- for k, v in vars_complex.items():
1997
+ var_keys = sorted(vars_complex.keys())
1998
+ for key in var_keys:
1728
1999
  self.writetobuffer(" " * left_space)
1729
- self.writetobuffer("{0:>18} = {1}".format(k, v.__repr__()), newline = True)
2000
+ self.writetobuffer("{0:>20} = {1}".format(key, vars_complex[key].__repr__()), newline = True)
1730
2001
 
1731
2002
  self.writetobuffer("="*width, newline = True)
1732
2003
 
@@ -1779,7 +2050,7 @@ class Session:
1779
2050
  else:
1780
2051
  vars_simple[k] = v
1781
2052
 
1782
- width = self.application.get_width()
2053
+ width = self.application.get_width() - 2 # 保留2个字符,防止 > 导致换行
1783
2054
 
1784
2055
  title = f" GLOBAL VARIABLES LIST "
1785
2056
  left = (width - len(title)) // 2
@@ -1802,21 +2073,23 @@ class Session:
1802
2073
  self.writetobuffer(" " * left_space)
1803
2074
  line_vars = var_keys[start:end]
1804
2075
  for var in line_vars:
1805
- self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
2076
+ repr = vars_simple[var].__repr__()
2077
+ vwidth = 22 - (wcswidth(repr) - len(repr))
2078
+ self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
1806
2079
 
1807
2080
  self.writetobuffer("", newline = True)
1808
2081
 
1809
2082
  # print vars in complex, 每个变量占1行
1810
2083
  for k, v in vars_complex.items():
1811
2084
  self.writetobuffer(" " * left_space)
1812
- self.writetobuffer("{0:>18} = {1}".format(k, v.__repr__()), newline = True)
2085
+ self.writetobuffer("{0:>20} = {1}".format(k, v.__repr__()), newline = True)
1813
2086
 
1814
2087
  self.writetobuffer("="*width, newline = True)
1815
2088
 
1816
2089
  elif len(args) == 1:
1817
2090
  var = args[0]
1818
2091
  if var in self.application.globals.keys():
1819
- self.info("{0:>18} = {1:<19}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
2092
+ self.info("{0:>20} = {1:<22}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
1820
2093
  else:
1821
2094
  self.info("全局空间不存在名称为 {} 的变量".format(var), "全局变量")
1822
2095
 
@@ -1891,7 +2164,7 @@ class Session:
1891
2164
  self.info("创建Timer {} 成功: {}".format(ti.id, ti.__repr__()))
1892
2165
 
1893
2166
  def handle_alias(self, code: CodeLine = None, *args, **kwargs):
1894
- '''
2167
+ r"""
1895
2168
  嵌入命令 #alias / #ali 的执行函数,操作别名。该命令可以不带参数、带一个参数或者两个参数。
1896
2169
  该函数不应该在代码中直接调用。
1897
2170
 
@@ -1922,7 +2195,7 @@ class Session:
1922
2195
  - #trigger
1923
2196
  - #timer
1924
2197
  - #command
1925
- '''
2198
+ """
1926
2199
 
1927
2200
  self._handle_objs("Alias", self._aliases, *code.code[2:])
1928
2201
 
@@ -2281,6 +2554,7 @@ class Session:
2281
2554
  self._variables.clear()
2282
2555
  self._tasks.clear()
2283
2556
 
2557
+
2284
2558
  def load_module(self, module_names):
2285
2559
  """
2286
2560
  模块加载函数。
@@ -2304,27 +2578,12 @@ class Session:
2304
2578
  "加载指定名称模块"
2305
2579
  try:
2306
2580
  if module_name not in self._modules.keys():
2307
- mod = importlib.import_module(module_name)
2308
- if hasattr(mod, 'Configuration'):
2309
- config = mod.Configuration(self)
2310
- self._modules[module_name] = {"module": mod, "config": config}
2311
- self.info(f"主配置模块 {module_name} 加载完成.")
2312
- else:
2313
- self._modules[module_name] = {"module": mod, "config": None}
2314
- self.info(f"子配置模块 {module_name} 加载完成.")
2581
+ self._modules[module_name] = ModuleInfo(module_name, self)
2315
2582
 
2316
2583
  else:
2317
- mod = self._modules[module_name]["module"]
2318
- config = self._modules[module_name]["config"]
2319
- if config: del config
2320
- mod = importlib.reload(mod)
2321
- if hasattr(mod, 'Configuration'):
2322
- config = mod.Configuration(self)
2323
- self._modules[module_name] = {"module": mod, "config": config}
2324
- self.info(f"主配置模块 {module_name} 重新加载完成.")
2325
- else:
2326
- self._modules[module_name] = {"module": mod, "config": None}
2327
- self.info(f"子配置模块 {module_name} 重新加载完成.")
2584
+ mod = self._modules[module_name]
2585
+ if isinstance(mod, ModuleInfo):
2586
+ mod.reload()
2328
2587
 
2329
2588
  except Exception as e:
2330
2589
  import traceback
@@ -2350,20 +2609,11 @@ class Session:
2350
2609
  self._unload_module(mod)
2351
2610
 
2352
2611
  def _unload_module(self, module_name):
2353
- "卸载指定名称模块。卸载支持需要模块的Configuration实现__del__方法"
2612
+ "卸载指定名称模块。卸载支持需要模块的Configuration实现 __unload__ 或 unload 方法"
2354
2613
  if module_name in self._modules.keys():
2355
- mod = self._modules[module_name]["module"]
2356
- config = self._modules[module_name]["config"]
2357
- if config:
2358
- if hasattr(config, "unload"):
2359
- unload = getattr(config, "unload", None)
2360
- if callable(unload):
2361
- unload(config)
2362
-
2363
- del config
2364
- del mod
2365
- self._modules.pop(module_name)
2366
- self.info(f"配置模块 {module_name} 已成功卸载.")
2614
+ mod = self._modules.pop(module_name)
2615
+ if isinstance(mod, ModuleInfo):
2616
+ mod.unload()
2367
2617
 
2368
2618
  else:
2369
2619
  self.warning(f"指定模块名称 {module_name} 并未加载.")
@@ -2377,9 +2627,9 @@ class Session:
2377
2627
  :param module_names: 要重新加载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。当不指定时,重新加载所有已加载模块。
2378
2628
  """
2379
2629
  if module_names is None:
2380
- self.clean()
2381
- mods = list(self._modules.keys())
2382
- self.load_module(mods)
2630
+ for name, module in self._modules.items():
2631
+ if isinstance(module, ModuleInfo):
2632
+ module.reload()
2383
2633
 
2384
2634
  self.info(f"所有配置模块全部重新加载完成.")
2385
2635
 
@@ -2387,14 +2637,17 @@ class Session:
2387
2637
  for mod in module_names:
2388
2638
  mod = mod.strip()
2389
2639
  if mod in self._modules.keys():
2390
- self.load_module(mod)
2640
+ module = self._modules[mod]
2641
+ if isinstance(module, ModuleInfo):
2642
+ module.reload()
2391
2643
  else:
2392
2644
  self.warning(f"指定模块名称 {mod} 并未加载,无法重新加载.")
2393
2645
 
2394
2646
  elif isinstance(module_names, str):
2395
2647
  if module_names in self._modules.keys():
2396
- mod = module_names.strip()
2397
- self.load_module(mod)
2648
+ module = self._modules[module_names]
2649
+ if isinstance(module, ModuleInfo):
2650
+ module.reload()
2398
2651
  else:
2399
2652
  self.warning(f"指定模块名称 {module_names} 并未加载,无法重新加载.")
2400
2653
 
@@ -2478,7 +2731,7 @@ class Session:
2478
2731
 
2479
2732
  elif mod in self.plugins.keys():
2480
2733
  self.application.reload_plugin(self.plugins[mod])
2481
-
2734
+ self.info(f'插件 {mod} 重新加载完成!')
2482
2735
  else:
2483
2736
  self.warning(f"指定名称 {mod} 既未找到模块,也未找到插件,重新加载失败..")
2484
2737
 
@@ -2532,12 +2785,29 @@ class Session:
2532
2785
  - #reload
2533
2786
  '''
2534
2787
 
2535
- count = len(self._modules.keys())
2536
- if count == 0:
2537
- self.info("当前会话并未加载任何模块。", "MODULES")
2538
- else:
2539
- self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
2788
+ args = code.code[2:]
2789
+
2790
+ if len(args) == 0:
2791
+ count = len(self._modules.keys())
2792
+ if count == 0:
2793
+ self.info("当前会话并未加载任何模块。", "MODULES")
2794
+ else:
2795
+ self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
2540
2796
 
2797
+ elif len(args) >= 1:
2798
+ modules = ",".join(args).split(",")
2799
+ for mod in modules:
2800
+ if mod in self._modules.keys():
2801
+ module = self._modules[mod]
2802
+ if isinstance(module, ModuleInfo):
2803
+ if module.ismainmodule:
2804
+ self.info(f"模块 {module.name} 中包含的配置包括: {', '.join(module.config.keys())}")
2805
+ else:
2806
+ self.info(f"模块 {module.name} 为子模块,不包含配置。")
2807
+
2808
+ else:
2809
+ self.info(f"本会话中不存在指定名称 {mod} 的模块,可能是尚未加载到本会话中")
2810
+
2541
2811
  def handle_reset(self, code: CodeLine = None, *args, **kwargs):
2542
2812
  '''
2543
2813
  嵌入命令 #reset 的执行函数,复位全部脚本。该命令不带参数。
@@ -2557,7 +2827,8 @@ class Session:
2557
2827
 
2558
2828
  def handle_save(self, code: CodeLine = None, *args, **kwargs):
2559
2829
  '''
2560
- 嵌入命令 #save 的执行函数,保存当前会话变量(系统变量除外)至文件。该命令不带参数。
2830
+ 嵌入命令 #save 的执行函数,保存当前会话变量(系统变量和临时变量除外)至文件。该命令不带参数。
2831
+ 系统变量包括 %line, %copy 和 %raw 三个,临时变量是指变量名已下划线开头的变量
2561
2832
  该函数不应该在代码中直接调用。
2562
2833
 
2563
2834
  使用:
@@ -2578,10 +2849,10 @@ class Session:
2578
2849
  with open(file, "wb") as fp:
2579
2850
  saved = dict()
2580
2851
  saved.update(self._variables)
2581
- # keys = list(saved.keys())
2582
- # for key in keys:
2583
- # if key.startswith("%"):
2584
- # saved.pop(key)
2852
+ keys = list(saved.keys())
2853
+ for key in keys:
2854
+ if key.startswith("_"):
2855
+ saved.pop(key)
2585
2856
  saved.pop("%line", None)
2586
2857
  saved.pop("%raw", None)
2587
2858
  saved.pop("%copy", None)
@@ -2680,7 +2951,7 @@ class Session:
2680
2951
  if name in self.plugins.keys():
2681
2952
  plugin = self.plugins[name]
2682
2953
  self.info(f"{plugin.desc['DESCRIPTION']}, 版本 {plugin.desc['VERSION']} 作者 {plugin.desc['AUTHOR']} 发布日期 {plugin.desc['RELEASE_DATE']}", f"PLUGIN {name}")
2683
- self.writetobuffer(plugin.help)
2954
+ self.writetobuffer(plugin.help, True)
2684
2955
 
2685
2956
  def handle_replace(self, code: CodeLine = None, *args, **kwargs):
2686
2957
  '''
@@ -2832,3 +3103,105 @@ class Session:
2832
3103
  :param style: 要输出信息的格式(ANSI), 默认为 ERR_STYLE, \x1b[31m
2833
3104
  """
2834
3105
  self.info2(msg, title, style)
3106
+
3107
+ def handle_log(self, code: CodeLine = None, *args, **kwargs):
3108
+ '''
3109
+ 嵌入命令 #log 的执行函数,控制当前会话的记录状态。
3110
+ 该函数不应该在代码中直接调用。
3111
+
3112
+ 使用:
3113
+ - #log : 显示所有记录器的状态情况
3114
+ - #log start [logger-name] [-a|-w|-n] [-r] : 启动一个记录器
3115
+
3116
+ 参数:
3117
+ - :logger-name: 记录器名称。当不指定时,选择名称为会话名称的记录器(会话默认记录器)
3118
+ - :-a|-w|-n: 记录器模式选择。 -a 为添加模式(未指定时默认值),在原记录文件后端添加; -w 为覆写模式,清空原记录文件并重新记录; -n 为新建模式,以名称和当前时间为参数,使用 name.now.log 形式创建新的记录文件
3119
+ - :-r: 指定记录器是否使用 raw 模式
3120
+
3121
+ - #log stop [logger-name] : 停止一个记录器
3122
+
3123
+ 参数:
3124
+ - :logger-name: 记录器名称。当不指定时,选择名称为会话名称的记录器(会话默认记录器)
3125
+
3126
+ - #log show [loggerFile]: 显示全部日志记录或指定记录文件
3127
+
3128
+ 参数:
3129
+ - :loggerFile: 要显示的记录文件名称。当不指定时,弹出对话框列出当前目录下所有记录文件
3130
+
3131
+ 示例:
3132
+ - ``#log`` : 在当前会话窗口列出所有记录器状态
3133
+ - ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 log 目录下 name.log 文件的后端
3134
+ - ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 log 目录下 name.log 文件的后端
3135
+ - ``#log start chat`` : 启动名为 chat 的记录器。该记录器以纯文本模式,记录代码中调用过该记录器 .log 进行记录的信息
3136
+ - ``#log stop`` : 停止本会话默认记录器(记录器名为会话名)。
3137
+
3138
+ 注意:
3139
+ - 记录器文件模式(-a|-w|-n)在修改后,只有在下一次该记录器启动时才会生效
3140
+ - 记录器记录模式(-r)在修改后立即生效
3141
+ '''
3142
+
3143
+ args = list()
3144
+ if isinstance(code, CodeLine):
3145
+ args = code.code[2:]
3146
+
3147
+ if len(args) == 0:
3148
+ session_loggers = set(self._loggers.keys())
3149
+ app_loggers = set(self.application.loggers.keys()).difference(session_loggers)
3150
+ self.info("本会话中的记录器情况:")
3151
+ for name in session_loggers:
3152
+ logger = self.application.loggers[name]
3153
+ self.info(f"记录器 {logger.name}, 当前状态: {'开启' if logger.enabled else '关闭'}, 文件模式: {logger.mode}, 记录模式: {'ANSI' if logger.raw else '纯文本'}")
3154
+
3155
+ if len(app_loggers) > 0:
3156
+ self.info("本应用其他会话中的记录器情况:")
3157
+ for name in app_loggers:
3158
+ logger = self.application.loggers[name]
3159
+ self.info(f"记录器 {logger.name}, 当前状态: {'开启' if logger.enabled else '关闭'}, 文件模式: {logger.mode}, 记录模式: {'ANSI' if logger.raw else '纯文本'}")
3160
+
3161
+ else:
3162
+ name = self.name
3163
+ if len(args) > 1 and not args[1].startswith('-'):
3164
+ name = args[1]
3165
+
3166
+ if (args[0] == "start"):
3167
+ if "-n" in args:
3168
+ mode = "n"
3169
+ mode_name = '新建'
3170
+ elif "-w" in args:
3171
+ mode = "w"
3172
+ mode_name = '覆写'
3173
+ else:
3174
+ mode = "a"
3175
+ mode_name = '添加'
3176
+
3177
+ raw = True if "-r" in args else False
3178
+ raw_name = '原始ANSI' if raw else '纯文本'
3179
+
3180
+ logger = self.getLogger(name = name, mode = mode, raw = raw)
3181
+ logger.enabled = True
3182
+
3183
+ self.info(f"{datetime.datetime.now()}: 记录器{name}以{mode_name}文件模式以及{raw_name}记录模式开启。")
3184
+
3185
+ elif (args[0] == "stop"):
3186
+ self.info(f"{datetime.datetime.now()}: 记录器{name}记录已关闭。")
3187
+ self.log.enabled = False
3188
+
3189
+ elif (args[0] == "show"):
3190
+ if len(args) > 1 and not args[1].startswith('-'):
3191
+ file = args[1]
3192
+ if os.path.exists(file):
3193
+ filepath = os.path.abspath(file)
3194
+ #self.info(f'file {filepath} exists, will be shown.')
3195
+ self.application.logFileShown = filepath
3196
+ self.application.showLogInTab()
3197
+ elif os.path.exists(os.path.join('./log', file)):
3198
+ filepath = os.path.abspath(os.path.join('./log', file))
3199
+ #self.info(f'file {filepath} exists, will be shown.')
3200
+ self.application.logFileShown = filepath
3201
+ self.application.showLogInTab()
3202
+ else:
3203
+ self.warning(f'指定记录文件 {file} 不存在!')
3204
+
3205
+ else:
3206
+ self.application.show_logSelectDialog()
3207
+