From 86f0b4bd20cdec86dfb5bdb7978d1f6ff4af111a Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 14 Aug 2026 22:41:54 +0800
Subject: [PATCH] [verified] feat: export performance diagnostics

---
 C1.source/Sources/Aligner/PerformanceDiagnosticsExporter.swift |  157 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 157 insertions(+), 0 deletions(-)

diff --git a/C1.source/Sources/Aligner/PerformanceDiagnosticsExporter.swift b/C1.source/Sources/Aligner/PerformanceDiagnosticsExporter.swift
new file mode 100644
index 0000000..1aea448
--- /dev/null
+++ b/C1.source/Sources/Aligner/PerformanceDiagnosticsExporter.swift
@@ -0,0 +1,157 @@
+import AppKit
+import Darwin
+import Foundation
+import AlignerCore
+
+@MainActor
+final class PerformanceDiagnosticsExporter {
+    func export(
+        version: String,
+        build: String,
+        preferences: AlignerPreferences,
+        accessibility: String,
+        screenRecording: String,
+        quickSwitch: [String: Any]
+    ) {
+        let savePanel = NSSavePanel()
+        savePanel.title = "导出性能诊断包"
+        savePanel.nameFieldStringValue = "Aligner-Diagnostics-\(fileTimestamp()).zip"
+        savePanel.allowedContentTypes = [.zip]
+        savePanel.canCreateDirectories = true
+
+        NSApp.activate(ignoringOtherApps: true)
+        guard savePanel.runModal() == .OK, let destinationURL = savePanel.url else {
+            DevelopmentDiagnostics.log("diagnostics.export.cancelled")
+            return
+        }
+
+        let summaryData: Data
+        do {
+            summaryData = try makeSummaryData(
+                version: version,
+                build: build,
+                preferences: preferences,
+                accessibility: accessibility,
+                screenRecording: screenRecording,
+                quickSwitch: quickSwitch
+            )
+        } catch {
+            showFailure(error)
+            return
+        }
+
+        let logURLs = DevelopmentDiagnostics.logURLs
+        DevelopmentDiagnostics.logSync("diagnostics.export.start", ["logFileCount": logURLs.count])
+        DispatchQueue.global(qos: .utility).async {
+            do {
+                _ = try PerformanceDiagnosticArchiveWriter.write(
+                    to: destinationURL,
+                    summaryJSON: summaryData,
+                    eventLogURLs: logURLs
+                )
+                DispatchQueue.main.async {
+                    DevelopmentDiagnostics.log("diagnostics.export.succeeded", [
+                        "archiveCreated": true
+                    ])
+                    self.showSuccess(destinationURL)
+                }
+            } catch {
+                DispatchQueue.main.async {
+                    DevelopmentDiagnostics.log("diagnostics.export.failed", DevelopmentDiagnostics.errorSummaryFields(error))
+                    self.showFailure(error)
+                }
+            }
+        }
+    }
+
+    private func makeSummaryData(
+        version: String,
+        build: String,
+        preferences: AlignerPreferences,
+        accessibility: String,
+        screenRecording: String,
+        quickSwitch: [String: Any]
+    ) throws -> Data {
+        let processInfo = ProcessInfo.processInfo
+        let systemVersion = processInfo.operatingSystemVersion
+        let displaySummaries = NSScreen.screens.map { screen in
+            [
+                "frame": NSStringFromRect(screen.frame),
+                "visibleFrame": NSStringFromRect(screen.visibleFrame),
+                "scale": screen.backingScaleFactor,
+                "isMain": screen == NSScreen.main
+            ] as [String: Any]
+        }
+        let summary: [String: Any] = [
+            "schemaVersion": 1,
+            "collectedAt": ISO8601DateFormatter().string(from: Date()),
+            "app": [
+                "name": "Aligner",
+                "version": version,
+                "build": build,
+                "bundleIdentifier": Bundle.main.bundleIdentifier ?? ""
+            ],
+            "system": [
+                "model": hardwareModel(),
+                "osVersion": processInfo.operatingSystemVersionString,
+                "osVersionComponents": "\(systemVersion.majorVersion).\(systemVersion.minorVersion).\(systemVersion.patchVersion)",
+                "processorCount": processInfo.processorCount,
+                "activeProcessorCount": processInfo.activeProcessorCount,
+                "physicalMemoryBytes": processInfo.physicalMemory,
+                "displays": displaySummaries
+            ],
+            "permissions": [
+                "accessibility": accessibility,
+                "screenRecording": screenRecording
+            ],
+            "preferences": [
+                "showMinimizedWindows": preferences.showMinimizedWindows,
+                "showFullscreenWindows": preferences.showFullscreenWindows,
+                "waterfallViewMode": preferences.quickSwitchWaterfallViewMode.rawValue,
+                "theme": preferences.theme.rawValue,
+                "language": preferences.language.rawValue,
+                "spaceDisplayStrategy": preferences.spaceDisplayStrategy.rawValue
+            ],
+            "quickSwitch": quickSwitch,
+            "collection": [
+                "includesApplicationNames": true,
+                "includesWindowCounts": true,
+                "includesWindowTitles": false,
+                "includesScreenshots": false,
+                "includesTypedText": false
+            ]
+        ]
+        return try JSONSerialization.data(withJSONObject: summary, options: [.prettyPrinted, .sortedKeys])
+    }
+
+    private func showSuccess(_ destinationURL: URL) {
+        let alert = NSAlert()
+        alert.messageText = "性能诊断包已导出"
+        alert.informativeText = "请把 \(destinationURL.lastPathComponent) 发给 Aligner 支持人员。"
+        alert.alertStyle = .informational
+        alert.addButton(withTitle: "好")
+        alert.runModal()
+    }
+
+    private func showFailure(_ error: Error) {
+        let alert = NSAlert(error: error)
+        alert.messageText = "无法导出性能诊断包"
+        alert.runModal()
+    }
+
+    private func fileTimestamp() -> String {
+        let formatter = DateFormatter()
+        formatter.locale = Locale(identifier: "en_US_POSIX")
+        formatter.dateFormat = "yyyyMMdd-HHmmss"
+        return formatter.string(from: Date())
+    }
+
+    private func hardwareModel() -> String {
+        var size = 0
+        guard sysctlbyname("hw.model", nil, &size, nil, 0) == 0, size > 0 else { return "unknown" }
+        var buffer = [CChar](repeating: 0, count: size)
+        guard sysctlbyname("hw.model", &buffer, &size, nil, 0) == 0 else { return "unknown" }
+        let bytes = buffer.prefix { $0 != 0 }.map { UInt8(bitPattern: $0) }
+        return String(decoding: bytes, as: UTF8.self)
+    }
+}

--
Gitblit v1.9.3