81 lines
2.7 KiB
Python
81 lines
2.7 KiB
Python
|
|
"""Read-only Pyramid endpoint probe: python -m app.probe_pyramids.
|
||
|
|
|
||
|
|
Uses the project's configured account and WqClient without changing stored data.
|
||
|
|
A standalone process authenticates separately; it cannot inherit a running
|
||
|
|
server's in-memory cookies. Authentication responses and secrets are never printed.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import asyncio
|
||
|
|
import json
|
||
|
|
|
||
|
|
from .config import Settings
|
||
|
|
from .db import create_database
|
||
|
|
from .models import Account
|
||
|
|
from .security import cipher
|
||
|
|
from .worldquant import WqClient, WqError
|
||
|
|
|
||
|
|
PATHS = (
|
||
|
|
"/users/self/activities/pyramid-alphas",
|
||
|
|
"/users/self/pyramid/alphas",
|
||
|
|
"/activities/pyramid-alphas",
|
||
|
|
"/pyramid/alphas",
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
async def probe(client):
|
||
|
|
"""Probe fixed same-origin GET paths using an authenticated WqClient.
|
||
|
|
|
||
|
|
Returns status and successful JSON for each path; stops on session expiry.
|
||
|
|
Transport failures propagate to the caller without exposing request details.
|
||
|
|
"""
|
||
|
|
if not client.authenticated:
|
||
|
|
raise WqError("请先连接 WorldQuant", "disconnected")
|
||
|
|
results = []
|
||
|
|
for path in PATHS:
|
||
|
|
response = await client.client.get(path)
|
||
|
|
result = {"path": path, "status": response.status_code}
|
||
|
|
if response.status_code == 200:
|
||
|
|
try:
|
||
|
|
result["data"] = response.json()
|
||
|
|
except ValueError:
|
||
|
|
result["error"] = "invalid_json"
|
||
|
|
results.append(result)
|
||
|
|
if response.status_code in (401, 429):
|
||
|
|
break
|
||
|
|
return results
|
||
|
|
|
||
|
|
|
||
|
|
async def main():
|
||
|
|
settings = Settings()
|
||
|
|
client = WqClient(settings)
|
||
|
|
engine = None
|
||
|
|
try:
|
||
|
|
if settings.wq_email:
|
||
|
|
email, password = settings.wq_email, settings.wq_password.get_secret_value()
|
||
|
|
else:
|
||
|
|
engine, sessions = create_database(settings.database_url)
|
||
|
|
async with sessions() as db:
|
||
|
|
account = await db.get(Account, 1)
|
||
|
|
if not account or not account.email or not account.password_encrypted:
|
||
|
|
raise WqError("未配置平台凭据", "disconnected")
|
||
|
|
email = account.email
|
||
|
|
password = cipher(settings).decrypt(account.password_encrypted.encode()).decode()
|
||
|
|
await client.authenticate(email, password)
|
||
|
|
print(json.dumps(await probe(client), ensure_ascii=False, indent=2))
|
||
|
|
except WqError as exc:
|
||
|
|
print(json.dumps({"error": exc.code}, ensure_ascii=False))
|
||
|
|
return 1
|
||
|
|
except Exception as exc:
|
||
|
|
# Connection/config errors can contain credentials; print only the type.
|
||
|
|
print(json.dumps({"error": type(exc).__name__}))
|
||
|
|
return 1
|
||
|
|
finally:
|
||
|
|
await client.close()
|
||
|
|
if engine is not None:
|
||
|
|
await engine.dispose()
|
||
|
|
return 0
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
raise SystemExit(asyncio.run(main()))
|