traffic: add persistent app profiles (api+gui)
This commit is contained in:
@@ -138,6 +138,26 @@ class TrafficAppMarksResult:
|
||||
timeout_sec: int = 0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TrafficAppProfile:
|
||||
id: str
|
||||
name: str
|
||||
app_key: str
|
||||
command: str
|
||||
target: str # vpn|direct
|
||||
ttl_sec: int
|
||||
vpn_profile: str
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TrafficAppProfileSaveResult:
|
||||
ok: bool
|
||||
message: str
|
||||
profile: Optional[TrafficAppProfile] = None
|
||||
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TrafficCandidateSubnet:
|
||||
@@ -860,6 +880,114 @@ class ApiClient:
|
||||
timeout_sec=int(data.get("timeout_sec", 0) or 0),
|
||||
)
|
||||
|
||||
def traffic_app_profiles_list(self) -> List[TrafficAppProfile]:
|
||||
data = cast(
|
||||
Dict[str, Any],
|
||||
self._json(self._request("GET", "/api/v1/traffic/app-profiles")) or {},
|
||||
)
|
||||
raw = data.get("profiles") or []
|
||||
if not isinstance(raw, list):
|
||||
raw = []
|
||||
|
||||
out: List[TrafficAppProfile] = []
|
||||
for it in raw:
|
||||
if not isinstance(it, dict):
|
||||
continue
|
||||
pid = str(it.get("id") or "").strip()
|
||||
if not pid:
|
||||
continue
|
||||
out.append(
|
||||
TrafficAppProfile(
|
||||
id=pid,
|
||||
name=str(it.get("name") or "").strip(),
|
||||
app_key=str(it.get("app_key") or "").strip(),
|
||||
command=str(it.get("command") or "").strip(),
|
||||
target=str(it.get("target") or "").strip().lower(),
|
||||
ttl_sec=int(it.get("ttl_sec", 0) or 0),
|
||||
vpn_profile=str(it.get("vpn_profile") or "").strip(),
|
||||
created_at=str(it.get("created_at") or "").strip(),
|
||||
updated_at=str(it.get("updated_at") or "").strip(),
|
||||
)
|
||||
)
|
||||
return out
|
||||
|
||||
def traffic_app_profile_upsert(
|
||||
self,
|
||||
*,
|
||||
id: str = "",
|
||||
name: str = "",
|
||||
app_key: str = "",
|
||||
command: str,
|
||||
target: str,
|
||||
ttl_sec: int = 0,
|
||||
vpn_profile: str = "",
|
||||
) -> TrafficAppProfileSaveResult:
|
||||
payload: Dict[str, Any] = {
|
||||
"command": str(command or "").strip(),
|
||||
"target": str(target or "").strip().lower(),
|
||||
}
|
||||
if id:
|
||||
payload["id"] = str(id).strip()
|
||||
if name:
|
||||
payload["name"] = str(name).strip()
|
||||
if app_key:
|
||||
payload["app_key"] = str(app_key).strip()
|
||||
if int(ttl_sec or 0) > 0:
|
||||
payload["ttl_sec"] = int(ttl_sec)
|
||||
if vpn_profile:
|
||||
payload["vpn_profile"] = str(vpn_profile).strip()
|
||||
|
||||
data = cast(
|
||||
Dict[str, Any],
|
||||
self._json(
|
||||
self._request("POST", "/api/v1/traffic/app-profiles", json_body=payload)
|
||||
)
|
||||
or {},
|
||||
)
|
||||
msg = str(data.get("message") or "")
|
||||
raw = data.get("profiles") or []
|
||||
if not isinstance(raw, list):
|
||||
raw = []
|
||||
prof: Optional[TrafficAppProfile] = None
|
||||
if raw and isinstance(raw[0], dict):
|
||||
it = cast(Dict[str, Any], raw[0])
|
||||
pid = str(it.get("id") or "").strip()
|
||||
if pid:
|
||||
prof = TrafficAppProfile(
|
||||
id=pid,
|
||||
name=str(it.get("name") or "").strip(),
|
||||
app_key=str(it.get("app_key") or "").strip(),
|
||||
command=str(it.get("command") or "").strip(),
|
||||
target=str(it.get("target") or "").strip().lower(),
|
||||
ttl_sec=int(it.get("ttl_sec", 0) or 0),
|
||||
vpn_profile=str(it.get("vpn_profile") or "").strip(),
|
||||
created_at=str(it.get("created_at") or "").strip(),
|
||||
updated_at=str(it.get("updated_at") or "").strip(),
|
||||
)
|
||||
|
||||
ok = bool(prof) and (msg.strip().lower() in ("saved", "ok"))
|
||||
if not msg and ok:
|
||||
msg = "saved"
|
||||
return TrafficAppProfileSaveResult(ok=ok, message=msg, profile=prof)
|
||||
|
||||
def traffic_app_profile_delete(self, id: str) -> CmdResult:
|
||||
pid = str(id or "").strip()
|
||||
if not pid:
|
||||
raise ValueError("missing id")
|
||||
data = cast(
|
||||
Dict[str, Any],
|
||||
self._json(
|
||||
self._request("DELETE", "/api/v1/traffic/app-profiles", params={"id": pid})
|
||||
)
|
||||
or {},
|
||||
)
|
||||
return CmdResult(
|
||||
ok=bool(data.get("ok", False)),
|
||||
message=str(data.get("message") or ""),
|
||||
exit_code=None,
|
||||
stdout="",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
# DNS / SmartDNS
|
||||
def dns_upstreams_get(self) -> DnsUpstreams:
|
||||
|
||||
Reference in New Issue
Block a user