ganiu-bridge 1.0.0__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.
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: ganiu-bridge
3
+ Version: 1.0.0
4
+ Summary: 嘎妞连接桥 — 让手机上的嘎妞 App 通过 HTTP API 遥控这台电脑(自动注册到嘎妞后端)
5
+ Author: Ganiu
6
+ License: Proprietary
7
+ Keywords: ganiu,bridge,remote-control,assistant
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: End Users/Desktop
18
+ Classifier: Natural Language :: Chinese (Simplified)
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ Provides-Extra: screenshot
22
+ Requires-Dist: Pillow>=9.0; extra == "screenshot"
23
+
24
+ # 嘎妞连接桥(ganiu-bridge)
25
+
26
+ 让手机上的**嘎妞 App** 通过局域网/公网 HTTP API 遥控这台电脑:执行命令、读写文件、查看系统信息、截图(可选装 Pillow)。
27
+
28
+ ## 安装
29
+
30
+ ```bash
31
+ pip install ganiu-bridge
32
+ ```
33
+
34
+ ## 使用
35
+
36
+ ```bash
37
+ # 从嘎妞 App「设置 → 设备管理」获取设备配对码
38
+ ganiu-bridge --token 你的配对码
39
+ ```
40
+
41
+ 启动后自动注册到嘎妞后端,手机端即可看到这台电脑。
42
+
43
+ - 默认端口 `18791`,可用 `--port` 修改
44
+ - **零第三方依赖**(纯 Python 标准库),Python 3.9+ 即可
45
+ - 截图功能(可选):`pip install "ganiu-bridge[screenshot]"`
46
+ - 安全:未配置 token 时仅允许本机回环访问;配置 token 后远程请求需携带 `Authorization: Bearer <token>`
47
+
48
+ ## 环境变量
49
+
50
+ | 变量 | 说明 |
51
+ |---|---|
52
+ | `GANIU_BACKEND_URL` | 嘎妞后端地址,默认官方后端 |
@@ -0,0 +1,29 @@
1
+ # 嘎妞连接桥(ganiu-bridge)
2
+
3
+ 让手机上的**嘎妞 App** 通过局域网/公网 HTTP API 遥控这台电脑:执行命令、读写文件、查看系统信息、截图(可选装 Pillow)。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pip install ganiu-bridge
9
+ ```
10
+
11
+ ## 使用
12
+
13
+ ```bash
14
+ # 从嘎妞 App「设置 → 设备管理」获取设备配对码
15
+ ganiu-bridge --token 你的配对码
16
+ ```
17
+
18
+ 启动后自动注册到嘎妞后端,手机端即可看到这台电脑。
19
+
20
+ - 默认端口 `18791`,可用 `--port` 修改
21
+ - **零第三方依赖**(纯 Python 标准库),Python 3.9+ 即可
22
+ - 截图功能(可选):`pip install "ganiu-bridge[screenshot]"`
23
+ - 安全:未配置 token 时仅允许本机回环访问;配置 token 后远程请求需携带 `Authorization: Bearer <token>`
24
+
25
+ ## 环境变量
26
+
27
+ | 变量 | 说明 |
28
+ |---|---|
29
+ | `GANIU_BACKEND_URL` | 嘎妞后端地址,默认官方后端 |
@@ -0,0 +1,8 @@
1
+ """
2
+ 嘎妞连接桥 — 让手机上的嘎妞 App 通过 HTTP API 遥控这台电脑
3
+
4
+ pip install ganiu-bridge && ganiu-bridge --token <配对码>
5
+ """
6
+ from .core import VERSION, DEFAULT_PORT # noqa: F401
7
+
8
+ __version__ = VERSION
@@ -0,0 +1,123 @@
1
+ """
2
+ 嘎妞桥接控制端 — 共享核心
3
+ HTTP API 服务,接受手机端嘎妞的远程控制指令
4
+ """
5
+ import json, subprocess, os, sys, platform, shutil
6
+ from http.server import HTTPServer, BaseHTTPRequestHandler
7
+ from pathlib import Path
8
+
9
+ VERSION = "1.0.0"
10
+ DEFAULT_PORT = 18791
11
+
12
+
13
+ def get_system_info():
14
+ """获取系统信息"""
15
+ info = {
16
+ "hostname": platform.node(),
17
+ "os": platform.system(),
18
+ "os_version": platform.version(),
19
+ "arch": platform.machine(),
20
+ "python": sys.version,
21
+ "cpu_count": os.cpu_count(),
22
+ "cwd": os.getcwd(),
23
+ }
24
+ # 磁盘信息
25
+ if platform.system() == "Windows":
26
+ import ctypes
27
+ free = ctypes.c_ulonglong(0)
28
+ total = ctypes.c_ulonglong(0)
29
+ ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p("C:\\"), ctypes.byref(free), ctypes.byref(total), None)
30
+ info["disk_total"] = total.value
31
+ info["disk_free"] = free.value
32
+ else:
33
+ stat = os.statvfs("/")
34
+ info["disk_total"] = stat.f_frsize * stat.f_blocks
35
+ info["disk_free"] = stat.f_frsize * stat.f_bavail
36
+ return info
37
+
38
+
39
+ def run_command(cmd: str, timeout: int = 30, workdir: str = None):
40
+ """执行系统命令"""
41
+ try:
42
+ shell = platform.system() == "Windows"
43
+ result = subprocess.run(
44
+ cmd if shell else ["bash", "-c", cmd],
45
+ capture_output=True, text=True,
46
+ timeout=timeout,
47
+ cwd=workdir or os.getcwd(),
48
+ shell=shell,
49
+ )
50
+ return {
51
+ "exit_code": result.returncode,
52
+ "stdout": result.stdout[-50000:],
53
+ "stderr": result.stderr[-10000:],
54
+ }
55
+ except subprocess.TimeoutExpired:
56
+ return {"exit_code": -1, "stdout": "", "stderr": f"命令超时({timeout}s)"}
57
+ except Exception as e:
58
+ return {"exit_code": -1, "stdout": "", "stderr": str(e)}
59
+
60
+
61
+ def read_file(path: str):
62
+ """读取文件"""
63
+ try:
64
+ p = Path(path)
65
+ if not p.exists():
66
+ return {"error": "文件不存在"}
67
+ if p.stat().st_size > 10 * 1024 * 1024:
68
+ return {"error": "文件超过10MB"}
69
+ return {"content": p.read_text(encoding="utf-8", errors="replace"), "size": p.stat().st_size}
70
+ except Exception as e:
71
+ return {"error": str(e)}
72
+
73
+
74
+ def write_file(path: str, content: str):
75
+ """写入文件"""
76
+ try:
77
+ p = Path(path)
78
+ p.parent.mkdir(parents=True, exist_ok=True)
79
+ p.write_text(content, encoding="utf-8")
80
+ return {"ok": True, "path": str(p)}
81
+ except Exception as e:
82
+ return {"error": str(e)}
83
+
84
+
85
+ def list_files(path: str):
86
+ """列出目录"""
87
+ try:
88
+ p = Path(path)
89
+ if not p.exists():
90
+ return {"error": "路径不存在"}
91
+ items = []
92
+ for f in sorted(p.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower())):
93
+ items.append({
94
+ "name": f.name,
95
+ "is_dir": f.is_dir(),
96
+ "size": f.stat().st_size if f.is_file() else 0,
97
+ })
98
+ return {"path": str(p), "items": items[:200]}
99
+ except Exception as e:
100
+ return {"error": str(e)}
101
+
102
+
103
+ def take_screenshot():
104
+ """截图 (需要PIL)"""
105
+ try:
106
+ from PIL import ImageGrab
107
+ import io, base64
108
+ img = ImageGrab.grab()
109
+ buf = io.BytesIO()
110
+ img.save(buf, format="JPEG", quality=60)
111
+ return {"image_base64": base64.b64encode(buf.getvalue()).decode()}
112
+ except Exception as e:
113
+ return {"error": f"截图失败: {e}. 请安装: pip install Pillow"}
114
+
115
+
116
+ def which(program):
117
+ """查找可执行文件"""
118
+ if platform.system() == "Windows":
119
+ for ext in os.environ.get("PATHEXT", "").split(os.pathsep):
120
+ exe = program + ext
121
+ if shutil.which(exe):
122
+ return exe
123
+ return shutil.which(program)
@@ -0,0 +1,131 @@
1
+ """
2
+ 嘎妞桥接控制端 — HTTP API 服务器(含自动注册)
3
+ """
4
+ import json, sys, os, socket, platform as pf, time, hmac
5
+ from http.server import HTTPServer, BaseHTTPRequestHandler
6
+ from urllib.parse import urlparse
7
+ from urllib.request import Request, urlopen
8
+
9
+ from .core import * # noqa: F401,F403
10
+ from .core import DEFAULT_PORT, VERSION, get_system_info, list_files, run_command, take_screenshot, write_file, read_file
11
+
12
+ TOKEN = ""
13
+ PORT = DEFAULT_PORT
14
+ BACKEND = os.environ.get("GANIU_BACKEND_URL", "http://115.190.134.232:8000") # 嘎妞后端 # 可用环境变量覆盖,迁移改端点不改代码
15
+ DEVICE_NAME = socket.gethostname()
16
+ DEVICE_OS = pf.system()
17
+ DEVICE_IP = socket.gethostbyname(DEVICE_NAME)
18
+ _registered = False
19
+
20
+
21
+ def register_device():
22
+ """自动注册到嘎妞后端"""
23
+ global _registered
24
+ if not TOKEN:
25
+ print(" ⚠ 未配置TOKEN,跳过注册。在手机设置中获取设备配对码。")
26
+ return False
27
+ try:
28
+ data = json.dumps({"name": DEVICE_NAME, "os": DEVICE_OS, "ip": DEVICE_IP}).encode()
29
+ req = Request(f"{BACKEND}/api/v1/devices/register", data=data,
30
+ headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"})
31
+ resp = urlopen(req, timeout=10)
32
+ result = json.loads(resp.read())
33
+ if result.get("ok"):
34
+ print(f" ✅ 已注册到嘎妞后端: {DEVICE_NAME} ({DEVICE_IP})")
35
+ _registered = True
36
+ return True
37
+ else:
38
+ print(f" ❌ 注册失败: {result}")
39
+ except Exception as e:
40
+ print(f" ❌ 注册失败: {e}")
41
+ return False
42
+
43
+
44
+ class BridgeHandler(BaseHTTPRequestHandler):
45
+ def log_message(self, format, *args):
46
+ pass
47
+
48
+ def _check_auth(self):
49
+ if not TOKEN:
50
+ # 安全修复 2026-11-04:空 TOKEN 时仅允许本机回环访问,防止远程无鉴权执行命令/读写文件
51
+ client = self.client_address[0]
52
+ return client in ("127.0.0.1", "::1", "localhost")
53
+ auth = self.headers.get("Authorization", "")
54
+ return hmac.compare_digest(auth, f"Bearer {TOKEN}")
55
+
56
+ def _send(self, data, status=200):
57
+ self.send_response(status)
58
+ self.send_header("Content-Type", "application/json; charset=utf-8")
59
+ self.send_header("Access-Control-Allow-Origin", "*")
60
+ self.end_headers()
61
+ self.wfile.write(json.dumps(data, ensure_ascii=False).encode())
62
+
63
+ def do_OPTIONS(self):
64
+ self.send_response(204)
65
+ self.send_header("Access-Control-Allow-Origin", "*")
66
+ self.send_header("Access-Control-Allow-Methods", "GET,POST,OPTIONS")
67
+ self.send_header("Access-Control-Allow-Headers", "Authorization,Content-Type")
68
+ self.end_headers()
69
+
70
+ def do_GET(self):
71
+ if not self._check_auth():
72
+ return self._send({"error": "未授权"}, 401)
73
+ path = urlparse(self.path).path
74
+ if path == "/":
75
+ return self._send({"name": DEVICE_NAME, "version": VERSION, "os": DEVICE_OS, "registered": _registered})
76
+ if path == "/info":
77
+ return self._send(get_system_info())
78
+ if path == "/files":
79
+ qs = urlparse(self.path).query
80
+ params = dict(p.split("=") for p in qs.split("&") if "=" in p)
81
+ return self._send(list_files(params.get("path", os.getcwd())))
82
+ if path == "/screenshot":
83
+ return self._send(take_screenshot())
84
+ self._send({"error": "未知路径"}, 404)
85
+
86
+ def do_POST(self):
87
+ if not self._check_auth():
88
+ return self._send({"error": "未授权"}, 401)
89
+ path = urlparse(self.path).path
90
+ length = int(self.headers.get("Content-Length", 0))
91
+ body = json.loads(self.rfile.read(length).decode()) if length > 0 else {}
92
+ if path == "/cmd":
93
+ return self._send(run_command(body.get("cmd", ""), timeout=body.get("timeout", 30), workdir=body.get("workdir")))
94
+ if path == "/read":
95
+ return self._send(read_file(body.get("path", "")))
96
+ if path == "/write":
97
+ return self._send(write_file(body.get("path", ""), body.get("content", "")))
98
+ self._send({"error": "未知路径"}, 404)
99
+
100
+
101
+ def start_server(port=None, token=None):
102
+ global TOKEN, PORT
103
+ if port: PORT = port
104
+ if token: TOKEN = token
105
+ server = HTTPServer(("0.0.0.0", PORT), BridgeHandler)
106
+ print(f"\n 嘎妞桥接控制端 v{VERSION}")
107
+ print(f" 系统: {DEVICE_OS} | 主机: {DEVICE_NAME} | 端口: {PORT}")
108
+ # 自动注册
109
+ register_device()
110
+ if not TOKEN:
111
+ print(" ⚠ 安全提醒: 未配置TOKEN,远程访问将被拒绝(仅本机127.0.0.1可用)")
112
+ print(f" 正在监听...\n")
113
+ try:
114
+ server.serve_forever()
115
+ except KeyboardInterrupt:
116
+ print("\n 已停止")
117
+ server.shutdown()
118
+
119
+
120
+ def main():
121
+ import argparse
122
+ parser = argparse.ArgumentParser(description="嘎妞连接桥 — 接受手机嘎妞 App 的远程控制指令")
123
+ parser.add_argument("--port", type=int, default=DEFAULT_PORT)
124
+ parser.add_argument("--token", type=str, default="", help="设备配对码(从嘎妞App设置获取)")
125
+ parser.add_argument("--version", action="version", version=f"ganiu-bridge {VERSION}")
126
+ args = parser.parse_args()
127
+ start_server(port=args.port, token=args.token)
128
+
129
+
130
+ if __name__ == "__main__":
131
+ main()
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: ganiu-bridge
3
+ Version: 1.0.0
4
+ Summary: 嘎妞连接桥 — 让手机上的嘎妞 App 通过 HTTP API 遥控这台电脑(自动注册到嘎妞后端)
5
+ Author: Ganiu
6
+ License: Proprietary
7
+ Keywords: ganiu,bridge,remote-control,assistant
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: End Users/Desktop
18
+ Classifier: Natural Language :: Chinese (Simplified)
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ Provides-Extra: screenshot
22
+ Requires-Dist: Pillow>=9.0; extra == "screenshot"
23
+
24
+ # 嘎妞连接桥(ganiu-bridge)
25
+
26
+ 让手机上的**嘎妞 App** 通过局域网/公网 HTTP API 遥控这台电脑:执行命令、读写文件、查看系统信息、截图(可选装 Pillow)。
27
+
28
+ ## 安装
29
+
30
+ ```bash
31
+ pip install ganiu-bridge
32
+ ```
33
+
34
+ ## 使用
35
+
36
+ ```bash
37
+ # 从嘎妞 App「设置 → 设备管理」获取设备配对码
38
+ ganiu-bridge --token 你的配对码
39
+ ```
40
+
41
+ 启动后自动注册到嘎妞后端,手机端即可看到这台电脑。
42
+
43
+ - 默认端口 `18791`,可用 `--port` 修改
44
+ - **零第三方依赖**(纯 Python 标准库),Python 3.9+ 即可
45
+ - 截图功能(可选):`pip install "ganiu-bridge[screenshot]"`
46
+ - 安全:未配置 token 时仅允许本机回环访问;配置 token 后远程请求需携带 `Authorization: Bearer <token>`
47
+
48
+ ## 环境变量
49
+
50
+ | 变量 | 说明 |
51
+ |---|---|
52
+ | `GANIU_BACKEND_URL` | 嘎妞后端地址,默认官方后端 |
@@ -0,0 +1,11 @@
1
+ PYPI_README.md
2
+ pyproject.toml
3
+ ganiu_bridge/__init__.py
4
+ ganiu_bridge/core.py
5
+ ganiu_bridge/server.py
6
+ ganiu_bridge.egg-info/PKG-INFO
7
+ ganiu_bridge.egg-info/SOURCES.txt
8
+ ganiu_bridge.egg-info/dependency_links.txt
9
+ ganiu_bridge.egg-info/entry_points.txt
10
+ ganiu_bridge.egg-info/requires.txt
11
+ ganiu_bridge.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ganiu-bridge = ganiu_bridge.server:main
@@ -0,0 +1,3 @@
1
+
2
+ [screenshot]
3
+ Pillow>=9.0
@@ -0,0 +1 @@
1
+ ganiu_bridge
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ganiu-bridge"
7
+ version = "1.0.0"
8
+ description = "嘎妞连接桥 — 让手机上的嘎妞 App 通过 HTTP API 遥控这台电脑(自动注册到嘎妞后端)"
9
+ readme = "PYPI_README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "Proprietary" }
12
+ authors = [{ name = "Ganiu" }]
13
+ keywords = ["ganiu", "bridge", "remote-control", "assistant"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.9",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Operating System :: Microsoft :: Windows",
21
+ "Operating System :: POSIX :: Linux",
22
+ "Operating System :: MacOS",
23
+ "Environment :: Console",
24
+ "Intended Audience :: End Users/Desktop",
25
+ "Natural Language :: Chinese (Simplified)",
26
+ ]
27
+ # 零第三方依赖:纯 Python 标准库(截图功能可选装 Pillow)
28
+ dependencies = []
29
+
30
+ [project.optional-dependencies]
31
+ screenshot = ["Pillow>=9.0"]
32
+
33
+ [project.scripts]
34
+ ganiu-bridge = "ganiu_bridge.server:main"
35
+
36
+ [tool.setuptools]
37
+ packages = ["ganiu_bridge"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+