86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
import asyncio
|
||
import time
|
||
from enum import Enum
|
||
from typing import Optional, Any
|
||
|
||
|
||
class EGovStatus(str, Enum):
|
||
IDLE = "idle"
|
||
STARTING = "starting"
|
||
WAITING_MFA = "waiting_mfa"
|
||
LOGGED_IN = "logged_in"
|
||
DOWNLOADING = "downloading"
|
||
ERROR = "error"
|
||
|
||
|
||
class EGovState:
|
||
def __init__(self):
|
||
self.status: EGovStatus = EGovStatus.IDLE
|
||
self.message: str = ""
|
||
self.mfa_event: asyncio.Event = asyncio.Event()
|
||
self.mfa_code: Optional[str] = None
|
||
self.screenshot_b64: Optional[str] = None
|
||
self.last_download: Optional[dict] = None # {filename, path, size}
|
||
|
||
# ブラウザセッション(Playwright 方式, 後方互換用)
|
||
self._playwright: Optional[Any] = None
|
||
self._browser: Optional[Any] = None
|
||
self._context: Optional[Any] = None
|
||
self._page: Optional[Any] = None
|
||
|
||
# ── OAuth2 / e-Gov API 方式 ──────────────────────────────
|
||
self.access_token: Optional[str] = None
|
||
self.refresh_token: Optional[str] = None
|
||
self.token_expires_at: Optional[float] = None # unix timestamp
|
||
self._pkce_verifier: Optional[str] = None
|
||
self._oauth_state: Optional[str] = None
|
||
|
||
def is_token_valid(self) -> bool:
|
||
"""アクセストークンが有効かどうかを返す(60秒マージン)"""
|
||
if not self.access_token:
|
||
return False
|
||
if self.token_expires_at and time.time() >= self.token_expires_at - 60:
|
||
return False
|
||
return True
|
||
|
||
def set_tokens(self, token_response: dict):
|
||
"""トークンレスポンスをステートにセット"""
|
||
self.access_token = token_response.get("access_token")
|
||
self.refresh_token = token_response.get("refresh_token")
|
||
expires_in = token_response.get("expires_in", 300)
|
||
self.token_expires_at = time.time() + int(expires_in)
|
||
|
||
def reset(self):
|
||
self.status = EGovStatus.IDLE
|
||
self.message = ""
|
||
self.mfa_event = asyncio.Event()
|
||
self.mfa_code = None
|
||
self.screenshot_b64 = None
|
||
self.last_download = None
|
||
self.access_token = None
|
||
self.refresh_token = None
|
||
self.token_expires_at = None
|
||
self._pkce_verifier = None
|
||
self._oauth_state = None
|
||
|
||
async def close_browser(self):
|
||
"""ブラウザを閉じてリソースを解放"""
|
||
try:
|
||
if self._browser:
|
||
await self._browser.close()
|
||
except Exception:
|
||
pass
|
||
try:
|
||
if self._playwright:
|
||
await self._playwright.stop()
|
||
except Exception:
|
||
pass
|
||
self._playwright = None
|
||
self._browser = None
|
||
self._context = None
|
||
self._page = None
|
||
|
||
|
||
# モジュールレベルのシングルトン
|
||
state = EGovState()
|