#!/usr/bin/env python3 """极简HTTP服务: POST /save 接收规则JSON写回gost.yaml""" import json, subprocess from http.server import BaseHTTPRequestHandler, HTTPServer class H(BaseHTTPRequestHandler): USER="admin"; PASS="oyh159159oiw.@" def _check_auth(self): import base64 a=self.headers.get("Authorization","") if a.startswith("Basic "): try: u,p=base64.b64decode(a[6:]).decode().split(":",1) return u==self.USER and p==self.PASS except Exception: return False return False def _cors(self): self.send_header("Access-Control-Allow-Origin","*") self.send_header("Access-Control-Allow-Headers","*") self.send_header("Access-Control-Allow-Methods","POST, OPTIONS") def do_OPTIONS(self): self.send_response(204); self._cors(); self.end_headers() def do_GET(self): if not self._check_auth(): self.send_response(401); self._cors() self.send_header("WWW-Authenticate","Basic realm=gost"); self.end_headers(); return if self.path not in ("/yaml","/rawyaml"): self.send_response(404); self._cors(); self.end_headers(); return if self.path=="/rawyaml": with open("/etc/gost/gost.yaml","rb") as f: raw=f.read() self.send_response(200) self._cors(); self.send_header("Content-Type","text/plain; charset=utf-8") self.end_headers(); self.wfile.write(raw) return self.send_response(404); self._cors(); self.end_headers(); return try: with open("/etc/gost/gost.yaml") as f: txt=f.read() import yaml as Y data=Y.safe_load(txt) or {} import json as J out=J.dumps({"services":data.get("services",[])}).encode() self.send_response(200) except Exception as e: out=str(e).encode(); self.send_response(500) self._cors(); self.send_header("Content-Type","application/json") self.end_headers(); self.wfile.write(out) def do_POST(self): if not self._check_auth(): self.send_response(401); self._cors() self.send_header("WWW-Authenticate","Basic realm=gost"); self.end_headers(); return if self.path != "/save": self.send_response(404); self._cors(); self.end_headers(); return n = int(self.headers.get("Content-Length","0")) body = self.rfile.read(n) try: r = subprocess.run(["python3","/usr/local/bin/gost-save.py"], input=body, capture_output=True, timeout=10) out = r.stdout.decode() or r.stderr.decode() code = 200 if r.returncode==0 else 500 except Exception as e: out = str(e); code = 500 self.send_response(code) self._cors(); self.send_header("Content-Type","text/plain") self.end_headers() self.wfile.write(out.encode()) def log_message(self,*a): pass def auto_sync(): import time, urllib.request, base64, yaml as Y, shutil, datetime CONF="/etc/gost/gost.yaml" auth="Basic "+base64.b64encode(b"admin:oyh159159oiw.@").decode() while True: time.sleep(60) try: req=urllib.request.Request("http://127.0.0.1:18080/gostapi/config") req.add_header("Authorization",auth) with urllib.request.urlopen(req,timeout=10) as r: rt=json.load(r) names_rt=sorted(s["name"] for s in (rt.get("services") or [])) with open(CONF) as f: cfg=Y.safe_load(f) or {} names_yaml=sorted(s["name"] for s in (cfg.get("services") or [])) # 提取运行时规则的纯净结构(去掉status等动态字段) clean=[] for s in (rt.get("services") or []): d={k:v for k,v in s.items() if k in ("name","addr","handler","listener","forwarder","metadata","ignoreClientVersion")} clean.append(d) if names_rt!=names_yaml: bak=CONF+".bak-"+datetime.datetime.now().strftime("%Y%m%d%H%M%S") shutil.copy(CONF,bak) cfg["services"]=clean with open(CONF,"w") as f: Y.safe_dump(cfg,f,sort_keys=False,allow_unicode=True) print("auto-synced yaml:",names_rt,flush=True) except Exception as e: print("auto-sync err:",e,flush=True) import threading threading.Thread(target=auto_sync,daemon=True).start() HTTPServer(("0.0.0.0",18081),H).serve_forever()