""" Flare – API Executor ~~~~~~~~~~~~~~~~~~~~ • Placeholder yerleştirme ({{variables.x}}, {{auth_tokens.api.token}}, {{config.xxx}}) • Proxy string veya ProxyConfig objesi • Auth: enabled==True → token alma & cache """ from __future__ import annotations import json import re import time from typing import Any, Dict import requests from utils import log from config_provider import ConfigProvider, APIConfig, ProxyConfig cfg = ConfigProvider.get() _token_cache: Dict[str, Dict[str, Any]] = {} # api_name → {token, expiry} # ----------- Placeholder helpers ---------- _placeholder_re = re.compile(r"\{\{\s*([^\}]+?)\s*\}\}") def _render(obj: Any, variables: Dict[str, Any], api_name: str) -> Any: def repl(match): key = match.group(1) if key.startswith("variables."): return str(variables.get(key.split(".", 1)[1], "")) if key.startswith("auth_tokens."): _, api, _ = key.split(".") return _token_cache.get(api, {}).get("token", "") if key.startswith("config."): _, prop = key.split(".", 1) return str(getattr(cfg.global_config, prop, "")) return match.group(0) if isinstance(obj, str): return _placeholder_re.sub(repl, obj) if isinstance(obj, dict): return {k: _render(v, variables, api_name) for k, v in obj.items()} if isinstance(obj, list): return [_render(v, variables, api_name) for v in obj] return obj # ----------- Auth helpers ----------------- def _ensure_token(api: APIConfig): if not api.auth or not api.auth.enabled: return cached = _token_cache.get(api.name) if cached and cached["expiry"] > time.time(): return body = api.auth.token_request_body body = _render(body, {}, api.name) log(f"🔒 Fetching token for {api.name} …") r = requests.post(api.auth.token_endpoint, json=body, timeout=api.timeout_seconds) r.raise_for_status() js = r.json() token = js for part in api.auth.response_token_path.split("."): token = token[part] _token_cache[api.name] = {"token": token, "expiry": time.time() + 3500} # ----------- Main call -------------------- def call_api(api: APIConfig, variables: Dict[str, Any]): _ensure_token(api) headers = _render(api.headers, variables, api.name) body = _render(api.body_template, variables, api.name) url = api.url method = api.method.upper() proxy = None if api.proxy: proxy = api.proxy if isinstance(api.proxy, str) else (api.proxy.url if api.proxy.enabled else None) log(f"🌐 {api.name} → {method} {url}") r = requests.request( method, url, json=body if method in ("POST", "PUT", "PATCH") else None, params=body if method == "GET" else None, headers=headers, proxies={"http": proxy, "https": proxy} if proxy else None, timeout=api.timeout_seconds, ) r.raise_for_status() return r