mqs-compat 0.3.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.
- mqs/__init__.py +8 -0
- mqs/compat/__init__.py +5 -0
- mqs/compat/botpy.py +78 -0
- mqs_compat-0.3.0.dist-info/METADATA +36 -0
- mqs_compat-0.3.0.dist-info/RECORD +6 -0
- mqs_compat-0.3.0.dist-info/WHEEL +4 -0
mqs/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""QSandbox Python companion — the SDK shim only.
|
|
2
|
+
|
|
3
|
+
The sandbox server, CLI and control API are the Rust ``mqs`` binary; this
|
|
4
|
+
package exists so that QQ SDKs which hardcode their endpoints (botpy) can be
|
|
5
|
+
pointed at a running sandbox without editing the SDK.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.3.0"
|
mqs/compat/__init__.py
ADDED
mqs/compat/botpy.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Point the real botpy SDK at QSandbox.
|
|
2
|
+
|
|
3
|
+
botpy hardcodes both the REST domain (``botpy.http.Route.DOMAIN``) and the
|
|
4
|
+
access-token URL (``https://bots.qq.com/app/getAppAccessToken``), so a
|
|
5
|
+
``base_url`` config alone cannot work. This module monkeypatches both.
|
|
6
|
+
|
|
7
|
+
Usage::
|
|
8
|
+
|
|
9
|
+
import mqs.compat.botpy # noqa: F401 — before creating botpy.Client
|
|
10
|
+
from botpy import Client
|
|
11
|
+
|
|
12
|
+
Client(intents=Intents(public_messages=True), is_sandbox=False)
|
|
13
|
+
|
|
14
|
+
Set ``MQS_BASE_URL`` (default ``http://127.0.0.1:5700``) or call
|
|
15
|
+
``mqs.compat.botpy.patch("http://127.0.0.1:1234")`` explicitly.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import os
|
|
22
|
+
import time
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from urllib.parse import urlparse
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def patch(base_url: str | None = None) -> str:
|
|
28
|
+
base_url = (base_url or os.environ.get("MQS_BASE_URL") or "http://127.0.0.1:5700").rstrip("/")
|
|
29
|
+
parsed = urlparse(base_url)
|
|
30
|
+
if parsed.scheme not in ("http", "https") or not parsed.netloc:
|
|
31
|
+
raise ValueError(f"invalid base_url: {base_url}")
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
import botpy.robot as bot_robot
|
|
35
|
+
from botpy import http as bot_http
|
|
36
|
+
except ImportError as exc: # pragma: no cover
|
|
37
|
+
raise RuntimeError("botpy is not installed; pip install qq-botpy") from exc
|
|
38
|
+
|
|
39
|
+
bot_http.Route.SCHEME = parsed.scheme
|
|
40
|
+
bot_http.Route.DOMAIN = parsed.netloc
|
|
41
|
+
bot_http.Route.SANDBOX_DOMAIN = parsed.netloc
|
|
42
|
+
|
|
43
|
+
async def update_access_token(self) -> None: # type: ignore[no-untyped-def]
|
|
44
|
+
import aiohttp
|
|
45
|
+
|
|
46
|
+
async with aiohttp.ClientSession() as session:
|
|
47
|
+
async with session.post(
|
|
48
|
+
f"{base_url}/app/getAppAccessToken",
|
|
49
|
+
json={"appId": self.app_id, "clientSecret": self.secret},
|
|
50
|
+
timeout=aiohttp.ClientTimeout(total=20),
|
|
51
|
+
) as response:
|
|
52
|
+
data = await response.json()
|
|
53
|
+
if "access_token" not in data or "expires_in" not in data:
|
|
54
|
+
raise RuntimeError(f"mqs rejected the bot credentials: {data}")
|
|
55
|
+
self.access_token = data["access_token"]
|
|
56
|
+
self.expires_in = int(data["expires_in"]) + int(time.time())
|
|
57
|
+
|
|
58
|
+
bot_robot.Token.update_access_token = update_access_token
|
|
59
|
+
return base_url
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def patch_from_runtime(home: str | None = None, profile: str | None = None) -> str:
|
|
63
|
+
"""Read ``profiles/<name>/runtime.json`` (written by ``mqs serve``) and patch."""
|
|
64
|
+
home_path = Path(home or os.environ.get("MQS_HOME") or "~/.mqs").expanduser()
|
|
65
|
+
name = profile or os.environ.get("MQS_PROFILE") or "default"
|
|
66
|
+
runtime = home_path / "profiles" / name / "runtime.json"
|
|
67
|
+
try:
|
|
68
|
+
payload = json.loads(runtime.read_text(encoding="utf-8"))
|
|
69
|
+
except FileNotFoundError as exc:
|
|
70
|
+
raise RuntimeError(f"no running QSandbox server for profile {name!r} ({runtime} missing)") from exc
|
|
71
|
+
return patch(payload["base_url"])
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# importing the module is enough for the default local setup
|
|
75
|
+
try:
|
|
76
|
+
patch()
|
|
77
|
+
except (RuntimeError, ValueError): # botpy not installed — the shim keeps working
|
|
78
|
+
pass
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mqs-compat
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Point the real QQ SDKs (botpy) at a running QSandbox — Python-only compatibility shim
|
|
5
|
+
Project-URL: Homepage, https://github.com/Moonlark-Dev/qsandbox
|
|
6
|
+
Project-URL: Repository, https://github.com/Moonlark-Dev/qsandbox
|
|
7
|
+
Author: Moonlark Dev Team
|
|
8
|
+
License-Expression: AGPL-3.0-or-later
|
|
9
|
+
Keywords: botpy,moonlark,qqbot,sandbox
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development :: Testing
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Provides-Extra: botpy
|
|
16
|
+
Requires-Dist: qq-botpy; extra == 'botpy'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# mqs-compat
|
|
20
|
+
|
|
21
|
+
Python-only companion of [QSandbox](https://github.com/Moonlark-Dev/qsandbox).
|
|
22
|
+
|
|
23
|
+
The sandbox itself is a Rust binary; only the *SDK shim* stays in Python, because
|
|
24
|
+
`botpy` hardcodes its endpoints and monkeypatching it is a Python-only job.
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import mqs.compat.botpy # noqa: F401 — before creating botpy.Client
|
|
28
|
+
import botpy
|
|
29
|
+
|
|
30
|
+
client = botpy.Client(intents=botpy.Intents(public_messages=True))
|
|
31
|
+
client.run(appid="10000", secret="mqs-secret-10000")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`MQS_BASE_URL` (default `http://127.0.0.1:5700`) or `patch("http://host:port")`
|
|
35
|
+
selects the sandbox. `patch_from_runtime()` reads `profiles/<name>/runtime.json`
|
|
36
|
+
written by `mqs serve`.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
mqs/__init__.py,sha256=Mnt8yMs0RBVAaw-2zybl5tZayEsXvlBSa7o0GEsybnA,285
|
|
2
|
+
mqs/compat/__init__.py,sha256=Rn0KrDRfOIMweW0XZhJvibMMPF1SR0pXDYJ1UHqb48I,163
|
|
3
|
+
mqs/compat/botpy.py,sha256=4eKnEGH-EtZO09d5WjfYfBCmfTAcZLaoNzBvUdamwi8,2986
|
|
4
|
+
mqs_compat-0.3.0.dist-info/METADATA,sha256=QOEwiqrUcQNqoP3IvXfw5KKfCAd2Byl-tiI-RV-XtVg,1358
|
|
5
|
+
mqs_compat-0.3.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
6
|
+
mqs_compat-0.3.0.dist-info/RECORD,,
|