mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-14 10:13:54 +00:00
诊断区收敛为 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 术语 同步入库。
67 lines
2.3 KiB
Swift
67 lines
2.3 KiB
Swift
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)
|
||
}
|
||
}
|
||
}
|