package models import ( "encoding/json" "sync" "time" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = time.Now // // Durable log of every RPC method the server has no semantic handler for yet. // Writes to logs/unknown-methods.log so future work can replay shapes // (method id + name, body length, hex prefix). Return behavior of callers is unchanged. // // // ⛑ 2026-09-30 加按 methodId 节流(原因见下)。此前是「一次调用一行」, // 而实机证明高频 Notify 会把这里打成洪水:AskOnMetroEnterStation 累计 4.8 万次、 // AskOnMetroExitStation 4.7 万次、ReportSetActionGroup 2.4 万次、AskTriggerPlotEvent 1.3 万次, // 日志涨到 39 MB 且每次调用都要 lock + File.AppendAllText(开-写-关)。 // 现在:每个 id 首次必写完整行(保留取证/差集能力), // 之后在 RepeatFlushSeconds 窗口内只累加计数不落盘, // 窗口到点写一条 REPEAT 汇总。落盘次数从 O(调用数) 降到 O(id 数 × 时长/窗口)。 // type UnknownMethodLogger struct { SyncRoot any `json:"syncRoot"` LogPath *string `json:"_logPath"` States map[uint32]ThrottleState `json:"states"` } const ( UnknownMethodLogger_MaxHexBytesPerLine int32 = 256 UnknownMethodLogger_RepeatFlushSeconds int32 = 60 UnknownMethodLogger_TailReadBytes int32 = 64 * 1024 ) type ThrottleState struct { // 自上次落盘以来累计的调用次数。 Pending int32 `json:"pending"` // 上次真正落盘的时间(UTC)。仅在 SyncRoot 内读写。 LastWriteUtc time.Time `json:"lastWriteUtc"` // 是否已写过首行(首行含 hex,是取证关键)。仅在 SyncRoot 内写。 Seen bool `json:"seen"` // Seen 的 volatile 镜像,用于无锁快路径判定。 SeenFlag int32 `json:"seenFlag"` }