-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.py
More file actions
97 lines (78 loc) · 3.54 KB
/
Copy pathconfig.py
File metadata and controls
97 lines (78 loc) · 3.54 KB
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
96
97
import os
from dotenv import load_dotenv
from redis import ConnectionPool
load_dotenv()
class Config:
SECRET_KEY = os.environ.get("SECRET_KEY") or "dev-key-change-me"
SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL")
SQLALCHEMY_TRACK_MODIFICATIONS = False
# JWT settings
JWT_SECRET_KEY = os.environ.get("JWT_SECRET") or "jwt-secret-change-me"
JWT_ALGORITHM = os.environ.get("JWT_ALGORITHM") or "HS256"
# File upload settings
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB max file size
UPLOAD_FOLDER = "uploads"
ALLOWED_EXTENSIONS = {
"audio": ["mp3", "wav", "m4a"],
"image": ["png", "jpg", "jpeg", "gif"],
"text": ["txt", "csv", "json"],
}
# IP Whitelisting for Cloudflare Tunnel
ALLOWED_IPS = (
[ip.strip() for ip in os.environ.get("ALLOWED_IPS", "").split(",")]
if os.environ.get("ALLOWED_IPS")
else []
)
# ESP32 Factory Key HMAC Secret
FACTORY_SECRET = os.environ.get("FACTORY_SECRET") or "dev_factory_secret_change_me"
# Redis settings for ESP32 event pub/sub
REDIS_URL = os.environ.get("REDIS_URL") or "redis://localhost:6379/0"
# Redis response caching
CACHE_ENABLED = os.environ.get("CACHE_ENABLED", "true").lower() == "true"
# MinIO / S3 settings
MINIO_ENDPOINT = os.environ.get("MINIO_ENDPOINT", "minio:9000")
MINIO_ROOT_USER = os.environ.get("MINIO_ROOT_USER", "minioadmin")
MINIO_ROOT_PASSWORD = os.environ.get("MINIO_ROOT_PASSWORD", "minioadmin")
MINIO_BUCKET = os.environ.get("MINIO_BUCKET", "pd-server")
MINIO_SECURE = os.environ.get("MINIO_SECURE", "false").lower() == "true"
# Storage backend: "local" or "s3"
STORAGE_BACKEND = os.environ.get("STORAGE_BACKEND", "local")
# Gunicorn workers (default 4 for 2-CPU VM with gevent workers)
GUNICORN_WORKERS = int(os.environ.get("GUNICORN_WORKERS", "4"))
# CORS allowed origins (comma-separated list, empty = deny all)
CORS_ORIGINS = os.environ.get("CORS_ORIGINS", "")
# Logging
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
LOG_FORMAT = os.environ.get("LOG_FORMAT", "pretty") # pretty or json
LOG_SILENT_PATHS = os.environ.get("LOG_SILENT_PATHS", "/metrics,/health,/ready")
LOG_FILE_RETENTION_DAYS = int(os.environ.get("LOG_FILE_RETENTION_DAYS", "7"))
# Global rate limiting (applies before route matching, including 404s)
RATE_LIMIT_ENABLED = os.environ.get("RATE_LIMIT_ENABLED", "true").lower() == "true"
RATE_LIMIT_REQUESTS = int(os.environ.get("RATE_LIMIT_REQUESTS", "120"))
RATE_LIMIT_WINDOW_SECONDS = int(os.environ.get("RATE_LIMIT_WINDOW_SECONDS", "60"))
RATE_LIMIT_EXEMPT_PATHS = {
p.strip()
for p in os.environ.get("RATE_LIMIT_EXEMPT_PATHS", "").split(",")
if p.strip()
}
_redis_pool: ConnectionPool | None = None
@classmethod
def redis_pool(cls) -> ConnectionPool:
if cls._redis_pool is None:
cls._redis_pool = ConnectionPool.from_url(
cls.REDIS_URL,
decode_responses=True,
max_connections=50,
)
return cls._redis_pool
@staticmethod
def init_app(app):
os.makedirs(Config.UPLOAD_FOLDER, exist_ok=True)
# Connection pool settings - only for PostgreSQL/MySQL, not SQLite
uri = app.config.get("SQLALCHEMY_DATABASE_URI") or ""
if uri and not uri.startswith("sqlite"):
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
"pool_size": 10,
"max_overflow": 20,
"pool_pre_ping": True,
}