# aider-watch-client buffer | 2026-04-20 @ Asia/Taipei """JSONL buffer 當 awoooi API 不可達時緩衝 events;launchd 定期呼 flush()。""" from __future__ import annotations import json from pathlib import Path from typing import Callable # Late-import to allow tests to monkey-patch import aider_watch_client.config as _config BUFFER_DIR: Path = _config.BUFFER_DIR from ulid import ULID def _ensure(): _config.ensure_dirs() def _get_buffer_dir() -> Path: # test 可 monkey-patch 這個 module-level BUFFER_DIR import aider_watch_client.buffer as _self return _self.BUFFER_DIR def write(events: list[dict]) -> Path: """批次寫一個 pending file。""" bd = _get_buffer_dir() bd.mkdir(parents=True, exist_ok=True) fp = bd / f"pending_{ULID()}.jsonl" with fp.open("w") as f: for ev in events: f.write(json.dumps(ev, ensure_ascii=False, default=str) + "\n") return fp def flush(post_fn: Callable[[list[dict]], bool]) -> int: """把 buffer 下所有 pending file 重送;成功刪檔,失敗保留。回傳成功筆數。""" bd = _get_buffer_dir() bd.mkdir(parents=True, exist_ok=True) total = 0 for fp in list(bd.glob("pending_*.jsonl")): lines = [l for l in fp.read_text().splitlines() if l.strip()] if not lines: fp.unlink(); continue batch = [json.loads(l) for l in lines] ok_all = True # API max 50 per request for i in range(0, len(batch), 50): chunk = batch[i:i+50] if not post_fn(chunk): ok_all = False break total += len(chunk) if ok_all: fp.unlink() return total