hyper-bot 0.75__tar.gz → 0.772__tar.gz

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.
Files changed (25) hide show
  1. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Adapters/OneBot.py +31 -43
  2. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Adapters/OneBotLib/Manager.py +43 -9
  3. hyper-bot-0.772/Hyper/Adapters/OneBotLib/Res.py +90 -0
  4. hyper-bot-0.772/Hyper/Adapters/Satori.py +94 -0
  5. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Configurator.py +5 -3
  6. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Errors.py +6 -0
  7. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Events.py +5 -1
  8. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Listener.py +2 -0
  9. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Manager.py +2 -0
  10. hyper-bot-0.772/Hyper/Network.py +156 -0
  11. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Segments.py +32 -92
  12. {hyper-bot-0.75/Hyper → hyper-bot-0.772/Hyper/Utils}/Logic.py +17 -21
  13. hyper-bot-0.772/Hyper/Utils/TypeExt.py +177 -0
  14. {hyper-bot-0.75 → hyper-bot-0.772}/PKG-INFO +1 -1
  15. {hyper-bot-0.75 → hyper-bot-0.772}/hyper_bot.egg-info/PKG-INFO +1 -1
  16. {hyper-bot-0.75 → hyper-bot-0.772}/hyper_bot.egg-info/SOURCES.txt +4 -2
  17. {hyper-bot-0.75 → hyper-bot-0.772}/setup.py +2 -2
  18. hyper-bot-0.75/Hyper/ModuleClass.py +0 -67
  19. hyper-bot-0.75/Hyper/Network.py +0 -77
  20. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/DataBase.py +0 -0
  21. {hyper-bot-0.75 → hyper-bot-0.772}/Hyper/Logger.py +0 -0
  22. {hyper-bot-0.75 → hyper-bot-0.772}/LICENSE +0 -0
  23. {hyper-bot-0.75 → hyper-bot-0.772}/hyper_bot.egg-info/dependency_links.txt +0 -0
  24. {hyper-bot-0.75 → hyper-bot-0.772}/hyper_bot.egg-info/top_level.txt +0 -0
  25. {hyper-bot-0.75 → hyper-bot-0.772}/setup.cfg +0 -0
@@ -1,15 +1,15 @@
1
1
  import json
2
- import queue
3
2
  import threading
4
3
  import time
5
4
  import asyncio
6
5
  import os
7
6
  from typing import Union
8
7
 
9
- from Hyper import Configurator, Errors, Logger, Logic, Manager, Network, Events
8
+ from Hyper import Errors, Network, Events
9
+ from Hyper.Utils import Logic
10
+ from Hyper.Manager import reports
10
11
  from Hyper.Events import *
11
12
 
12
- reports = queue.Queue()
13
13
  config = Configurator.cm.get_cfg()
14
14
  logger = Logger.Logger()
15
15
  logger.set_level(config.log_level)
@@ -24,20 +24,13 @@ class Actions:
24
24
  self.connection = cnt_i
25
25
 
26
26
  def __getattr__(self, item) -> callable:
27
- def wrapper(no_return: bool, **kwargs) -> Manager.Ret | None:
28
- if no_return:
29
- Manager.Packet(
30
- str(item),
31
- **kwargs
32
- ).send_to(self.connection)
33
- return None
34
- else:
35
- packet = Manager.Packet(
36
- str(item),
37
- **kwargs
38
- )
39
- packet.send_to(self.connection)
40
- return get_ret(packet.echo)
27
+ def wrapper(**kwargs) -> str:
28
+ packet = Manager.Packet(
29
+ str(item),
30
+ **kwargs
31
+ )
32
+ packet.send_to(self.connection)
33
+ return packet.echo
41
34
 
42
35
  return wrapper
43
36
 
@@ -59,8 +52,17 @@ class Actions:
59
52
  )
60
53
  else:
61
54
  raise Errors.ArgsInvalidError("'send' API requires 'group_id' or 'user_id' but none of them are provided.")
62
- packet.send_to(self.connection)
63
- return get_ret(packet.echo)
55
+ retried = 0
56
+ while 1:
57
+ packet.send_to(self.connection)
58
+ result = Manager.Ret.fetch(packet.echo)
59
+ if result.ret_code != 0 or (4 <= len(str(result.data.message_id)) <= 6):
60
+ retried += 1
61
+ if retried >= 5:
62
+ return result
63
+ await asyncio.sleep(1)
64
+ else:
65
+ return result
64
66
 
65
67
  @Logger.AutoLogAsync.register(Logger.AutoLog.templates().recall, logger)
66
68
  async def del_message(self, message_id: int) -> None:
@@ -90,13 +92,13 @@ class Actions:
90
92
  async def get_login_info(self) -> Manager.Ret:
91
93
  packet = Manager.Packet("get_login_info")
92
94
  packet.send_to(self.connection)
93
- return get_ret(packet.echo)
95
+ return Manager.Ret.fetch(packet.echo)
94
96
 
95
97
  @Logic.Cacher().cache_async
96
98
  async def get_version_info(self) -> Manager.Ret:
97
99
  packet = Manager.Packet("get_version_info")
98
100
  packet.send_to(self.connection)
99
- return get_ret(packet.echo)
101
+ return Manager.Ret.fetch(packet.echo)
100
102
 
101
103
  async def send_forward_msg(self, message: Manager.Message) -> Manager.Ret:
102
104
  packet = Manager.Packet(
@@ -104,7 +106,7 @@ class Actions:
104
106
  messages=await message.get()
105
107
  )
106
108
  packet.send_to(self.connection)
107
- return get_ret(packet.echo)
109
+ return Manager.Ret.fetch(packet.echo)
108
110
 
109
111
  async def send_group_forward_msg(self, group_id: int, message: Manager.Message) -> Manager.Ret:
110
112
  packet = Manager.Packet(
@@ -113,7 +115,7 @@ class Actions:
113
115
  messages=await message.get()
114
116
  )
115
117
  packet.send_to(self.connection)
116
- return get_ret(packet.echo)
118
+ return Manager.Ret.fetch(packet.echo)
117
119
 
118
120
  @Logger.AutoLogAsync.register(Logger.AutoLog.templates().set_req, logger)
119
121
  async def set_group_add_request(self, flag: str, sub_type: str, approve: bool, reason: str = "Refused") -> None:
@@ -133,7 +135,7 @@ class Actions:
133
135
  no_cache=True,
134
136
  )
135
137
  packet.send_to(self.connection)
136
- return get_ret(packet.echo)
138
+ return Manager.Ret.fetch(packet.echo)
137
139
 
138
140
  @Logic.Cacher().cache_async
139
141
  async def get_group_member_info(self, group_id: int, user_id: int) -> Manager.Ret:
@@ -144,7 +146,7 @@ class Actions:
144
146
  no_cache=True
145
147
  )
146
148
  packet.send_to(self.connection)
147
- return get_ret(packet.echo)
149
+ return Manager.Ret.fetch(packet.echo)
148
150
 
149
151
  @Logic.Cacher().cache_async
150
152
  async def get_group_info(self, group_id: int) -> Manager.Ret:
@@ -154,12 +156,12 @@ class Actions:
154
156
  no_cache=True
155
157
  )
156
158
  packet.send_to(self.connection)
157
- return get_ret(packet.echo)
159
+ return Manager.Ret.fetch(packet.echo)
158
160
 
159
161
  async def get_status(self) -> Manager.Ret:
160
162
  packet = Manager.Packet("get_status")
161
163
  packet.send_to(self.connection)
162
- return get_ret(packet.echo)
164
+ return Manager.Ret.fetch(packet.echo)
163
165
 
164
166
  @Logger.AutoLogAsync.register(Logger.AutoLog.templates().set_ess, logger)
165
167
  async def set_essence_msg(self, message_id: int) -> None:
@@ -182,7 +184,7 @@ class Actions:
182
184
  message_id=msg_id
183
185
  )
184
186
  packet.send_to(self.connection)
185
- return get_ret(packet.echo)
187
+ return Manager.Ret.fetch(packet.echo)
186
188
 
187
189
 
188
190
  async def tester(message_data: Event, actions: Actions) -> None:
@@ -191,7 +193,7 @@ async def tester(message_data: Event, actions: Actions) -> None:
191
193
 
192
194
  async def __handler(data: dict, actions: Actions) -> None:
193
195
  if data.get("echo") is not None:
194
- reports.put(Manager.Ret(data))
196
+ reports.put(data)
195
197
  elif data.get("post_type") == "meta_event" or data.get("user_id") == data.get("self_id"):
196
198
  pass
197
199
  else:
@@ -208,7 +210,6 @@ async def __handler(data: dict, actions: Actions) -> None:
208
210
 
209
211
 
210
212
  handler: callable = tester
211
- connection: callable = tester
212
213
 
213
214
 
214
215
  def reg(func: callable):
@@ -216,20 +217,7 @@ def reg(func: callable):
216
217
  handler = func
217
218
 
218
219
 
219
- def get_ret(echo: str) -> Manager.Ret:
220
- old = None
221
- while True:
222
- content: Manager.Ret = reports.get()
223
- if old is not None:
224
- reports.put(old)
225
- if content.echo == echo:
226
- return content
227
- else:
228
- old = content
229
-
230
-
231
220
  def run():
232
- global connection
233
221
  try:
234
222
  if handler is tester:
235
223
  raise Errors.ListenerNotRegisteredError("No handler registered")
@@ -1,11 +1,13 @@
1
- from Hyper import Logic, Configurator, Logger, Network
2
- from Hyper.Logger import levels
3
- from Hyper.Segments import *
1
+ import Hyper.Utils.TypeExt
2
+ from Hyper import Configurator, Logger, Network, Segments
3
+ from Hyper.Utils import Logic
4
4
 
5
5
  from typing import Union
6
- import inspect
6
+ import queue
7
7
  import random
8
+ import json
8
9
 
10
+ reports = queue.Queue()
9
11
  config = Configurator.cm.get_cfg()
10
12
  logger = Logger.Logger()
11
13
  logger.set_level(config.log_level)
@@ -33,7 +35,30 @@ class Packet:
33
35
  connection.send(self.endpoint, payload, self.echo)
34
36
 
35
37
 
38
+ class MessageBuilder:
39
+ def __init__(self):
40
+ self.sgs = []
41
+
42
+ def __getattr__(self, item):
43
+ if item == "build":
44
+ def build() -> Message:
45
+ return Message(*self.sgs)
46
+
47
+ return build
48
+
49
+ elif item in Segments.message_types.keys():
50
+ def wrapper(*args, **kwargs):
51
+ self.sgs.append(Segments.message_types[item]["type"](*args, **kwargs))
52
+ return self
53
+
54
+ return wrapper
55
+ else:
56
+ return None
57
+
58
+
36
59
  class Message:
60
+ builder = MessageBuilder()
61
+
37
62
  def __init__(self, *args):
38
63
  if len(args) == 1 and isinstance(args[0], list):
39
64
  contents = args[0]
@@ -47,10 +72,7 @@ class Message:
47
72
  self.contents.append(content)
48
73
 
49
74
  async def get(self) -> list:
50
- ret = []
51
- for i in self.contents:
52
- ret.append(i.to_json())
53
- return ret
75
+ return self.get_sync()
54
76
 
55
77
  def get_sync(self) -> list:
56
78
  ret = []
@@ -93,5 +115,17 @@ class Ret:
93
115
  def __init__(self, json_data: dict):
94
116
  self.status = json_data["status"]
95
117
  self.ret_code = json_data["retcode"]
96
- self.data = json_data.get("data")
118
+ self.data = Hyper.Utils.TypeExt.ObjectedDict(json_data.get("data"))
97
119
  self.echo = json_data.get("echo")
120
+
121
+ @classmethod
122
+ def fetch(cls, echo: str) -> "Ret":
123
+ old = None
124
+ while True:
125
+ content = reports.get()
126
+ if old is not None:
127
+ reports.put(old)
128
+ if content["echo"] == echo:
129
+ return cls(content)
130
+ else:
131
+ old = content
@@ -0,0 +1,90 @@
1
+ message_types = {}
2
+
3
+ def segment_builder(sg_type: str, summary_tmp: str = None):
4
+ # print(inspect.get_annotations(cls))
5
+ def inner_builder(cls):
6
+ var = dict(vars(cls))
7
+ anns: dict = var.get("__annotations__", False) or dict()
8
+
9
+ def init(self, *args, **kwargs):
10
+ arg = {}
11
+ if len(args) > 0:
12
+ for i in args:
13
+ arg[list(anns.keys())[list(args).index(i)]] = i
14
+
15
+ if len(kwargs) > 0:
16
+ for i in kwargs:
17
+ try:
18
+ arg[i] = anns[i](kwargs[i])
19
+ except TypeError:
20
+ arg[i] = kwargs[i]
21
+ new_arg = arg.copy()
22
+
23
+ if len(anns) > len(arg):
24
+ for i in anns.keys():
25
+ if i not in arg.keys():
26
+ if i not in var.keys():
27
+ new_arg[i] = None
28
+ continue
29
+ if not isinstance(var[i], anns[i]):
30
+ new_arg[i] = anns[i](var[i])
31
+ else:
32
+ new_arg[i] = var[i]
33
+
34
+ for i in new_arg:
35
+ setattr(self, i, new_arg[i])
36
+
37
+ cls.__init__ = init
38
+
39
+ def to_json(self) -> dict:
40
+ base = {"type": sg_type, "data": {}}
41
+ for i in anns:
42
+ if getattr(self, i) is None:
43
+ continue
44
+ if not isinstance(getattr(self, i), anns[i]):
45
+ base["data"][i] = anns[i](getattr(self, i))
46
+ else:
47
+ base["data"][i] = getattr(self, i)
48
+ # try:
49
+ # base["data"][i] = anns[i](getattr(self, i))
50
+ # except TypeError:
51
+ # base["data"][i] = getattr(self, i)
52
+ return base
53
+
54
+ cls.to_json = to_json
55
+
56
+ def to_str(self) -> str:
57
+ text = summary_tmp
58
+ if text is None:
59
+ text = "[]"
60
+ if "<" not in text and ">" not in text:
61
+ return text
62
+
63
+ for i in anns:
64
+ if f"<{i}>" in summary_tmp:
65
+ try:
66
+ v = self.__getattribute__(i)
67
+ except AttributeError:
68
+ v = None
69
+ text = text.replace(f"<{i}>", str(v))
70
+
71
+ return text
72
+
73
+ cls.__str__ = to_str if cls().__str__() == "__not_set__" else cls.__str__
74
+
75
+ message_types[sg_type] = {
76
+ "type": cls,
77
+ "args": list(anns.keys())
78
+ }
79
+
80
+ return cls
81
+
82
+ return inner_builder
83
+
84
+
85
+ class Base:
86
+ def __init__(self, *args, **kwargs): ...
87
+
88
+ def to_json(self) -> dict: ...
89
+
90
+ def __str__(self) -> str: return "__not_set__"
@@ -0,0 +1,94 @@
1
+ from Hyper.Adapters.OneBot import *
2
+ from Hyper.Errors import *
3
+
4
+
5
+ class Actions(Actions):
6
+ def __init__(self, cnt: Union[Network.WebsocketConnection, Network.HTTPConnection, Network.SatoriConnection]):
7
+ self.connection = cnt
8
+
9
+ class CustomAction:
10
+ def __init__(self,
11
+ cnt_i: Union[Network.WebsocketConnection, Network.HTTPConnection, Network.SatoriConnection]):
12
+ self.connection = cnt_i
13
+
14
+ def __getattr__(self, item) -> callable:
15
+ def wrapper(**kwargs) -> str:
16
+ packet = Manager.Packet(
17
+ str(item),
18
+ **kwargs
19
+ )
20
+ packet.send_to(self.connection)
21
+ return packet.echo
22
+
23
+ return wrapper
24
+
25
+ self.custom = CustomAction(self.connection)
26
+
27
+
28
+ async def __handler(data: dict, actions: Actions) -> None:
29
+ if data["op"] == 2:
30
+ pass
31
+ else:
32
+ # task = asyncio.create_task(handler(Events.em.new(data), actions))
33
+ # timed = 0
34
+ #
35
+ # while not task.done():
36
+ # await asyncio.sleep(0.1)
37
+ # timed += 0.1
38
+ # if timed >= 30:
39
+ # task.cancel()
40
+ # logger.log(f"处理{task.get_name()}超时", level=Logger.levels.ERROR)
41
+ # break
42
+ print(data)
43
+
44
+
45
+ def reg(func: callable):
46
+ global handler
47
+ handler = func
48
+
49
+
50
+ def run():
51
+ try:
52
+ if handler is tester:
53
+ raise Errors.ListenerNotRegisteredError("No handler registered")
54
+ # connection = websocket.WebSocket()
55
+ if isinstance(config.connection, Configurator.WSConnectionC):
56
+ connection = Network.SatoriConnection(
57
+ config.connection.host, config.connection.port, config.connection.token
58
+ )
59
+ else:
60
+ raise ConfigError
61
+ retried = 0
62
+ while True:
63
+ try:
64
+ connection.connect()
65
+ except ConnectionRefusedError or TimeoutError:
66
+ if retried >= config.connection.retries:
67
+ logger.log(f"重试次数达到最大值({config.connection.retries}),退出", level=Logger.levels.CRITICAL)
68
+ break
69
+
70
+ logger.log(f"连接建立失败,3秒后重试({retried}/{config.connection.retries})",
71
+ level=Logger.levels.WARNING)
72
+ retried += 1
73
+ time.sleep(3)
74
+ continue
75
+ logger.log("成功建立连接", level=Logger.levels.INFO)
76
+ retried = 0
77
+ actions = Actions(connection)
78
+ while True:
79
+ try:
80
+ data = connection.recv()
81
+ except ConnectionResetError:
82
+ logger.log("连接断开", level=Logger.levels.ERROR)
83
+ break
84
+ except json.decoder.JSONDecodeError:
85
+ logger.log("收到错误的JSON内容", level=Logger.levels.ERROR)
86
+ threading.Thread(target=lambda: asyncio.run(__handler(data, actions))).start()
87
+ except KeyboardInterrupt:
88
+ logger.log("正在退出(Ctrl+C)", level=Logger.levels.WARNING)
89
+ try:
90
+ connection.close()
91
+ except:
92
+ pass
93
+ os._exit(0)
94
+
@@ -1,13 +1,14 @@
1
1
  import typing
2
2
 
3
- from Hyper import Logic
3
+ from Hyper.Utils import Logic
4
4
 
5
5
 
6
6
  class WSConnectionC:
7
- def __init__(self, host: str, port: int, retries: int = 0):
7
+ def __init__(self, host: str, port: int, retries: int = 0, satori_token: str = None):
8
8
  self.host: str = host
9
9
  self.port: int = port
10
10
  self.retries: int = retries
11
+ self.token: str = satori_token
11
12
 
12
13
 
13
14
  class HTTPConnectionC:
@@ -55,7 +56,8 @@ class Config:
55
56
  self.connection = WSConnectionC(
56
57
  config_json["Connection"]["host"],
57
58
  config_json["Connection"]["port"],
58
- config_json["Connection"]["retries"]
59
+ config_json["Connection"]["retries"],
60
+ config_json["Connection"]["satori_token"]
59
61
  )
60
62
  elif config_json["Connection"]["mode"] == "HTTP":
61
63
  self.connection = HTTPConnectionC(
@@ -16,3 +16,9 @@ class ListenerNotRegisteredError(Exception):
16
16
  class ArgsInvalidError(Exception):
17
17
  def __init__(self, message: str = None):
18
18
  super().__init__(message)
19
+
20
+
21
+ class ConfigError(Exception):
22
+ def __init__(self, message: str = None):
23
+ super().__init__(message)
24
+
@@ -1,4 +1,5 @@
1
1
  from Hyper import Configurator, Logger, Manager
2
+ from Hyper.Utils.TypeExt import Integer
2
3
  from Hyper.Segments import message_types
3
4
  from Hyper.Logger import levels
4
5
 
@@ -14,10 +15,12 @@ class EventManager:
14
15
  "notice": {},
15
16
  "request": {}
16
17
  }
18
+ self.events = []
17
19
 
18
20
  def reg(self, type_of: str, str_eql: str) -> callable:
19
21
  def wrapper(cls):
20
22
  self.event_lis[type_of][str_eql] = cls
23
+ self.events.append(cls)
21
24
  return cls
22
25
 
23
26
  return wrapper
@@ -88,7 +91,7 @@ class Event:
88
91
  self.user_id = data.get("user_id")
89
92
  self.group_id = data.get("group_id")
90
93
 
91
- self.is_owner = int(self.user_id) in config.owner
94
+ self.is_owner = Integer.convert_from(self.user_id) in config.owner
92
95
  self.servicing = False
93
96
  self.blocked = True if self.user_id in config.black_list or self.group_id in config.black_list else False
94
97
  self.is_silent = self.user_id in config.silents or self.group_id in config.silents or 0 in config.silents
@@ -103,6 +106,7 @@ class MessageEvent(Event):
103
106
  self.sub_type = data.get("sub_type")
104
107
  self.message_id = str(data.get("message_id"))
105
108
  self.message = gen_message(data=data)
109
+ self.msg_str = str(self.message)
106
110
 
107
111
 
108
112
  @em.reg("message", "private")
@@ -4,4 +4,6 @@ config = Configurator.cm.get_cfg()
4
4
 
5
5
  if config.protocol == "OneBot":
6
6
  from Hyper.Adapters.OneBot import *
7
+ elif config.protocol == "Satori":
8
+ from Hyper.Adapters.Satori import *
7
9
  servicing = []
@@ -4,3 +4,5 @@ config = cm.get_cfg()
4
4
 
5
5
  if config.protocol == "OneBot":
6
6
  from Hyper.Adapters.OneBotLib.Manager import *
7
+ elif config.protocol == "Satori":
8
+ from Hyper.Adapters.SatoriLib.Manager import *
@@ -0,0 +1,156 @@
1
+ import asyncio
2
+ import time
3
+ import websocket
4
+ import httpx
5
+ import queue
6
+ import flask
7
+ import traceback
8
+ import json
9
+ import logging
10
+ import threading
11
+
12
+
13
+ class WebsocketConnection:
14
+ def __init__(self, url: str):
15
+ self.ws = websocket.WebSocket()
16
+ self.url = url
17
+
18
+ def connect(self) -> None:
19
+ self.ws.connect(self.url)
20
+
21
+ def send(self, message: str) -> None:
22
+ self.ws.send(message)
23
+
24
+ def close(self) -> None:
25
+ self.ws.close()
26
+
27
+ def recv(self) -> dict:
28
+ return json.loads(self.ws.recv())
29
+
30
+
31
+ class HTTPConnection:
32
+ def __init__(self, url: str, listener_url: str):
33
+ self.url = url
34
+ listener_url = listener_url.replace("http://", "")
35
+ listener_url = listener_url.replace("https://", "")
36
+ self.listener_url = listener_url.split(":")[0]
37
+ try:
38
+ self.port = int(listener_url.split(":")[1])
39
+ except IndexError:
40
+ self.port = 8080
41
+ self.app = flask.Flask(__name__)
42
+ self.app.config["LOGGER_HANDLER_POLICY"] = "never"
43
+ logging.getLogger("werkzeug").setLevel(logging.ERROR)
44
+ self.reports = queue.Queue()
45
+
46
+ self.listener_started = False
47
+
48
+ def __start_listener(self) -> None:
49
+ @self.app.route("/", methods=["POST"])
50
+ def listener():
51
+ self.reports.put(flask.request.json)
52
+ return {}
53
+
54
+ # self.app.run(host=self.listener_url, port=self.port)
55
+
56
+ threading.Thread(target=lambda: self.app.run(host=self.listener_url, port=self.port)).start()
57
+ self.listener_started = True
58
+
59
+ def connect(self) -> None:
60
+ if not self.listener_started:
61
+ self.__start_listener()
62
+ httpx.post(self.url)
63
+ traceback.print_exc()
64
+
65
+ def recv(self) -> dict:
66
+ return self.reports.get()
67
+
68
+ def send(self, endpoint: str, data: dict, echo: str) -> None:
69
+ response = httpx.post(f"{self.url}/{endpoint}", json=data)
70
+ res = response.json()
71
+ res["echo"] = echo
72
+ self.reports.put(res)
73
+
74
+ @staticmethod
75
+ def close() -> None:
76
+ shutdown_func = flask.request.environ.get('werkzeug.server.shutdown')
77
+ if shutdown_func is None:
78
+ raise RuntimeError('Not running with the Werkzeug Server')
79
+ shutdown_func()
80
+
81
+
82
+ class SatoriConnection:
83
+ def __init__(self, host: str, port: int, token: str = None):
84
+ self.ws = websocket.WebSocket()
85
+ self.host = host
86
+ self.port = port
87
+ self.token = token
88
+ self.reports = queue.Queue()
89
+
90
+ def heart_beat(self) -> None:
91
+ while 1:
92
+ time.sleep(10)
93
+ self.ws.send(json.dumps({"op": 1, "body": {}}))
94
+
95
+ def connect(self) -> None:
96
+ self.ws.connect(f"ws://{self.host}:{self.port}/v1/events")
97
+ payload = {
98
+ "op": 3,
99
+ "body": {
100
+ "token": self.token
101
+ }
102
+ }
103
+ self.ws.send(json.dumps(payload))
104
+ res = json.loads(self.ws.recv())
105
+ if res["op"] == 4:
106
+ threading.Thread(target=self.heart_beat).start()
107
+ else:
108
+ raise ConnectionError("连接失败")
109
+
110
+ def send(self, payload: dict, echo: str = None) -> None:
111
+ response = httpx.post(f"http://{self.host}:{self.port}", json=payload)
112
+ try:
113
+ data = response.json()
114
+ data["echo"] = echo
115
+ self.reports.put(data)
116
+ except:
117
+ pass
118
+
119
+ def close(self) -> None:
120
+ pass
121
+
122
+ def recv(self) -> dict:
123
+ return json.loads(self.ws.recv())
124
+
125
+ #
126
+ # class KritorConnection:
127
+ # def __init__(self, host: str, port: int, account: str, ticket: str):
128
+ # self.channel = grpc.insecure_channel(f"{host}:{port}")
129
+ # self.account = account
130
+ # self.ticket = ticket
131
+ #
132
+ # def connect(self) -> None:
133
+ # auth_stub = AuthenticationServiceStub(self.channel)
134
+ # response = auth_stub.Authenticate(
135
+ # AuthenticateRequest(
136
+ # account=self.account,
137
+ # ticket=self.ticket
138
+ # )
139
+ # )
140
+ # if response.AuthenticateResponseCode != 0:
141
+ # raise ConnectionError("鉴权失败")
142
+ #
143
+ # def send(self, stub, payload: dict, echo: str = None) -> None:
144
+ # response = httpx.post(f"http://{self.host}:{self.port}", json=payload)
145
+ # try:
146
+ # data = response.json()
147
+ # data["echo"] = echo
148
+ # self.reports.put(data)
149
+ # except:
150
+ # pass
151
+ #
152
+ # def close(self) -> None:
153
+ # pass
154
+ #
155
+ # def recv(self) -> dict:
156
+ # return json.loads(self.ws.recv())
@@ -1,98 +1,36 @@
1
1
  import json
2
+ import os.path
2
3
  import typing
3
4
  import uuid
4
5
 
5
6
  from Hyper.Errors import *
7
+ from Hyper.Configurator import cm
6
8
 
7
- message_types = {}
8
-
9
-
10
- def segment_builder(sg_type: str, summary_tmp: str = None):
11
- # print(inspect.get_annotations(cls))
12
- def inner_builder(cls):
13
- var = dict(vars(cls))
14
- anns: dict = var.get("__annotations__", False) or dict()
15
- arg = {}
16
-
17
- def init(self, *args, **kwargs):
18
- if len(args) > 0:
19
- for i in args:
20
- arg[list(anns.keys())[list(args).index(i)]] = i
21
-
22
- if len(kwargs) > 0:
23
- for i in kwargs:
24
- try:
25
- arg[i] = anns[i](kwargs[i])
26
- except TypeError:
27
- arg[i] = kwargs[i]
28
- new_arg = arg.copy()
29
-
30
- if len(anns) > len(arg):
31
- for i in anns.keys():
32
- if i not in arg.keys():
33
- if i not in var.keys():
34
- new_arg[i] = None
35
- continue
36
- if not isinstance(var[i], anns[i]):
37
- new_arg[i] = anns[i](var[i])
38
- else:
39
- new_arg[i] = var[i]
40
-
41
- for i in new_arg:
42
- setattr(self, i, new_arg[i])
43
-
44
- cls.__init__ = init
45
-
46
- def to_json(self) -> dict:
47
- base = {"type": sg_type, "data": {}}
48
- for i in anns:
49
- if not isinstance(getattr(self, i), anns[i]):
50
- base["data"][i] = anns[i](getattr(self, i))
51
- else:
52
- base["data"][i] = getattr(self, i)
53
- # try:
54
- # base["data"][i] = anns[i](getattr(self, i))
55
- # except TypeError:
56
- # base["data"][i] = getattr(self, i)
57
- return base
58
-
59
- cls.to_json = to_json
60
-
61
- def to_str(self) -> str:
62
- text = summary_tmp
63
- if text is None:
64
- text = "[]"
65
- if "<" not in text and ">" not in text:
66
- return text
67
-
68
- for i in anns:
69
- if f"<{i}>" in summary_tmp:
70
- try:
71
- v = self.__getattribute__(i)
72
- except AttributeError:
73
- v = None
74
- text = text.replace(f"<{i}>", str(v))
75
-
76
- return text
77
-
78
- cls.__str__ = to_str if cls().__str__() == "__not_set__" else cls.__str__
79
-
80
- message_types[sg_type] = {
81
- "type": cls,
82
- "args": list(anns.keys())
83
- }
84
-
85
- return cls
86
-
87
- return inner_builder
88
-
89
-
90
- class Base:
91
- def __init__(self, *args, **kwargs): ...
9
+ config = cm.get_cfg()
10
+ if config.protocol == "OneBot":
11
+ from Hyper.Adapters.OneBotLib.Res import segment_builder, Base, message_types
12
+ elif config.protocol == "Satori":
13
+ # from Hyper.Adapters.SatoriLib.Res import segment_builder, Base, message_types
14
+ pass
92
15
 
93
- def to_json(self) -> dict: ...
94
16
 
95
- def __str__(self) -> str: return "__not_set__"
17
+ class MediaSeg(Base):
18
+ @classmethod
19
+ def build(cls, file: str):
20
+ if file.startswith("http") or file.startswith("file:") or file.startswith("base64:"):
21
+ return cls(file=file)
22
+ else:
23
+ if os.path.isfile(file):
24
+ if os.path.isabs(file):
25
+ res = cls()
26
+ res.file = f"file://{file}"
27
+ return res
28
+ else:
29
+ res = cls()
30
+ res.file = f"file://{os.path.abspath(file)}"
31
+ return res
32
+ else:
33
+ return None
96
34
 
97
35
 
98
36
  @segment_builder("text", "<text>")
@@ -101,9 +39,9 @@ class Text(Base):
101
39
 
102
40
 
103
41
  @segment_builder("image", "[图片]")
104
- class Image(Base):
42
+ class Image(MediaSeg):
105
43
  file: str
106
- url: str = ""
44
+ url: str
107
45
  summary: str = "[图片]"
108
46
 
109
47
 
@@ -129,13 +67,15 @@ class Location(Base):
129
67
 
130
68
 
131
69
  @segment_builder("record", "[语音]")
132
- class Record(Base):
70
+ class Record(MediaSeg):
133
71
  file: str
72
+ url: str
134
73
 
135
74
 
136
75
  @segment_builder("video", "[视频]")
137
- class Video(Base):
76
+ class Video(MediaSeg):
138
77
  file: str
78
+ url: str
139
79
 
140
80
 
141
81
  @segment_builder("poke", "[拍一拍]")
@@ -296,6 +236,6 @@ class Rps(Base):
296
236
  class Music(Base):
297
237
  type: str
298
238
  id: str = None
299
- url: str = None
239
+ url: str
300
240
  audio: str = None
301
241
  title: str = None
@@ -3,6 +3,7 @@ import os
3
3
  import shutil
4
4
  import traceback
5
5
  import asyncio
6
+ from typing import Union
6
7
  import aiohttp
7
8
  import time
8
9
  import requests
@@ -103,26 +104,13 @@ class ErrorHandler:
103
104
  return wrapper
104
105
 
105
106
 
106
- class Random:
107
- def __init__(self, seed: int = None):
108
- self.seed = seed
109
-
110
- def random(self) -> int:
111
- self.seed = self.seed ** 2
112
- self.seed = int(str(self.seed)[:7])
113
- return int(str(self.seed)[1:5])
114
-
115
- def __call__(self) -> int:
116
- return self.random()
117
-
118
-
119
107
  class FileManager:
120
108
  @staticmethod
121
109
  def create(path: str) -> bool:
122
110
  try:
123
111
  with open(path, "w") as f:
124
112
  f.write("")
125
- except (FileExistsError | OSError | IOError):
113
+ except (FileExistsError, OSError, IOError):
126
114
  return False
127
115
 
128
116
  return True
@@ -144,7 +132,7 @@ class FileManager:
144
132
 
145
133
  @staticmethod
146
134
  @Cacher(7).cache
147
- def read_as_json(path: str, encoding: str = "utf-8") -> dict | list:
135
+ def read_as_json(path: str, encoding: str = "utf-8") -> Union[list, dict]:
148
136
  with open(path, "r", encoding=encoding) as f:
149
137
  return json.load(f)
150
138
 
@@ -159,7 +147,7 @@ class FileManager:
159
147
  try:
160
148
  os.remove(path)
161
149
  return True
162
- except (FileNotFoundError | OSError | IOError):
150
+ except (FileNotFoundError, OSError, IOError):
163
151
  return False
164
152
 
165
153
  @staticmethod
@@ -167,7 +155,7 @@ class FileManager:
167
155
  try:
168
156
  shutil.copy(path1, path2)
169
157
  return True
170
- except (FileNotFoundError | OSError | IOError):
158
+ except (FileNotFoundError, OSError, IOError):
171
159
  return False
172
160
 
173
161
 
@@ -245,10 +233,12 @@ class TempDownloader:
245
233
  self.index = index
246
234
  self.silent = silent
247
235
 
248
- async def get_bytes(self) -> dict[str, bytes]:
236
+ async def get_bytes(self, ua: str = None) -> dict[str, bytes]:
249
237
  result_to_re = {}
250
238
  this: bytes = bytes()
251
239
  headers = {"Range": f"bytes={self.part[0]}-{self.part[1]}"}
240
+ if ua:
241
+ headers["User-Agent"] = ua
252
242
 
253
243
  async with aiohttp.ClientSession() as session:
254
244
  async with session.get(self.url, headers=headers) as resp:
@@ -296,10 +286,16 @@ class Downloader:
296
286
  result[-1][-1] = size - 1
297
287
  return result
298
288
 
299
- async def download(self):
289
+ async def download(self, ua: str = None):
300
290
  if not self.check():
301
291
  raise Exception
302
- response = requests.get(self.url, stream=True, verify=False)
292
+ if ua:
293
+ headers = {
294
+ "User-Agent": ua
295
+ }
296
+ response = requests.get(self.url, stream=True, verify=False, headers=headers)
297
+ else:
298
+ response = requests.get(self.url, stream=True, verify=False)
303
299
  if response.status_code != 200:
304
300
  raise ConnectionError
305
301
 
@@ -326,7 +322,7 @@ class Downloader:
326
322
  for i in parts:
327
323
  _ = TempDownloader(url=self.url, part=i, index=parts.index(i), silent=self.silent)
328
324
 
329
- tasks.append(asyncio.create_task(_.get_bytes()))
325
+ tasks.append(asyncio.create_task(_.get_bytes(ua=ua)))
330
326
 
331
327
  await asyncio.gather(*tasks)
332
328
  for i in tasks:
@@ -0,0 +1,177 @@
1
+ import re
2
+ import json
3
+ from typing import Union
4
+
5
+
6
+ class ObjectedDict:
7
+ def __init__(self, content: dict = None):
8
+ if content is None:
9
+ self.__content = dict()
10
+ else:
11
+ self.__content = content
12
+
13
+ def __getattr__(self, attr):
14
+ if attr == "_ObjectedDict__content" or attr == "raw":
15
+ return self.__content
16
+ else:
17
+ att = self.__content.get(attr)
18
+ if isinstance(att, dict):
19
+ return ObjectedDict(att)
20
+ else:
21
+ return att
22
+
23
+ def __setattr__(self, attr, value):
24
+ if attr == "_ObjectedDict__content":
25
+ super().__setattr__(attr, value)
26
+ else:
27
+ self.__content[attr] = value
28
+
29
+ def __getitem__(self, item):
30
+ return self.__content.get(item)
31
+
32
+ def __setitem__(self, key, value):
33
+ if self.__content.get(key):
34
+ self.__content[key] = value
35
+
36
+ def __str__(self) -> str:
37
+ return self.__content.__str__()
38
+
39
+
40
+ class Char(str):
41
+ @classmethod
42
+ def convert_from(cls, obj: Union[str, "String"]):
43
+ if len(obj) != 1:
44
+ raise TypeError("Char is not fxxking String!")
45
+ else:
46
+ return cls(obj)
47
+
48
+ @property
49
+ def width(self) -> int:
50
+ char = self
51
+ if len(char) != 1:
52
+ raise TypeError("String too long")
53
+ o = ord(char)
54
+ widths = [
55
+ (126, 1), (159, 0), (687, 1), (710, 0), (711, 1),
56
+ (727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),
57
+ (4347, 1), (4447, 1.75), (7467, 1), (7521, 0), (8369, 1),
58
+ (8426, 0), (9000, 1), (9002, 1.75), (11021, 1), (12350, 1.75),
59
+ (12351, 1), (12438, 1.75), (12442, 0), (19893, 1.75), (19967, 1),
60
+ (55203, 1.75), (63743, 1), (64106, 1.75), (65039, 1), (65059, 0),
61
+ (65131, 1.75), (65279, 1), (65376, 1.75), (65500, 1), (65510, 1.75),
62
+ (120831, 1), (262141, 1.75), (1114109, 1),
63
+ ]
64
+ if o == 0xe or o == 0xf:
65
+ return 0
66
+ for num, wid in widths:
67
+ if o <= num:
68
+ return wid
69
+ return 1
70
+
71
+
72
+ class String(str):
73
+ def cmdl_parse(self) -> list:
74
+ args = []
75
+ temp = ""
76
+ in_sub = False
77
+ last_sig = ""
78
+ for i in (self if self.endswith(" ") else self + " "):
79
+ if in_sub and i == " ":
80
+ temp += i
81
+ elif not in_sub and i == " ":
82
+ args.append(temp)
83
+ temp = ""
84
+ elif i == '"' or i == "'":
85
+ if not in_sub:
86
+ in_sub = True
87
+ last_sig = i
88
+ elif i == last_sig:
89
+ in_sub = False
90
+ else:
91
+ temp += i
92
+
93
+ res = []
94
+
95
+ for i in args:
96
+ if "=" in i:
97
+ if " " in i:
98
+ continue
99
+ index = args.index(i)
100
+ new = args[index].split("=", 1)
101
+ args[index] = {new[0]: new[1]}
102
+
103
+ for i in args:
104
+ if str(i) != "":
105
+ if isinstance(i, dict):
106
+ res.append(i)
107
+ else:
108
+ res.append(String(i))
109
+
110
+ del temp, in_sub, last_sig, args
111
+
112
+ return res
113
+
114
+ def match(self, par: str) -> bool:
115
+ return True if re.match(par, self) else False
116
+
117
+ def clear(self) -> "String":
118
+ if len(self) != 0:
119
+ return String("")
120
+ else:
121
+ return self
122
+
123
+ def to_json(self) -> Union[list, dict]:
124
+ return json.loads(self)
125
+
126
+ def format(self, w_p_l: int = 110) -> "String":
127
+ c_lis = list(map(Char.convert_from, list(self)))
128
+ lines = []
129
+ temp_line = ""
130
+ temp_length = 0
131
+ for i in c_lis:
132
+ if i == "\n":
133
+ lines.append(temp_line)
134
+ temp_line = ""
135
+ temp_length = 0
136
+ temp_line += i
137
+ temp_length += i.width
138
+ if temp_length >= w_p_l:
139
+ lines.append(temp_line)
140
+ temp_line = ""
141
+ temp_length = 0
142
+
143
+ lines.append(temp_line)
144
+
145
+ return String("\n".join(lines))
146
+
147
+
148
+ class List(list):
149
+ def __getitem__(self, item):
150
+ try:
151
+ return super().__getitem__(item)
152
+ except IndexError:
153
+ return None
154
+
155
+
156
+ class Integer(int):
157
+ @classmethod
158
+ def convert_from(cls, target):
159
+ if isinstance(target, int):
160
+ return cls(target)
161
+
162
+ try:
163
+ return cls(int(target))
164
+ except:
165
+ return cls(-1)
166
+
167
+
168
+ class Enum:
169
+ def __init__(self, *args):
170
+ self.items = list(args)
171
+
172
+ def __getattr__(self, item):
173
+ if item in self.items:
174
+ return self.items.index(item)
175
+ else:
176
+ return None
177
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hyper-bot
3
- Version: 0.75
3
+ Version: 0.772
4
4
  Summary: 稳定高效、易于开发的QQ Bot框架
5
5
  Home-page: https://github.com/HarcicYang/HypeR_Bot
6
6
  Author: Harcic
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hyper-bot
3
- Version: 0.75
3
+ Version: 0.772
4
4
  Summary: 稳定高效、易于开发的QQ Bot框架
5
5
  Home-page: https://github.com/HarcicYang/HypeR_Bot
6
6
  Author: Harcic
@@ -6,13 +6,15 @@ Hyper/Errors.py
6
6
  Hyper/Events.py
7
7
  Hyper/Listener.py
8
8
  Hyper/Logger.py
9
- Hyper/Logic.py
10
9
  Hyper/Manager.py
11
- Hyper/ModuleClass.py
12
10
  Hyper/Network.py
13
11
  Hyper/Segments.py
14
12
  Hyper/Adapters/OneBot.py
13
+ Hyper/Adapters/Satori.py
15
14
  Hyper/Adapters/OneBotLib/Manager.py
15
+ Hyper/Adapters/OneBotLib/Res.py
16
+ Hyper/Utils/Logic.py
17
+ Hyper/Utils/TypeExt.py
16
18
  hyper_bot.egg-info/PKG-INFO
17
19
  hyper_bot.egg-info/SOURCES.txt
18
20
  hyper_bot.egg-info/dependency_links.txt
@@ -4,11 +4,11 @@ from setuptools import setup
4
4
 
5
5
  setup(
6
6
  name="hyper-bot",
7
- version="0.75",
7
+ version="0.772",
8
8
  description="稳定高效、易于开发的QQ Bot框架",
9
9
  author="Harcic",
10
10
  author_email="harcic@outlook.com",
11
11
  url="https://github.com/HarcicYang/HypeR_Bot",
12
- packages=["Hyper", "Hyper.Adapters", "Hyper.Adapters.OneBotLib"],
12
+ packages=["Hyper", "Hyper.Adapters", "Hyper.Adapters.OneBotLib", "Hyper.Utils"],
13
13
  include_package_data=True,
14
14
  )
@@ -1,67 +0,0 @@
1
- from Hyper import Events, Listener, Logger, Configurator
2
-
3
- import dataclasses
4
-
5
- config = Configurator.cm.get_cfg()
6
- logger = Logger.Logger()
7
- logger.set_level(config.log_level)
8
-
9
-
10
- @dataclasses.dataclass
11
- class ModuleInfo:
12
- is_hidden: bool = True
13
- module_name: str = "None"
14
- author: str = "None"
15
- version: str = "0.0"
16
- desc: str = "None"
17
- helps: str = "None"
18
-
19
-
20
- class Module:
21
- def __init__(self, actions: Listener.Actions, event):
22
- self.actions = actions
23
- self.event = event
24
-
25
- async def handle(self):
26
- pass
27
-
28
- @staticmethod
29
- def info() -> ModuleInfo:
30
- return ModuleInfo()
31
-
32
-
33
- class InnerHandler:
34
- def __init__(self, module: Module, allowed: list):
35
- self.module = module
36
- self.allowed = allowed
37
-
38
-
39
- register_modules: list[InnerHandler] = []
40
-
41
-
42
- class ModuleRegister:
43
- @staticmethod
44
- def register(*args):
45
- def decorator(cls):
46
- if len(args) < 1:
47
- allowed = [Events.Event]
48
- else:
49
- allowed = list(args)
50
-
51
- from typing import Union
52
-
53
- def init(self, actions: Listener.Actions, event: Union[*allowed]):
54
- self.actions = actions
55
- self.event = event
56
-
57
- cls.__init__ = init
58
-
59
- register_modules.append(InnerHandler(cls, allowed))
60
-
61
- return cls
62
-
63
- return decorator
64
-
65
- @staticmethod
66
- def get_registered() -> list:
67
- return register_modules
@@ -1,77 +0,0 @@
1
- import websocket
2
- import httpx
3
- import queue
4
- import flask
5
- import traceback
6
- import json
7
- import logging
8
- import threading
9
-
10
-
11
- class WebsocketConnection:
12
- def __init__(self, url: str):
13
- self.ws = websocket.WebSocket()
14
- self.url = url
15
-
16
- def connect(self) -> None:
17
- self.ws.connect(self.url)
18
-
19
- def send(self, message: str) -> None:
20
- self.ws.send(message)
21
-
22
- def close(self) -> None:
23
- self.ws.close()
24
-
25
- def recv(self) -> dict:
26
- return json.loads(self.ws.recv())
27
-
28
-
29
- class HTTPConnection:
30
- def __init__(self, url: str, listener_url: str):
31
- self.url = url
32
- listener_url = listener_url.replace("http://", "")
33
- listener_url = listener_url.replace("https://", "")
34
- self.listener_url = listener_url.split(":")[0]
35
- try:
36
- self.port = int(listener_url.split(":")[1])
37
- except IndexError:
38
- self.port = 8080
39
- self.app = flask.Flask(__name__)
40
- self.app.config["LOGGER_HANDLER_POLICY"] = "never"
41
- logging.getLogger("werkzeug").setLevel(logging.ERROR)
42
- self.reports = queue.Queue()
43
-
44
- self.listener_started = False
45
-
46
- def __start_listener(self) -> None:
47
- @self.app.route("/", methods=["POST"])
48
- def listener():
49
- self.reports.put(flask.request.json)
50
- return {}
51
-
52
- # self.app.run(host=self.listener_url, port=self.port)
53
-
54
- threading.Thread(target=lambda: self.app.run(host=self.listener_url, port=self.port)).start()
55
- self.listener_started = True
56
-
57
- def connect(self) -> None:
58
- if not self.listener_started:
59
- self.__start_listener()
60
- httpx.post(self.url)
61
- traceback.print_exc()
62
-
63
- def recv(self) -> dict:
64
- return self.reports.get()
65
-
66
- def send(self, endpoint: str, data: dict, echo: str) -> None:
67
- response = httpx.post(f"{self.url}/{endpoint}", json=data)
68
- res = response.json()
69
- res["echo"] = echo
70
- self.reports.put(res)
71
-
72
- @staticmethod
73
- def close() -> None:
74
- shutdown_func = flask.request.environ.get('werkzeug.server.shutdown')
75
- if shutdown_func is None:
76
- raise RuntimeError('Not running with the Werkzeug Server')
77
- shutdown_func()
File without changes
File without changes
File without changes
File without changes