update stuff, add fallbacks, more order to the api
This commit is contained in:
parent
e777ed476d
commit
ad9fab907c
BIN
__pycache__/healthcheck.cpython-313.pyc
Normal file
BIN
__pycache__/healthcheck.cpython-313.pyc
Normal file
Binary file not shown.
BIN
__pycache__/tokenext.cpython-313.pyc
Normal file
BIN
__pycache__/tokenext.cpython-313.pyc
Normal file
Binary file not shown.
49
berretin.py
49
berretin.py
@ -8,6 +8,7 @@ from urllib.parse import urljoin
|
||||
import tokenext
|
||||
from healthcheck import ensure_config_exists
|
||||
|
||||
# load config
|
||||
config = ensure_config_exists()
|
||||
server_cfg = config["server"]
|
||||
|
||||
@ -16,6 +17,13 @@ PASSWORD = server_cfg.get("password", "").strip()
|
||||
CACHE_DIR = server_cfg.get("cache_dir", "cache")
|
||||
BASE_API = server_cfg.get("base_api", "https://ws1.smn.gob.ar")
|
||||
LOG_FILE = server_cfg.get("log_file", "").strip()
|
||||
|
||||
BASE_PATH = server_cfg.get("base_path", "/smn").strip()
|
||||
if not BASE_PATH.startswith("/"):
|
||||
BASE_PATH = "/" + BASE_PATH
|
||||
if BASE_PATH.endswith("/"):
|
||||
BASE_PATH = BASE_PATH[:-1]
|
||||
|
||||
SMN_TOKEN_FILE = "token"
|
||||
CACHE_TTL = timedelta(minutes=60)
|
||||
AUTH_ENABLED = PASSWORD != ""
|
||||
@ -28,6 +36,7 @@ def log(msg: str):
|
||||
f.write(f"[{datetime.now().isoformat()}] {msg}\n")
|
||||
print(msg)
|
||||
|
||||
# cache handling
|
||||
def get_cache_filename(url: str) -> str:
|
||||
h = hashlib.sha256(url.encode()).hexdigest()
|
||||
return os.path.join(CACHE_DIR, f"{h}.json")
|
||||
@ -51,7 +60,13 @@ def save_cache(url: str, data: dict):
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# token handling
|
||||
def load_smn_token():
|
||||
if not os.path.exists(SMN_TOKEN_FILE):
|
||||
log("[TOKEN] Token file not found — refreshing token...")
|
||||
refresh_smn_token()
|
||||
if not os.path.exists(SMN_TOKEN_FILE):
|
||||
raise FileNotFoundError("Token file could not be created.")
|
||||
with open(SMN_TOKEN_FILE, "r") as f:
|
||||
return f.read().strip()
|
||||
|
||||
@ -69,6 +84,7 @@ def check_access_token():
|
||||
header_token = request.headers.get("Authorization", "").strip()
|
||||
return header_token == PASSWORD
|
||||
|
||||
# upstream the request
|
||||
def fetch_from_smn(url: str, retry: bool = True):
|
||||
token = load_smn_token()
|
||||
headers = {
|
||||
@ -89,7 +105,8 @@ def fetch_from_smn(url: str, retry: bool = True):
|
||||
|
||||
return resp
|
||||
|
||||
@app.route("/smn/<path:subpath>")
|
||||
# the proxy stuff
|
||||
@app.route(f"{BASE_PATH}/<path:subpath>")
|
||||
def smn_proxy(subpath):
|
||||
if not check_access_token():
|
||||
return jsonify({"error": "Unauthorized"}), 401
|
||||
@ -121,7 +138,37 @@ def smn_proxy(subpath):
|
||||
except Exception:
|
||||
return Response("Invalid JSON from SMN", status=502)
|
||||
|
||||
@app.errorhandler(404)
|
||||
def handle_not_found(e):
|
||||
return jsonify({
|
||||
"error": "Endpoint not found",
|
||||
"message": f"The requested URL '{request.path}' is not a valid API endpoint.",
|
||||
}), 200
|
||||
|
||||
@app.errorhandler(405)
|
||||
def handle_method_not_allowed(e):
|
||||
return jsonify({
|
||||
"error": "Method not allowed",
|
||||
"allowed": ["GET"],
|
||||
"path": request.path
|
||||
}), 200
|
||||
|
||||
@app.errorhandler(Exception)
|
||||
def handle_general_error(e):
|
||||
log(f"[ERROR] Unexpected exception: {e}")
|
||||
return jsonify({
|
||||
"error": "Internal error",
|
||||
"message": str(e),
|
||||
"path": request.path
|
||||
}), 200
|
||||
|
||||
|
||||
# === Startup ===
|
||||
if __name__ == "__main__":
|
||||
os.makedirs(CACHE_DIR, exist_ok=True)
|
||||
if not os.path.exists(SMN_TOKEN_FILE):
|
||||
log("[STARTUP] No token file found — generating a new one.")
|
||||
refresh_smn_token()
|
||||
log(f"[STARTUP] Server starting on port {PORT}")
|
||||
log(f"[STARTUP] Base path set to '{BASE_PATH}/<path>'")
|
||||
app.run(host="0.0.0.0", port=PORT)
|
||||
|
||||
30
cache/47172bb6d3ba5ce5b090e419551d930d7d438dc6256e8ed03c5832b6bc7d8fa3.json
vendored
Normal file
30
cache/47172bb6d3ba5ce5b090e419551d930d7d438dc6256e8ed03c5832b6bc7d8fa3.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"date": "2025-11-10T13:00:00-03:00",
|
||||
"humidity": 55.0,
|
||||
"pressure": 1020.8,
|
||||
"feels_like": null,
|
||||
"temperature": 24.1,
|
||||
"visibility": 10.0,
|
||||
"weather": {
|
||||
"description": "Ligeramente nublado",
|
||||
"id": 13
|
||||
},
|
||||
"wind": {
|
||||
"direction": "Noreste",
|
||||
"deg": 45.0,
|
||||
"speed": 15.0
|
||||
},
|
||||
"station_id": 87582,
|
||||
"location": {
|
||||
"id": 10821,
|
||||
"name": "Aeroparque Buenos Aires",
|
||||
"department": "CABA",
|
||||
"province": "CABA",
|
||||
"type": "",
|
||||
"coord": {
|
||||
"lon": -58.4187,
|
||||
"lat": -34.5619
|
||||
},
|
||||
"distance": 0.35
|
||||
}
|
||||
}
|
||||
@ -9,12 +9,14 @@ DEFAULT_CONFIG = {
|
||||
"password": "debug",
|
||||
"cache_dir": "cache",
|
||||
"base_api": "https://ws1.smn.gob.ar",
|
||||
"log_file": ""
|
||||
"log_file": "",
|
||||
"base_path": "/smn"
|
||||
}
|
||||
}
|
||||
|
||||
def ensure_config_exists():
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
print("[CONFIG] config.ini not found - creating with default values")
|
||||
config.read_dict(DEFAULT_CONFIG)
|
||||
@ -36,4 +38,5 @@ def ensure_config_exists():
|
||||
with open(CONFIG_FILE, "w") as f:
|
||||
config.write(f)
|
||||
print("[CONFIG] Missing keys added to config.ini")
|
||||
|
||||
return config
|
||||
Loading…
Reference in New Issue
Block a user