mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 10:44:50 +00:00
84 lines
3.6 KiB
Swift
84 lines
3.6 KiB
Swift
import Foundation
|
||
|
||
@testable import ShadowsocksX_NG2
|
||
|
||
/// 测试支持:模拟 wrapper 写入部署收据。生产唯一收据写者是 Agent wrapper
|
||
/// (AgentContract.writeRuntimeReceipt),GUI 侧只有读(readRuntimeReceipt);
|
||
/// 收据格式知识由 Domain 的 RuntimeDeploymentReceipt 类型承载,此处只复刻
|
||
/// wrapper 的「写动作」供夹具布置磁盘状态。
|
||
extension RuntimeFileStore {
|
||
func writeRuntimeReceipt(for document: SslocalRuntimeDocument, processID: Int32) throws {
|
||
guard receiptIdentity(for: document) != nil else {
|
||
throw PersistenceError.ioFailure(detail: "Runtime contract digest is unavailable")
|
||
}
|
||
try writePublishedRuntimeReceipt(processID: processID)
|
||
}
|
||
}
|
||
|
||
/// 测试观察真实发布文件;不把上游输出反向重建为 GUI 运行意图。
|
||
struct PublishedRuntimeConfiguration: Equatable {
|
||
let configuration: SslocalConfigurationDocument
|
||
let snapshot: RuntimeSupervision
|
||
let intentSHA256: String
|
||
|
||
var servers: [SslocalServerDocument] { configuration.servers }
|
||
var locals: [SslocalLocalDocument] { configuration.locals }
|
||
var socksPort: Int { locals.first { $0.inboundProtocol == "socks" }?.localPort ?? 0 }
|
||
var httpPort: Int { locals.first { $0.inboundProtocol == "http" }?.localPort ?? 0 }
|
||
var aclRuntime: ProxyACLDocument? {
|
||
guard let acl = snapshot.acl,
|
||
let summary = snapshot.aclVariants.first(where: { $0.value == acl })?.key,
|
||
let path = configuration.aclFilePath
|
||
else { return nil }
|
||
return ProxyACLDocument(path: path, summary: summary, content: "", sha256: acl.sha256)
|
||
}
|
||
|
||
static func == (lhs: Self, rhs: Self) -> Bool {
|
||
lhs.configuration == rhs.configuration && lhs.intentSHA256 == rhs.intentSHA256
|
||
}
|
||
}
|
||
|
||
extension RuntimeFileStore {
|
||
func loadDocument() -> PublishedRuntimeConfiguration? {
|
||
guard let snapshot = RuntimePublication.load(at: supervisionFileURL),
|
||
let data = try? Data(contentsOf: directoryURL.appendingPathComponent(snapshot.configuration)),
|
||
let configuration = try? JSONDecoder().decode(SslocalConfigurationDocument.self, from: data),
|
||
let intentData = try? Data(
|
||
contentsOf: directoryURL.appendingPathComponent(snapshot.intentMetadata)),
|
||
let intent = try? JSONDecoder().decode(PublishedRuntimeIntent.self, from: intentData)
|
||
else { return nil }
|
||
return PublishedRuntimeConfiguration(
|
||
configuration: configuration, snapshot: snapshot, intentSHA256: intent.sha256)
|
||
}
|
||
|
||
func readData() -> Data? {
|
||
guard let snapshot = RuntimePublication.load(at: supervisionFileURL) else { return nil }
|
||
return try? Data(contentsOf: directoryURL.appendingPathComponent(snapshot.configuration))
|
||
}
|
||
|
||
func receiptIdentity(for document: PublishedRuntimeConfiguration) -> String? {
|
||
guard let current = loadDocument(), current.intentSHA256 == document.intentSHA256 else {
|
||
return nil
|
||
}
|
||
return current.snapshot.deploymentID
|
||
}
|
||
|
||
func writeRuntimeReceipt(for document: PublishedRuntimeConfiguration, processID: Int32) throws {
|
||
guard receiptIdentity(for: document) != nil else { throw POSIXError(.EINVAL) }
|
||
try writePublishedRuntimeReceipt(processID: processID)
|
||
}
|
||
}
|
||
|
||
extension RuntimeFileStore {
|
||
func writePublishedRuntimeReceipt(processID: Int32) throws {
|
||
guard let snapshot = RuntimePublication.load(at: supervisionFileURL) else {
|
||
throw POSIXError(.EINVAL)
|
||
}
|
||
try RuntimePublication.select(snapshot, configurationLink: fileURL, aclLink: aclFileURL)
|
||
try AtomicFileWriter.write(
|
||
JSONEncoder().encode(
|
||
RuntimeDeploymentReceipt(processID: processID, deploymentID: snapshot.deploymentID)),
|
||
to: runtimeStatusFileURL)
|
||
}
|
||
}
|