#!/usr/bin/env python3 """chv-sync-worker-client:Gitea worker 薄客户端(feat-chv-muse-p6)。 agent 侧(broker / chv-sync)只剩薄 CLI:解析参数、发类型化 JSON 请求到 worker socket、原样回显 worker 的 stdout/stderr、按 worker 的 returncode 退出。本进程不跑 git、不碰凭证、不做业务逻辑。 用法:chv-sync-worker-client [仓目录] 仓目录省略时由 worker 侧取唯一仓(与 chv-sync 同款语义,由 worker 的 repo=None 处理——本客户端只透传,不自己解析)。 只用标准库。 """ import json import os import socket import sys import time DEFAULT_SOCKET_PATH = "/run/chv-gitea/worker.sock" def _exchange(sock_path, request): """连 worker、发请求、收一帧回包。 返回 (resp_dict, error_str),成功时 error_str 为 None。""" try: conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) conn.settimeout(310) conn.connect(sock_path) except OSError as exc: return None, "worker 连不上:%s" % exc try: conn.sendall((json.dumps(request) + "\n").encode("utf-8")) data = b"" while len(data) < 65536: chunk = conn.recv(4096) if not chunk: break data += chunk if data.endswith(b"\n"): break except OSError as exc: return None, "worker 通信失败:%s" % exc finally: conn.close() try: resp = json.loads(data.decode("utf-8")) except (ValueError, UnicodeDecodeError): return None, "worker 回包不是 JSON" if not isinstance(resp, dict) or "ok" not in resp: return None, "worker 回包格式不对" return resp, None def main(argv=None): """发一次类型化请求并回显。返回 worker 的 returncode; 通信失败即 exit 2(调用方按失败处理,不静默成功)。""" args = list(argv if argv is not None else sys.argv[1:]) if not args or args[0] not in ("pull", "push", "status", "ping"): print("用法:chv-sync-worker-client " "pull|push|status|ping [仓目录]", file=sys.stderr) return 2 op = args[0] repo = args[1] if len(args) > 1 and args[1] else None sock_path = os.environ.get("CHV_GITEA_WORKER_SOCK", DEFAULT_SOCKET_PATH) request = {"op": op, "connector": "gitea", "repo": repo, "request_id": "cli-%d" % int(time.time() * 1000)} resp, err = _exchange(sock_path, request) if err is not None: print("chv-sync-worker-client: %s" % err, file=sys.stderr) return 2 if resp.get("stdout"): sys.stdout.write(resp["stdout"]) if resp.get("stderr"): sys.stderr.write(resp["stderr"]) if resp.get("error"): print("chv-sync-worker-client: %s" % resp["error"], file=sys.stderr) if resp.get("safety", {}).get("verdict") == "flag": print("chv-sync-worker-client: 输出已标记复核:%s" % resp["safety"], file=sys.stderr) return int(resp.get("returncode") or (0 if resp["ok"] else 1)) if __name__ == "__main__": raise SystemExit(main())