Spaces:
Building
Building
Update api_executor.py
Browse files- api_executor.py +62 -70
api_executor.py
CHANGED
@@ -1,93 +1,85 @@
|
|
1 |
"""
|
2 |
-
Flare – API Executor
|
3 |
-
~~~~~~~~~~~~~~~~~~~~
|
4 |
-
• Placeholder yerleştirme ({{variables.x}}, {{auth_tokens.api.token}}, {{config.xxx}})
|
5 |
-
• Proxy string veya ProxyConfig objesi
|
6 |
-
• Auth: enabled==True → token alma & cache
|
7 |
"""
|
8 |
|
9 |
from __future__ import annotations
|
10 |
-
|
11 |
-
import json
|
12 |
-
import re
|
13 |
-
import time
|
14 |
from typing import Any, Dict
|
15 |
-
|
16 |
-
import requests
|
17 |
from utils import log
|
18 |
from config_provider import ConfigProvider, APIConfig, ProxyConfig
|
19 |
-
|
20 |
cfg = ConfigProvider.get()
|
21 |
-
_token_cache: Dict[str, Dict[str, Any]] = {} # api_name → {token, expiry}
|
22 |
-
|
23 |
|
24 |
-
#
|
25 |
-
_placeholder_re = re.compile(r"\{\{\s*([^\}]+?)\s*\}\}")
|
26 |
|
|
|
27 |
|
28 |
-
def _render(obj
|
29 |
-
def
|
30 |
-
key
|
31 |
if key.startswith("variables."):
|
32 |
-
return str(
|
33 |
if key.startswith("auth_tokens."):
|
34 |
-
_,
|
35 |
-
return
|
36 |
if key.startswith("config."):
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
if isinstance(obj,
|
42 |
-
return _placeholder_re.sub(repl, obj)
|
43 |
-
if isinstance(obj, dict):
|
44 |
-
return {k: _render(v, variables, api_name) for k, v in obj.items()}
|
45 |
-
if isinstance(obj, list):
|
46 |
-
return [_render(v, variables, api_name) for v in obj]
|
47 |
return obj
|
48 |
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
if not api.auth or not api.auth.enabled:
|
53 |
-
return
|
54 |
-
cached = _token_cache.get(api.name)
|
55 |
-
if cached and cached["expiry"] > time.time():
|
56 |
-
return
|
57 |
-
|
58 |
-
body = api.auth.token_request_body
|
59 |
-
body = _render(body, {}, api.name)
|
60 |
-
log(f"🔒 Fetching token for {api.name} …")
|
61 |
-
r = requests.post(api.auth.token_endpoint, json=body, timeout=api.timeout_seconds)
|
62 |
r.raise_for_status()
|
63 |
-
js
|
64 |
-
|
65 |
-
for
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
69 |
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
_ensure_token(api)
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
url = api.url
|
77 |
-
method = api.method.upper()
|
78 |
-
|
79 |
-
proxy = None
|
80 |
if api.proxy:
|
81 |
-
proxy
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
proxies={"http": proxy, "https": proxy} if proxy else None,
|
91 |
timeout=api.timeout_seconds,
|
92 |
)
|
93 |
r.raise_for_status()
|
|
|
1 |
"""
|
2 |
+
Flare – API Executor (token refresh eklenmiş)
|
|
|
|
|
|
|
|
|
3 |
"""
|
4 |
|
5 |
from __future__ import annotations
|
6 |
+
import json, re, time, requests
|
|
|
|
|
|
|
7 |
from typing import Any, Dict
|
|
|
|
|
8 |
from utils import log
|
9 |
from config_provider import ConfigProvider, APIConfig, ProxyConfig
|
|
|
10 |
cfg = ConfigProvider.get()
|
|
|
|
|
11 |
|
12 |
+
_token: Dict[str, Dict[str, Any]] = {} # {api: {token, expiry, refresh_ep, refresh_body}}
|
|
|
13 |
|
14 |
+
_placeholder = re.compile(r"\{\{\s*([^\}]+?)\s*\}\}")
|
15 |
|
16 |
+
def _render(obj, vars, api):
|
17 |
+
def r(m):
|
18 |
+
key=m.group(1)
|
19 |
if key.startswith("variables."):
|
20 |
+
return str(vars.get(key.split(".",1)[1],""))
|
21 |
if key.startswith("auth_tokens."):
|
22 |
+
_, apiname, _ = key.split(".")
|
23 |
+
return _token.get(apiname,{}).get("token","")
|
24 |
if key.startswith("config."):
|
25 |
+
return str(getattr(cfg.global_config, key.split(".",1)[1], ""))
|
26 |
+
return m.group(0)
|
27 |
+
if isinstance(obj,str): return _placeholder.sub(r,obj)
|
28 |
+
if isinstance(obj,dict): return {k:_render(v,vars,api) for k,v in obj.items()}
|
29 |
+
if isinstance(obj,list): return [_render(v,vars,api) for v in obj]
|
|
|
|
|
|
|
|
|
|
|
30 |
return obj
|
31 |
|
32 |
+
def _fetch_token(api: APIConfig):
|
33 |
+
body=_render(api.auth.token_request_body,{},api.name)
|
34 |
+
r=requests.post(api.auth.token_endpoint,json=body,timeout=api.timeout_seconds)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
r.raise_for_status()
|
36 |
+
js=r.json()
|
37 |
+
tok=js
|
38 |
+
for p in api.auth.response_token_path.split("."): tok=tok[p]
|
39 |
+
_token[api.name]={
|
40 |
+
"token":tok,
|
41 |
+
"expiry":time.time()+3500,
|
42 |
+
"refresh_ep":api.auth.token_refresh_endpoint,
|
43 |
+
"refresh_body":api.auth.token_refresh_body,
|
44 |
+
}
|
45 |
|
46 |
+
def _ensure_token(api: APIConfig):
|
47 |
+
if not api.auth or not api.auth.enabled: return
|
48 |
+
info=_token.get(api.name)
|
49 |
+
if not info: _fetch_token(api); return
|
50 |
+
if info["expiry"]>time.time(): return
|
51 |
+
|
52 |
+
# refresh varsa dene
|
53 |
+
if info["refresh_ep"]:
|
54 |
+
body=_render(info["refresh_body"],{},api.name)
|
55 |
+
try:
|
56 |
+
r=requests.post(info["refresh_ep"],json=body,timeout=api.timeout_seconds)
|
57 |
+
r.raise_for_status()
|
58 |
+
js=r.json()
|
59 |
+
tok=js
|
60 |
+
for p in api.auth.response_token_path.split("."): tok=tok[p]
|
61 |
+
info["token"]=tok; info["expiry"]=time.time()+3500
|
62 |
+
return
|
63 |
+
except Exception as e:
|
64 |
+
log(f"⚠️ token refresh fail {e}")
|
65 |
+
|
66 |
+
_fetch_token(api)
|
67 |
+
|
68 |
+
def call_api(api: APIConfig, vars: Dict[str,Any]):
|
69 |
_ensure_token(api)
|
70 |
+
hdr=_render(api.headers,vars,api.name)
|
71 |
+
body=_render(api.body_template,vars,api.name)
|
72 |
+
proxy=None
|
|
|
|
|
|
|
|
|
73 |
if api.proxy:
|
74 |
+
proxy=api.proxy if isinstance(api.proxy,str) else (api.proxy.url if api.proxy.enabled else None)
|
75 |
+
log(f"🌐 {api.name} {api.method} {api.url}")
|
76 |
+
r=requests.request(
|
77 |
+
api.method,
|
78 |
+
api.url,
|
79 |
+
json=body if api.method in ("POST","PUT","PATCH") else None,
|
80 |
+
params=body if api.method=="GET" else None,
|
81 |
+
headers=hdr,
|
82 |
+
proxies={"http":proxy,"https":proxy} if proxy else None,
|
|
|
83 |
timeout=api.timeout_seconds,
|
84 |
)
|
85 |
r.raise_for_status()
|