pymud 0.20.0__py3-none-any.whl → 0.20.0a2__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/__init__.py +1 -3
- pymud/__main__.py +131 -2
- pymud/dialogs.py +6 -11
- pymud/extras.py +73 -1
- pymud/logger.py +4 -10
- pymud/objects.py +14 -45
- pymud/pkuxkx.py +7 -4
- pymud/pymud.py +54 -91
- pymud/session.py +138 -339
- pymud/settings.py +2 -2
- {pymud-0.20.0.dist-info → pymud-0.20.0a2.dist-info}/METADATA +201 -226
- pymud-0.20.0a2.dist-info/RECORD +17 -0
- {pymud-0.20.0.dist-info → pymud-0.20.0a2.dist-info}/WHEEL +1 -1
- pymud/main.py +0 -142
- pymud/modules.py +0 -188
- pymud-0.20.0.dist-info/RECORD +0 -19
- {pymud-0.20.0.dist-info → pymud-0.20.0a2.dist-info}/LICENSE.txt +0 -0
- {pymud-0.20.0.dist-info → pymud-0.20.0a2.dist-info}/entry_points.txt +0 -0
- {pymud-0.20.0.dist-info → pymud-0.20.0a2.dist-info}/top_level.txt +0 -0
pymud/session.py
CHANGED
@@ -1,15 +1,14 @@
|
|
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
|
2
2
|
from collections.abc import Iterable
|
3
3
|
from collections import OrderedDict
|
4
4
|
import logging, queue
|
5
5
|
from logging import FileHandler
|
6
6
|
from logging.handlers import QueueHandler, QueueListener
|
7
|
-
|
7
|
+
|
8
8
|
from .logger import Logger
|
9
|
-
from .extras import SessionBuffer, DotDict
|
9
|
+
from .extras import SessionBuffer, DotDict, Plugin
|
10
10
|
from .protocol import MudClientProtocol
|
11
|
-
from .
|
12
|
-
from .objects import BaseObject, Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
|
11
|
+
from .objects import Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
|
13
12
|
from .settings import Settings
|
14
13
|
|
15
14
|
|
@@ -30,14 +29,13 @@ class Session:
|
|
30
29
|
|
31
30
|
"""
|
32
31
|
#_esc_regx = re.compile("\x1b\\[[^mz]+[mz]")
|
33
|
-
_esc_regx = re.compile(
|
32
|
+
_esc_regx = re.compile("\x1b\\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
|
34
33
|
|
35
34
|
_sys_commands = (
|
36
35
|
"help",
|
37
36
|
"exit",
|
38
37
|
"close",
|
39
38
|
"connect", # 连接到服务器
|
40
|
-
"disconnect", # 从服务器断开连接
|
41
39
|
|
42
40
|
"info", # 输出蓝色info
|
43
41
|
"warning", # 输出黄色warning
|
@@ -91,7 +89,6 @@ class Session:
|
|
91
89
|
"var" : "variable",
|
92
90
|
"rep" : "repeat",
|
93
91
|
"con" : "connect",
|
94
|
-
"dis" : "disconnect",
|
95
92
|
"wa" : "wait",
|
96
93
|
"mess": "message",
|
97
94
|
"action": "trigger",
|
@@ -142,8 +139,6 @@ class Session:
|
|
142
139
|
self._status_maker = None # 创建状态窗口的函数(属性)
|
143
140
|
self.display_line = ""
|
144
141
|
|
145
|
-
self._activetime = time.time()
|
146
|
-
|
147
142
|
self.initialize()
|
148
143
|
|
149
144
|
self._loggers = dict()
|
@@ -257,6 +252,11 @@ class Session:
|
|
257
252
|
if self.connected:
|
258
253
|
self.write_eof()
|
259
254
|
|
255
|
+
# 两次保存,删掉一次
|
256
|
+
# # 断开时自动保存变量数据
|
257
|
+
# if Settings.client["var_autosave"]:
|
258
|
+
# self.handle_save()
|
259
|
+
|
260
260
|
def onDisconnected(self, protocol):
|
261
261
|
"当从服务器连接断开时执行的操作。包括保存变量(若设置)、打印断开时间、执行自定义事件(若设置)等。"
|
262
262
|
# 断开时自动保存变量数据
|
@@ -294,15 +294,6 @@ class Session:
|
|
294
294
|
|
295
295
|
return dura
|
296
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
|
-
|
306
297
|
@property
|
307
298
|
def status_maker(self):
|
308
299
|
"""
|
@@ -764,7 +755,7 @@ class Session:
|
|
764
755
|
lines = line.split(self.seperator)
|
765
756
|
for ln in lines:
|
766
757
|
if Settings.client["echo_input"]:
|
767
|
-
self.writetobuffer(f"\x1b[32m{ln}\x1b[0m"
|
758
|
+
self.writetobuffer(f"\x1b[32m{ln}\x1b[0m")
|
768
759
|
else:
|
769
760
|
self.log.log(f"\x1b[32m{ln}\x1b[0m\n")
|
770
761
|
|
@@ -773,14 +764,12 @@ class Session:
|
|
773
764
|
|
774
765
|
else:
|
775
766
|
if Settings.client["echo_input"]:
|
776
|
-
self.writetobuffer(f"\x1b[32m{line}\x1b[0m"
|
767
|
+
self.writetobuffer(f"\x1b[32m{line}\x1b[0m")
|
777
768
|
else:
|
778
769
|
self.log.log(f"\x1b[32m{line}\x1b[0m\n")
|
779
770
|
|
780
771
|
cmd = line + self.newline
|
781
772
|
self.write(cmd.encode(self.encoding, Settings.server["encoding_errors"]))
|
782
|
-
|
783
|
-
self._activetime = time.time()
|
784
773
|
|
785
774
|
async def waitfor(self, line: str, awaitable, wait_time = 0.05) -> None:
|
786
775
|
"""
|
@@ -804,7 +793,7 @@ class Session:
|
|
804
793
|
return await awaitable
|
805
794
|
|
806
795
|
def exec(self, cmd: str, name = None, *args, **kwargs):
|
807
|
-
|
796
|
+
"""
|
808
797
|
在名称为name的会话中使用exec_command执行MUD命令。当不指定name时,在当前会话中执行。
|
809
798
|
|
810
799
|
- exec 与 writeline 都会向服务器写入数据。其差异在于,exec执行的内容,会先经过Alias处理和Command处理,实际向远程发送内容与cmd可以不一致。
|
@@ -819,7 +808,7 @@ class Session:
|
|
819
808
|
示例:
|
820
809
|
.. code:: Python
|
821
810
|
|
822
|
-
session.addAlias(SimpleAlias(self.session,
|
811
|
+
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"))
|
823
812
|
session.exec("cb j1a")
|
824
813
|
"""
|
825
814
|
name = name or self.name
|
@@ -840,10 +829,12 @@ class Session:
|
|
840
829
|
name = name or self.name
|
841
830
|
if name in self.application.sessions.keys():
|
842
831
|
session = self.application.sessions[name]
|
843
|
-
|
832
|
+
await session.exec_command_async(cmd, *args, **kwargs)
|
844
833
|
else:
|
845
834
|
self.error(f"不存在名称为{name}的会话")
|
846
835
|
|
836
|
+
|
837
|
+
|
847
838
|
def exec_code(self, cl: CodeLine, *args, **kwargs):
|
848
839
|
"""
|
849
840
|
执行解析为CodeLine形式的MUD命令(必定为单个命令)。一般情况下,脚本中不应调用该方法,而应使用exec/exec_command。
|
@@ -917,7 +908,6 @@ class Session:
|
|
917
908
|
:param args: 保留兼容与扩展性所需
|
918
909
|
:param kwargs: 保留兼容与扩展性所需
|
919
910
|
"""
|
920
|
-
|
921
911
|
if cl.length == 0:
|
922
912
|
self.writeline("")
|
923
913
|
|
@@ -945,9 +935,9 @@ class Session:
|
|
945
935
|
else:
|
946
936
|
try:
|
947
937
|
cb = CodeBlock(sess_cmd)
|
948
|
-
|
938
|
+
await cb.async_execute(session, *args, **kwargs)
|
949
939
|
except Exception as e:
|
950
|
-
|
940
|
+
await session.exec_command_async(sess_cmd)
|
951
941
|
|
952
942
|
else:
|
953
943
|
if cmd in self._commands_alias.keys():
|
@@ -964,7 +954,7 @@ class Session:
|
|
964
954
|
|
965
955
|
else:
|
966
956
|
cmdtext, code = cl.expand(self, *args, **kwargs)
|
967
|
-
|
957
|
+
await self.exec_text_async(cmdtext)
|
968
958
|
|
969
959
|
def exec_text(self, cmdtext: str):
|
970
960
|
"""
|
@@ -1004,14 +994,14 @@ class Session:
|
|
1004
994
|
|
1005
995
|
异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
|
1006
996
|
"""
|
1007
|
-
|
997
|
+
|
1008
998
|
isNotCmd = True
|
1009
999
|
for command in self._commands.values():
|
1010
1000
|
if isinstance(command, Command) and command.enabled:
|
1011
1001
|
state = command.match(cmdtext)
|
1012
1002
|
if state.result == Command.SUCCESS:
|
1013
1003
|
# 命令的任务名称采用命令id,以便于后续查错
|
1014
|
-
|
1004
|
+
await self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
|
1015
1005
|
isNotCmd = False
|
1016
1006
|
break
|
1017
1007
|
|
@@ -1029,8 +1019,6 @@ class Session:
|
|
1029
1019
|
if notAlias:
|
1030
1020
|
self.writeline(cmdtext)
|
1031
1021
|
|
1032
|
-
return result
|
1033
|
-
|
1034
1022
|
def exec_command(self, line: str, *args, **kwargs) -> None:
|
1035
1023
|
"""
|
1036
1024
|
在当前会话中执行MUD命令。多个命令可以用分隔符隔开。
|
@@ -1081,18 +1069,15 @@ class Session:
|
|
1081
1069
|
"""
|
1082
1070
|
|
1083
1071
|
## 以下为函数执行本体
|
1084
|
-
result = None
|
1085
1072
|
if (not "#" in line) and (not "@" in line) and (not "%" in line):
|
1086
1073
|
cmds = line.split(self.seperator)
|
1087
1074
|
for cmd in cmds:
|
1088
|
-
|
1075
|
+
await self.exec_text_async(cmd)
|
1089
1076
|
if Settings.client["interval"] > 0:
|
1090
1077
|
await asyncio.sleep(Settings.client["interval"] / 1000.0)
|
1091
1078
|
else:
|
1092
1079
|
cb = CodeBlock(line)
|
1093
|
-
|
1094
|
-
|
1095
|
-
return result
|
1080
|
+
await cb.async_execute(self)
|
1096
1081
|
|
1097
1082
|
def write_eof(self) -> None:
|
1098
1083
|
"""
|
@@ -1156,212 +1141,50 @@ class Session:
|
|
1156
1141
|
|
1157
1142
|
return counts
|
1158
1143
|
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
def
|
1172
|
-
if
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
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)
|
1144
|
+
def _addObjects(self, objs: dict, cls: type):
|
1145
|
+
if cls == Alias:
|
1146
|
+
self._aliases.update(objs)
|
1147
|
+
elif cls == Command:
|
1148
|
+
self._commands.update(objs)
|
1149
|
+
elif cls == Trigger:
|
1150
|
+
self._triggers.update(objs)
|
1151
|
+
elif cls == Timer:
|
1152
|
+
self._timers.update(objs)
|
1153
|
+
elif cls == GMCPTrigger:
|
1154
|
+
self._gmcp.update(objs)
|
1155
|
+
|
1156
|
+
def _addObject(self, obj, cls: type):
|
1157
|
+
#if type(obj) == cls:
|
1158
|
+
if isinstance(obj, cls):
|
1159
|
+
if cls == Alias:
|
1160
|
+
self._aliases[obj.id] = obj
|
1161
|
+
elif cls == Command:
|
1162
|
+
self._commands[obj.id] = obj
|
1163
|
+
elif cls == Trigger:
|
1164
|
+
self._triggers[obj.id] = obj
|
1165
|
+
elif cls == Timer:
|
1166
|
+
self._timers[obj.id] = obj
|
1167
|
+
elif cls == GMCPTrigger:
|
1168
|
+
self._gmcp[obj.id] = obj
|
1253
1169
|
|
1254
1170
|
def _delObject(self, id, cls: type):
|
1255
1171
|
if cls == Alias:
|
1256
1172
|
self._aliases.pop(id, None)
|
1257
1173
|
elif cls == Command:
|
1258
|
-
|
1259
|
-
if isinstance(cmd, Command):
|
1260
|
-
cmd.reset()
|
1261
|
-
cmd.unload()
|
1262
|
-
cmd.__unload__()
|
1263
|
-
|
1174
|
+
self._commands.pop(id, None)
|
1264
1175
|
elif cls == Trigger:
|
1265
1176
|
self._triggers.pop(id, None)
|
1266
1177
|
elif cls == Timer:
|
1267
|
-
|
1268
|
-
if isinstance(timer, Timer):
|
1269
|
-
timer.enabled = False
|
1178
|
+
self._timers.pop(id, None)
|
1270
1179
|
elif cls == GMCPTrigger:
|
1271
1180
|
self._gmcp.pop(id, None)
|
1272
1181
|
|
1273
|
-
|
1274
1182
|
def _delObjects(self, ids: Iterable, cls: type):
|
1275
1183
|
"删除多个指定元素"
|
1276
1184
|
for id in ids:
|
1277
1185
|
self._delObject(id, cls)
|
1278
1186
|
|
1279
|
-
def
|
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):
|
1187
|
+
def addAliases(self, alis: dict):
|
1365
1188
|
"""
|
1366
1189
|
向会话中增加多个别名
|
1367
1190
|
|
@@ -1382,55 +1205,55 @@ class Session:
|
|
1382
1205
|
self._aliases['my_ali2'] = SimpleAlias(self.session, "s", "south", id = "my_ali2")
|
1383
1206
|
self.session.addAliases(self._aliases)
|
1384
1207
|
"""
|
1385
|
-
self._addObjects(alis)
|
1208
|
+
self._addObjects(alis, Alias)
|
1386
1209
|
|
1387
|
-
def addCommands(self, cmds):
|
1210
|
+
def addCommands(self, cmds: dict):
|
1388
1211
|
"""
|
1389
1212
|
向会话中增加多个命令。使用方法与 addAliases 类似。
|
1390
1213
|
|
1391
1214
|
:param cmds: 多个命令的字典。字典 key 应为每个命令的 id。
|
1392
1215
|
"""
|
1393
|
-
self._addObjects(cmds)
|
1216
|
+
self._addObjects(cmds, Command)
|
1394
1217
|
|
1395
|
-
def addTriggers(self, tris):
|
1218
|
+
def addTriggers(self, tris: dict):
|
1396
1219
|
"""
|
1397
1220
|
向会话中增加多个触发器。使用方法与 addAliases 类似。
|
1398
1221
|
|
1399
1222
|
:param tris: 多个触发器的字典。字典 key 应为每个触发器的 id。
|
1400
1223
|
"""
|
1401
|
-
self._addObjects(tris)
|
1224
|
+
self._addObjects(tris, Trigger)
|
1402
1225
|
|
1403
|
-
def addGMCPs(self, gmcps):
|
1226
|
+
def addGMCPs(self, gmcps: dict):
|
1404
1227
|
"""
|
1405
1228
|
向会话中增加多个GMCPTrigger。使用方法与 addAliases 类似。
|
1406
1229
|
|
1407
1230
|
:param gmcps: 多个GMCPTrigger的字典。字典 key 应为每个GMCPTrigger的 id。
|
1408
1231
|
"""
|
1409
|
-
self._addObjects(gmcps)
|
1232
|
+
self._addObjects(gmcps, GMCPTrigger)
|
1410
1233
|
|
1411
|
-
def addTimers(self, tis):
|
1234
|
+
def addTimers(self, tis: dict):
|
1412
1235
|
"""
|
1413
1236
|
向会话中增加多个定时器。使用方法与 addAliases 类似。
|
1414
1237
|
|
1415
1238
|
:param tis: 多个定时器的字典。字典 key 应为每个定时器的 id。
|
1416
1239
|
"""
|
1417
|
-
self._addObjects(tis)
|
1240
|
+
self._addObjects(tis, Timer)
|
1418
1241
|
|
1419
|
-
def addAlias(self, ali):
|
1242
|
+
def addAlias(self, ali: Alias):
|
1420
1243
|
"""
|
1421
1244
|
向会话中增加一个别名。
|
1422
1245
|
|
1423
1246
|
:param ali: 要增加的别名对象,应为 Alias 类型或其子类
|
1424
1247
|
"""
|
1425
|
-
self._addObject(ali)
|
1248
|
+
self._addObject(ali, Alias)
|
1426
1249
|
|
1427
|
-
def addCommand(self, cmd):
|
1250
|
+
def addCommand(self, cmd: Command):
|
1428
1251
|
"""
|
1429
1252
|
向会话中增加一个命令。
|
1430
1253
|
|
1431
1254
|
:param cmd: 要增加的命令对象,应为 Command 类型或其子类
|
1432
1255
|
"""
|
1433
|
-
self._addObject(cmd)
|
1256
|
+
self._addObject(cmd, Command)
|
1434
1257
|
|
1435
1258
|
def addTrigger(self, tri: Trigger):
|
1436
1259
|
"""
|
@@ -1438,7 +1261,7 @@ class Session:
|
|
1438
1261
|
|
1439
1262
|
:param tri: 要增加的触发器对象,应为 Trigger 类型或其子类
|
1440
1263
|
"""
|
1441
|
-
self._addObject(tri)
|
1264
|
+
self._addObject(tri, Trigger)
|
1442
1265
|
|
1443
1266
|
def addTimer(self, ti: Timer):
|
1444
1267
|
"""
|
@@ -1446,7 +1269,7 @@ class Session:
|
|
1446
1269
|
|
1447
1270
|
:param ti: 要增加的定时器对象,应为 Timer 类型或其子类
|
1448
1271
|
"""
|
1449
|
-
self._addObject(ti)
|
1272
|
+
self._addObject(ti, Timer)
|
1450
1273
|
|
1451
1274
|
def addGMCP(self, gmcp: GMCPTrigger):
|
1452
1275
|
"""
|
@@ -1455,7 +1278,7 @@ class Session:
|
|
1455
1278
|
:param gmcp: 要增加的GMCP触发器对象,应为 GMCPTrigger 类型或其子类
|
1456
1279
|
"""
|
1457
1280
|
|
1458
|
-
self._addObject(gmcp)
|
1281
|
+
self._addObject(gmcp, GMCPTrigger)
|
1459
1282
|
|
1460
1283
|
def delAlias(self, ali):
|
1461
1284
|
"""
|
@@ -1574,7 +1397,7 @@ class Session:
|
|
1574
1397
|
for ti in ti_s:
|
1575
1398
|
self.delTimer(ti)
|
1576
1399
|
|
1577
|
-
def delGMCP(self, gmcp):
|
1400
|
+
def delGMCP(self, gmcp: GMCPTrigger):
|
1578
1401
|
"""
|
1579
1402
|
从会话中移除一个GMCP触发器,可接受 GMCPTrigger 对象或其的id。使用方法与 delAlias 类似
|
1580
1403
|
|
@@ -1890,7 +1713,6 @@ class Session:
|
|
1890
1713
|
该函数不应该在代码中直接调用。
|
1891
1714
|
|
1892
1715
|
相关命令:
|
1893
|
-
- #disconnect
|
1894
1716
|
- #close
|
1895
1717
|
- #exit
|
1896
1718
|
'''
|
@@ -1912,18 +1734,6 @@ class Session:
|
|
1912
1734
|
|
1913
1735
|
self.info("已经与服务器连接了 {}".format(time_msg))
|
1914
1736
|
|
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
|
-
|
1927
1737
|
def handle_variable(self, code: CodeLine = None, *args, **kwargs):
|
1928
1738
|
'''
|
1929
1739
|
嵌入命令 #variable / #var 的执行函数,操作会话变量。
|
@@ -1962,7 +1772,7 @@ class Session:
|
|
1962
1772
|
else:
|
1963
1773
|
vars_simple[k] = v
|
1964
1774
|
|
1965
|
-
width = self.application.get_width()
|
1775
|
+
width = self.application.get_width()
|
1966
1776
|
|
1967
1777
|
title = f" VARIABLE LIST IN SESSION {self.name} "
|
1968
1778
|
left = (width - len(title)) // 2
|
@@ -1970,7 +1780,6 @@ class Session:
|
|
1970
1780
|
self.writetobuffer("="*left + title + "="*right, newline = True)
|
1971
1781
|
|
1972
1782
|
# print vars in simple, 每个变量占40格,一行可以多个变量
|
1973
|
-
# 这里可以考虑调整一下,默认40, 但如果一个变量值太长,则选择占两个位置
|
1974
1783
|
var_count = len(vars_simple)
|
1975
1784
|
var_per_line = (width - 2) // 40
|
1976
1785
|
lines = math.ceil(var_count / var_per_line)
|
@@ -1986,18 +1795,14 @@ class Session:
|
|
1986
1795
|
self.writetobuffer(" " * left_space)
|
1987
1796
|
line_vars = var_keys[start:end]
|
1988
1797
|
for var in line_vars:
|
1989
|
-
|
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__()))
|
1798
|
+
self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
|
1993
1799
|
|
1994
1800
|
self.writetobuffer("", newline = True)
|
1995
1801
|
|
1996
1802
|
# print vars in complex, 每个变量占1行
|
1997
|
-
|
1998
|
-
for key in var_keys:
|
1803
|
+
for k, v in vars_complex.items():
|
1999
1804
|
self.writetobuffer(" " * left_space)
|
2000
|
-
self.writetobuffer("{0:>
|
1805
|
+
self.writetobuffer("{0:>18} = {1}".format(k, v.__repr__()), newline = True)
|
2001
1806
|
|
2002
1807
|
self.writetobuffer("="*width, newline = True)
|
2003
1808
|
|
@@ -2050,7 +1855,7 @@ class Session:
|
|
2050
1855
|
else:
|
2051
1856
|
vars_simple[k] = v
|
2052
1857
|
|
2053
|
-
width = self.application.get_width()
|
1858
|
+
width = self.application.get_width()
|
2054
1859
|
|
2055
1860
|
title = f" GLOBAL VARIABLES LIST "
|
2056
1861
|
left = (width - len(title)) // 2
|
@@ -2073,23 +1878,21 @@ class Session:
|
|
2073
1878
|
self.writetobuffer(" " * left_space)
|
2074
1879
|
line_vars = var_keys[start:end]
|
2075
1880
|
for var in line_vars:
|
2076
|
-
|
2077
|
-
vwidth = 22 - (wcswidth(repr) - len(repr))
|
2078
|
-
self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
|
1881
|
+
self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
|
2079
1882
|
|
2080
1883
|
self.writetobuffer("", newline = True)
|
2081
1884
|
|
2082
1885
|
# print vars in complex, 每个变量占1行
|
2083
1886
|
for k, v in vars_complex.items():
|
2084
1887
|
self.writetobuffer(" " * left_space)
|
2085
|
-
self.writetobuffer("{0:>
|
1888
|
+
self.writetobuffer("{0:>18} = {1}".format(k, v.__repr__()), newline = True)
|
2086
1889
|
|
2087
1890
|
self.writetobuffer("="*width, newline = True)
|
2088
1891
|
|
2089
1892
|
elif len(args) == 1:
|
2090
1893
|
var = args[0]
|
2091
1894
|
if var in self.application.globals.keys():
|
2092
|
-
self.info("{0:>
|
1895
|
+
self.info("{0:>18} = {1:<19}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
|
2093
1896
|
else:
|
2094
1897
|
self.info("全局空间不存在名称为 {} 的变量".format(var), "全局变量")
|
2095
1898
|
|
@@ -2164,7 +1967,7 @@ class Session:
|
|
2164
1967
|
self.info("创建Timer {} 成功: {}".format(ti.id, ti.__repr__()))
|
2165
1968
|
|
2166
1969
|
def handle_alias(self, code: CodeLine = None, *args, **kwargs):
|
2167
|
-
|
1970
|
+
'''
|
2168
1971
|
嵌入命令 #alias / #ali 的执行函数,操作别名。该命令可以不带参数、带一个参数或者两个参数。
|
2169
1972
|
该函数不应该在代码中直接调用。
|
2170
1973
|
|
@@ -2195,7 +1998,7 @@ class Session:
|
|
2195
1998
|
- #trigger
|
2196
1999
|
- #timer
|
2197
2000
|
- #command
|
2198
|
-
|
2001
|
+
'''
|
2199
2002
|
|
2200
2003
|
self._handle_objs("Alias", self._aliases, *code.code[2:])
|
2201
2004
|
|
@@ -2554,7 +2357,6 @@ class Session:
|
|
2554
2357
|
self._variables.clear()
|
2555
2358
|
self._tasks.clear()
|
2556
2359
|
|
2557
|
-
|
2558
2360
|
def load_module(self, module_names):
|
2559
2361
|
"""
|
2560
2362
|
模块加载函数。
|
@@ -2578,12 +2380,32 @@ class Session:
|
|
2578
2380
|
"加载指定名称模块"
|
2579
2381
|
try:
|
2580
2382
|
if module_name not in self._modules.keys():
|
2581
|
-
|
2383
|
+
mod = importlib.import_module(module_name)
|
2384
|
+
if hasattr(mod, 'Configuration'):
|
2385
|
+
config = mod.Configuration(self)
|
2386
|
+
self._modules[module_name] = {"module": mod, "config": config}
|
2387
|
+
self.info(f"主配置模块 {module_name} 加载完成.")
|
2388
|
+
else:
|
2389
|
+
self._modules[module_name] = {"module": mod, "config": None}
|
2390
|
+
self.info(f"子配置模块 {module_name} 加载完成.")
|
2582
2391
|
|
2583
2392
|
else:
|
2584
|
-
mod = self._modules[module_name]
|
2585
|
-
|
2586
|
-
|
2393
|
+
mod = self._modules[module_name]["module"]
|
2394
|
+
config = self._modules[module_name]["config"]
|
2395
|
+
if config:
|
2396
|
+
if hasattr(config, "unload"):
|
2397
|
+
unload = getattr(config, "unload", None)
|
2398
|
+
if callable(unload):
|
2399
|
+
unload(config)
|
2400
|
+
del config
|
2401
|
+
mod = importlib.reload(mod)
|
2402
|
+
if hasattr(mod, 'Configuration'):
|
2403
|
+
config = mod.Configuration(self)
|
2404
|
+
self._modules[module_name] = {"module": mod, "config": config}
|
2405
|
+
self.info(f"主配置模块 {module_name} 重新加载完成.")
|
2406
|
+
else:
|
2407
|
+
self._modules[module_name] = {"module": mod, "config": None}
|
2408
|
+
self.info(f"子配置模块 {module_name} 重新加载完成.")
|
2587
2409
|
|
2588
2410
|
except Exception as e:
|
2589
2411
|
import traceback
|
@@ -2609,11 +2431,20 @@ class Session:
|
|
2609
2431
|
self._unload_module(mod)
|
2610
2432
|
|
2611
2433
|
def _unload_module(self, module_name):
|
2612
|
-
"卸载指定名称模块。卸载支持需要模块的Configuration实现
|
2434
|
+
"卸载指定名称模块。卸载支持需要模块的Configuration实现__del__方法"
|
2613
2435
|
if module_name in self._modules.keys():
|
2614
|
-
mod = self._modules
|
2615
|
-
|
2616
|
-
|
2436
|
+
mod = self._modules[module_name]["module"]
|
2437
|
+
config = self._modules[module_name]["config"]
|
2438
|
+
if config:
|
2439
|
+
if hasattr(config, "unload"):
|
2440
|
+
unload = getattr(config, "unload", None)
|
2441
|
+
if callable(unload):
|
2442
|
+
unload(config)
|
2443
|
+
|
2444
|
+
del config
|
2445
|
+
del mod
|
2446
|
+
self._modules.pop(module_name)
|
2447
|
+
self.info(f"配置模块 {module_name} 已成功卸载.")
|
2617
2448
|
|
2618
2449
|
else:
|
2619
2450
|
self.warning(f"指定模块名称 {module_name} 并未加载.")
|
@@ -2627,9 +2458,9 @@ class Session:
|
|
2627
2458
|
:param module_names: 要重新加载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。当不指定时,重新加载所有已加载模块。
|
2628
2459
|
"""
|
2629
2460
|
if module_names is None:
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2461
|
+
self.clean()
|
2462
|
+
mods = list(self._modules.keys())
|
2463
|
+
self.load_module(mods)
|
2633
2464
|
|
2634
2465
|
self.info(f"所有配置模块全部重新加载完成.")
|
2635
2466
|
|
@@ -2637,17 +2468,14 @@ class Session:
|
|
2637
2468
|
for mod in module_names:
|
2638
2469
|
mod = mod.strip()
|
2639
2470
|
if mod in self._modules.keys():
|
2640
|
-
|
2641
|
-
if isinstance(module, ModuleInfo):
|
2642
|
-
module.reload()
|
2471
|
+
self.load_module(mod)
|
2643
2472
|
else:
|
2644
2473
|
self.warning(f"指定模块名称 {mod} 并未加载,无法重新加载.")
|
2645
2474
|
|
2646
2475
|
elif isinstance(module_names, str):
|
2647
2476
|
if module_names in self._modules.keys():
|
2648
|
-
|
2649
|
-
|
2650
|
-
module.reload()
|
2477
|
+
mod = module_names.strip()
|
2478
|
+
self.load_module(mod)
|
2651
2479
|
else:
|
2652
2480
|
self.warning(f"指定模块名称 {module_names} 并未加载,无法重新加载.")
|
2653
2481
|
|
@@ -2731,7 +2559,7 @@ class Session:
|
|
2731
2559
|
|
2732
2560
|
elif mod in self.plugins.keys():
|
2733
2561
|
self.application.reload_plugin(self.plugins[mod])
|
2734
|
-
|
2562
|
+
|
2735
2563
|
else:
|
2736
2564
|
self.warning(f"指定名称 {mod} 既未找到模块,也未找到插件,重新加载失败..")
|
2737
2565
|
|
@@ -2785,29 +2613,12 @@ class Session:
|
|
2785
2613
|
- #reload
|
2786
2614
|
'''
|
2787
2615
|
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
self.info("当前会话并未加载任何模块。", "MODULES")
|
2794
|
-
else:
|
2795
|
-
self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
|
2616
|
+
count = len(self._modules.keys())
|
2617
|
+
if count == 0:
|
2618
|
+
self.info("当前会话并未加载任何模块。", "MODULES")
|
2619
|
+
else:
|
2620
|
+
self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
|
2796
2621
|
|
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
|
-
|
2811
2622
|
def handle_reset(self, code: CodeLine = None, *args, **kwargs):
|
2812
2623
|
'''
|
2813
2624
|
嵌入命令 #reset 的执行函数,复位全部脚本。该命令不带参数。
|
@@ -2827,8 +2638,7 @@ class Session:
|
|
2827
2638
|
|
2828
2639
|
def handle_save(self, code: CodeLine = None, *args, **kwargs):
|
2829
2640
|
'''
|
2830
|
-
嵌入命令 #save
|
2831
|
-
系统变量包括 %line, %copy 和 %raw 三个,临时变量是指变量名已下划线开头的变量
|
2641
|
+
嵌入命令 #save 的执行函数,保存当前会话变量(系统变量除外)至文件。该命令不带参数。
|
2832
2642
|
该函数不应该在代码中直接调用。
|
2833
2643
|
|
2834
2644
|
使用:
|
@@ -2849,10 +2659,10 @@ class Session:
|
|
2849
2659
|
with open(file, "wb") as fp:
|
2850
2660
|
saved = dict()
|
2851
2661
|
saved.update(self._variables)
|
2852
|
-
keys = list(saved.keys())
|
2853
|
-
for key in keys:
|
2854
|
-
|
2855
|
-
|
2662
|
+
# keys = list(saved.keys())
|
2663
|
+
# for key in keys:
|
2664
|
+
# if key.startswith("%"):
|
2665
|
+
# saved.pop(key)
|
2856
2666
|
saved.pop("%line", None)
|
2857
2667
|
saved.pop("%raw", None)
|
2858
2668
|
saved.pop("%copy", None)
|
@@ -2951,7 +2761,7 @@ class Session:
|
|
2951
2761
|
if name in self.plugins.keys():
|
2952
2762
|
plugin = self.plugins[name]
|
2953
2763
|
self.info(f"{plugin.desc['DESCRIPTION']}, 版本 {plugin.desc['VERSION']} 作者 {plugin.desc['AUTHOR']} 发布日期 {plugin.desc['RELEASE_DATE']}", f"PLUGIN {name}")
|
2954
|
-
self.writetobuffer(plugin.help
|
2764
|
+
self.writetobuffer(plugin.help)
|
2955
2765
|
|
2956
2766
|
def handle_replace(self, code: CodeLine = None, *args, **kwargs):
|
2957
2767
|
'''
|
@@ -3130,8 +2940,8 @@ class Session:
|
|
3130
2940
|
|
3131
2941
|
示例:
|
3132
2942
|
- ``#log`` : 在当前会话窗口列出所有记录器状态
|
3133
|
-
- ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到
|
3134
|
-
- ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到
|
2943
|
+
- ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 name.log 文件的后端
|
2944
|
+
- ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 name.log 文件的后端
|
3135
2945
|
- ``#log start chat`` : 启动名为 chat 的记录器。该记录器以纯文本模式,记录代码中调用过该记录器 .log 进行记录的信息
|
3136
2946
|
- ``#log stop`` : 停止本会话默认记录器(记录器名为会话名)。
|
3137
2947
|
|
@@ -3189,19 +2999,8 @@ class Session:
|
|
3189
2999
|
elif (args[0] == "show"):
|
3190
3000
|
if len(args) > 1 and not args[1].startswith('-'):
|
3191
3001
|
file = args[1]
|
3192
|
-
|
3193
|
-
|
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
|
-
|
3002
|
+
self.application.logFileShown = file
|
3003
|
+
self.application.showLogInTab()
|
3205
3004
|
else:
|
3206
3005
|
self.application.show_logSelectDialog()
|
3207
3006
|
|