init
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""Entry point — run crawl scenarios or start the admin panel."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import sys
|
||||
import time
|
||||
|
||||
import uvicorn
|
||||
|
||||
from admin.models import get_active_flow_config, init_db, insert_run
|
||||
from config import config
|
||||
from crawler.driver import driver_session
|
||||
from crawler.dynamic_flow import DynamicFlow
|
||||
from crawler.scenarios.fresh_session import FreshSessionScenario
|
||||
from crawler.scenarios.otp_login import OTPLoginScenario
|
||||
|
||||
|
||||
def _load_active_flow() -> dict[str, object]:
|
||||
cfg = asyncio.run(get_active_flow_config())
|
||||
if cfg is None:
|
||||
print("[WARN] No active flow config — running without dynamic flow steps.", file=sys.stderr)
|
||||
return cfg or {}
|
||||
|
||||
|
||||
def _record(
|
||||
scenario: str,
|
||||
identifier: str,
|
||||
flow_result: object | None,
|
||||
exc: Exception | None,
|
||||
t0: float,
|
||||
) -> None:
|
||||
from crawler.dynamic_flow import DynamicFlowResult
|
||||
|
||||
total_ms = int((time.monotonic() - t0) * 1000)
|
||||
if exc is not None:
|
||||
asyncio.run(insert_run(scenario, identifier, False, str(exc), [], total_ms))
|
||||
print(f"[FAIL] {identifier}: {exc}", file=sys.stderr)
|
||||
return
|
||||
|
||||
if isinstance(flow_result, DynamicFlowResult):
|
||||
steps_data = [
|
||||
{"name": s.name, "success": s.success, "error": s.error, "duration_ms": s.duration_ms}
|
||||
for s in flow_result.steps
|
||||
]
|
||||
asyncio.run(insert_run(
|
||||
scenario, identifier, flow_result.success,
|
||||
flow_result.failure_reason, steps_data, total_ms,
|
||||
))
|
||||
status = "OK" if flow_result.success else f"FAIL ({flow_result.failure_reason})"
|
||||
else:
|
||||
asyncio.run(insert_run(scenario, identifier, True, None, [], total_ms))
|
||||
status = "OK (no flow config)"
|
||||
|
||||
print(f"[{status}] {identifier} — {total_ms} ms")
|
||||
|
||||
|
||||
def run_otp(phone: str) -> None:
|
||||
def otp_resolver(p: str) -> str:
|
||||
# TODO: wire up your SMS gateway / webhook here.
|
||||
raise NotImplementedError("Implement otp_resolver to fetch OTP from your SMS gateway")
|
||||
|
||||
flow_cfg = _load_active_flow()
|
||||
t0 = time.monotonic()
|
||||
try:
|
||||
with driver_session() as driver:
|
||||
OTPLoginScenario(driver, phone, otp_resolver).run()
|
||||
result = DynamicFlow(driver, flow_cfg).run() if flow_cfg else None
|
||||
except Exception as exc:
|
||||
_record("otp", phone, None, exc, t0)
|
||||
return
|
||||
_record("otp", phone, result, None, t0)
|
||||
|
||||
|
||||
def run_fresh() -> None:
|
||||
flow_cfg = _load_active_flow()
|
||||
t0 = time.monotonic()
|
||||
try:
|
||||
with driver_session() as driver:
|
||||
FreshSessionScenario(driver).run()
|
||||
result = DynamicFlow(driver, flow_cfg).run() if flow_cfg else None
|
||||
except Exception as exc:
|
||||
_record("fresh", "fresh", None, exc, t0)
|
||||
return
|
||||
_record("fresh", "fresh", result, None, t0)
|
||||
|
||||
|
||||
def run_admin() -> None:
|
||||
init_db()
|
||||
from admin.main import app
|
||||
uvicorn.run(app, host=config.admin_host, port=config.admin_port)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Seed crawler & admin")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
sub.add_parser("admin", help="Start the admin panel")
|
||||
|
||||
otp_p = sub.add_parser("otp", help="Run Scenario 1 (SMS-OTP login)")
|
||||
otp_p.add_argument("--phone", help="Single phone number (default: all from config)")
|
||||
|
||||
sub.add_parser("fresh", help="Run Scenario 2 (fresh session)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.cmd == "admin":
|
||||
run_admin()
|
||||
elif args.cmd == "otp":
|
||||
phones = [args.phone] if args.phone else config.phone_numbers
|
||||
if not phones:
|
||||
print("No phone numbers configured. Set PHONE_NUMBERS in .env or pass --phone", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
for phone in phones:
|
||||
run_otp(phone)
|
||||
elif args.cmd == "fresh":
|
||||
run_fresh()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user