File size: 2,990 Bytes
1b4f3f8
 
 
38415cf
 
 
1b4f3f8
 
38415cf
 
1b4f3f8
 
 
38415cf
1b4f3f8
38415cf
916c313
38415cf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1b4f3f8
38415cf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""
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