Files
ShadowsocksX-NG/ShadowsocksX-NG2/Domain/RuntimeEventStore.swift
T
Qiu Yuzhou fd9be86149 refactor(ng2): add diagnostics workflow module as single UI-facing seam
诊断区收敛为 DiagnosticsWorkflow 深 module(Candidate 03,issue #43):事实
采样、轮询代际、raw 日志投影、报告准备与导出完成登记集中一个 seam,视图只
负责生命周期触发、呈现、剪贴板、保存面板与报告文件写入。侧栏与详情共享同
一份安全摘要;收集只读,不触碰目录、凭据、runtime 与系统代理设置。

目录不再把原始 ConfigurationCatalog 写入诊断快照:CatalogWorkflow 只输出
domain-neutral 聚合事实(计数 + 已知无效数),报告 builder 只接受已裁剪的
report facts。事件导出改为显式白名单派生(diagnosticReportLine):自由
detail、主机公布地址与 runtime 错误原文一律清洗,数量/端口/领域点名原因
保留;新增事件漏 case 无法编译。raw GUI 事件行与 wrapper agent.log 尾部仅
经显式查看/复制提供,永不进入报告(ADR-0006)。导出完成事件只在用户选择的
文件实际写入成功后登记。

RuntimeEventStore 事件改为携带封闭枚举原值,渲染发生在呈现边缘(白名单清
洗只可能作用于原值)。测试:新增 workflow interface 覆盖投毒导出、白名单、
raw/报告分离、缺失标注、只读、代际覆盖与取消;ADR-0006 与 CONTEXT.md 术语
同步入库。
2026-09-22 19:22:31 +08:00

67 lines
2.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
/// GUI 侧运行事件环形缓冲(spec #21 D5,issue #34):收集 `RuntimeLog.emit`
/// 的事件供主窗口日志查看器实时呈现与诊断导出取用。事件文本来自封闭枚举的
/// 渲染,构造上不含敏感值;容量封顶只留最近事件(够诊断即可,不做复杂轮转)。
/// wrapper 进程不使用本存储(其 stderr 已收敛进 agent.log)。
final class RuntimeEventStore: RuntimeEventSink, @unchecked Sendable {
struct Entry: Equatable, Identifiable {
let id: Int
let timestamp: Date
/// 事件原值(封闭枚举):原始呈现与报告白名单投影共用同一事实。
let event: RuntimeLogEvent
/// 事件文本(查看器与原始行共用)。
var text: String { event.description }
/// 查看器共用的行格式;固定 POSIX locale 保证报障对照不随用户
/// 区域漂移。
var renderedLine: String {
renderedLine(eventText: text)
}
/// 指定事件文本的行格式(报告侧经白名单清洗后复用同一时间戳与间隔,
/// issue #43)。
func renderedLine(eventText: String) -> String {
"\(Self.timestampFormatter.string(from: timestamp)) \(eventText)"
}
/// DateFormatter 在现代 Foundation 中线程安全;本格式器只被读取。
static let timestampFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
return formatter
}()
}
/// 进程级共享实例:GUI 启动时注册为 RuntimeLog 的接收缝。
static let shared = RuntimeEventStore()
private let lock = NSLock()
private var entries: [Entry] = []
private var nextID = 0
private let capacity: Int
init(capacity: Int = 500) {
self.capacity = max(1, capacity)
}
/// 当前缓冲快照(旧→新)。
var snapshot: [Entry] {
lock.lock()
defer { lock.unlock() }
return entries
}
func append(event: RuntimeLogEvent, timestamp: Date = Date()) {
lock.lock()
defer { lock.unlock() }
entries.append(Entry(id: nextID, timestamp: timestamp, event: event))
nextID += 1
if entries.count > capacity {
entries.removeFirst(entries.count - capacity)
}
}
}