This commit is contained in:
mrFq1
2023-06-05 23:39:23 +08:00
parent e5860ead2c
commit f488f41f8d
72 changed files with 247 additions and 45 deletions

View File

@@ -0,0 +1,108 @@
//
// DBConnectionSnapShot.swift
// ClashX Dashboard
//
//
import Cocoa
import DifferenceKit
struct DBConnectionSnapShot: Codable {
let downloadTotal: Int
let uploadTotal: Int
let connections: [DBConnection]
}
struct DBConnection: Codable, Hashable {
let id: String
let chains: [String]
let upload: Int64
let download: Int64
let start: Date
let rule: String
let rulePayload: String
let metadata: DBMetaConnectionData
}
struct DBMetaConnectionData: Codable, Hashable {
let uid: Int
let network: String
let type: String
let sourceIP: String
let destinationIP: String
let sourcePort: String
let destinationPort: String
let inboundIP: String
let inboundPort: String
let inboundName: String
let host: String
let dnsMode: String
let process: String
let processPath: String
let specialProxy: String
let specialRules: String
let remoteDestination: String
let sniffHost: String
}
class DBConnectionObject: NSObject, Differentiable {
@objc let id: String
@objc let host: String
@objc let sniffHost: String
@objc let process: String
@objc let download: Int64
@objc let upload: Int64
let downloadString: String
let uploadString: String
let chains: [String]
@objc let chainString: String
@objc let ruleString: String
@objc let startDate: Date
let startString: String
@objc let source: String
@objc let destinationIP: String?
@objc let type: String
var differenceIdentifier: String {
return id
}
func isContentEqual(to source: DBConnectionObject) -> Bool {
download == source.download &&
upload == source.upload &&
startString == source.startString
}
init(_ conn: DBConnection) {
let byteCountFormatter = ByteCountFormatter()
let startFormatter = RelativeDateTimeFormatter()
startFormatter.unitsStyle = .short
let metadata = conn.metadata
id = conn.id
host = "\(metadata.host == "" ? metadata.destinationIP : metadata.host):\(metadata.destinationPort)"
sniffHost = metadata.sniffHost == "" ? "-" : metadata.sniffHost
process = metadata.process
download = conn.download
downloadString = byteCountFormatter.string(fromByteCount: conn.download)
upload = conn.upload
uploadString = byteCountFormatter.string(fromByteCount: conn.upload)
chains = conn.chains
chainString = conn.chains.reversed().joined(separator: "/")
ruleString = conn.rulePayload == "" ? conn.rule : "\(conn.rule) :: \(conn.rulePayload)"
startDate = conn.start
startString = startFormatter.localizedString(for: conn.start, relativeTo: Date())
source = "\(metadata.sourceIP):\(metadata.sourcePort)"
destinationIP = [metadata.remoteDestination,
metadata.destinationIP,
metadata.host].first(where: { $0 != "" })
type = "\(metadata.type)(\(metadata.network))"
}
}

View File

@@ -0,0 +1,98 @@
//
// DBProviderStorage.swift
// ClashX Dashboard
//
//
import Cocoa
import SwiftUI
class DBProviderStorage: ObservableObject {
@Published var proxyProviders = [DBProxyProvider]()
@Published var ruleProviders = [DBRuleProvider]()
init() {}
}
class DBProxyProvider: ObservableObject, Identifiable {
let id = UUID().uuidString
@Published var name: ClashProviderName
@Published var proxies: [DBProxy]
@Published var type: ClashProvider.ProviderType
@Published var vehicleType: ClashProvider.ProviderVehicleType
@Published var trafficInfo: String
@Published var trafficPercentage: String
@Published var expireDate: String
@Published var updatedAt: String
init(provider: ClashProvider) {
name = provider.name
proxies = provider.proxies.map(DBProxy.init)
type = provider.type
vehicleType = provider.vehicleType
if let info = provider.subscriptionInfo {
let used = info.download + info.upload
let total = info.total
let trafficRate = "\(String(format: "%.2f", Double(used)/Double(total/100)))%"
let formatter = ByteCountFormatter()
trafficInfo = formatter.string(fromByteCount: used)
+ " / "
+ formatter.string(fromByteCount: total)
+ " ( \(trafficRate) )"
let expire = info.expire
expireDate = "Expire: "
+ Date(timeIntervalSince1970: TimeInterval(expire))
.formatted()
self.trafficPercentage = trafficRate
} else {
trafficInfo = ""
expireDate = ""
trafficPercentage = "0.0%"
}
if let updatedAt = provider.updatedAt {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .abbreviated
self.updatedAt = formatter.localizedString(for: updatedAt, relativeTo: .now)
} else {
self.updatedAt = ""
}
}
func updateInfo(_ new: DBProxyProvider) {
proxies = new.proxies
updatedAt = new.updatedAt
expireDate = new.expireDate
trafficInfo = new.trafficInfo
trafficPercentage = new.trafficPercentage
}
}
class DBRuleProvider: ObservableObject, Identifiable {
let id: String
@Published var name: ClashProviderName
@Published var ruleCount: Int
@Published var behavior: String
@Published var type: String
@Published var updatedAt: Date?
init(provider: ClashRuleProvider) {
id = UUID().uuidString
name = provider.name
ruleCount = provider.ruleCount
behavior = provider.behavior
type = provider.type
updatedAt = provider.updatedAt
}
}

View File

@@ -0,0 +1,120 @@
//
// DBProxyStorage.swift
// ClashX Dashboard
//
//
import Cocoa
import SwiftUI
class DBProxyStorage: ObservableObject {
@Published var groups = [DBProxyGroup]()
init() {
}
init(_ resp: ClashProxyResp) {
groups = resp.proxyGroups.map {
DBProxyGroup($0, resp: resp)
}
}
}
class DBProxyGroup: ObservableObject, Identifiable {
let id = UUID().uuidString
@Published var name: ClashProxyName
@Published var type: ClashProxyType
@Published var now: ClashProxyName? {
didSet {
currentProxy = proxies.first {
$0.name == now
}
}
}
@Published var proxies: [DBProxy]
@Published var currentProxy: DBProxy?
init(_ group: ClashProxy, resp: ClashProxyResp) {
name = group.name
type = group.type
now = group.now
proxies = group.all?.compactMap { name in
resp.proxiesMap[name]
}.map(DBProxy.init) ?? []
currentProxy = proxies.first {
$0.name == now
}
}
}
class DBProxy: ObservableObject {
let id: String
@Published var name: ClashProxyName
@Published var type: ClashProxyType
@Published var udpString: String
@Published var tfo: Bool
var delay: Int {
didSet {
delayString = DBProxy.delayString(delay)
delayColor = DBProxy.delayColor(delay)
}
}
@Published var delayString: String
@Published var delayColor: Color
init(_ proxy: ClashProxy) {
id = proxy.id ?? UUID().uuidString
name = proxy.name
type = proxy.type
tfo = proxy.tfo
delay = proxy.history.last?.delayInt ?? 0
udpString = {
if proxy.udp {
return "UDP"
} else if proxy.xudp {
return "XUDP"
} else {
return ""
}
}()
delayString = DBProxy.delayString(delay)
delayColor = DBProxy.delayColor(delay)
}
static func delayString(_ delay: Int) -> String {
switch delay {
case 0:
return NSLocalizedString("fail", comment: "")
default:
return "\(delay) ms"
}
}
static func delayColor(_ delay: Int) -> Color {
let httpsTest = true
switch delay {
case 0:
return .gray
case ..<200 where !httpsTest:
return .green
case ..<800 where httpsTest:
return .green
case 200..<500 where !httpsTest:
return .yellow
case 800..<1500 where httpsTest:
return .yellow
default:
return .orange
}
}
}