Skip to content

Commit 0210be0

Browse files
committed
Merge branch 'meta-dev' into meta
2 parents 09e5ebc + a61600c commit 0210be0

10 files changed

Lines changed: 160 additions & 78 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
uses: robinraju/release-downloader@v1.12
2424
with:
2525
repository: 'MetaCubeX/mihomo'
26-
tag: "v1.19.12"
26+
tag: "v1.19.13"
2727
fileName: "mihomo-darwin-???64-v?.*.*.gz"
2828

2929
# releaseId: "62870807"

ClashX.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
0106179F2AF38EFA005C7877 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FEC6682AD9369C00BAD9F5 /* Command.swift */; };
11+
0114F0CF2E5B60CB007C7AAC /* LogRateLimiter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0114F0CE2E5B60CB007C7AAC /* LogRateLimiter.swift */; };
1112
0162E74F2864B819007218A6 /* MetaTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0162E74E2864B819007218A6 /* MetaTask.swift */; };
1213
0197255A2CA15D6400C14E49 /* UserNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019725592CA15D6400C14E49 /* UserNotificationCenter.swift */; };
1314
0197255C2CA15FC600C14E49 /* NSWorkspace+openFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0197255B2CA15FC600C14E49 /* NSWorkspace+openFile.swift */; };
@@ -214,6 +215,7 @@
214215
/* End PBXCopyFilesBuildPhase section */
215216

216217
/* Begin PBXFileReference section */
218+
0114F0CE2E5B60CB007C7AAC /* LogRateLimiter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRateLimiter.swift; sourceTree = "<group>"; };
217219
015F1E90288E42A50052B20A /* ClashMetaConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashMetaConfig.swift; sourceTree = "<group>"; };
218220
0162E74D2864B818007218A6 /* com.metacubex.ClashX.ProxyConfigHelper-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "com.metacubex.ClashX.ProxyConfigHelper-Bridging-Header.h"; sourceTree = "<group>"; };
219221
0162E74E2864B819007218A6 /* MetaTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaTask.swift; sourceTree = "<group>"; };
@@ -597,6 +599,7 @@
597599
49B445152457CDF000B27E3E /* ClashStatusTool.swift */,
598600
49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */,
599601
49FEC6682AD9369C00BAD9F5 /* Command.swift */,
602+
0114F0CE2E5B60CB007C7AAC /* LogRateLimiter.swift */,
600603
);
601604
path = Utils;
602605
sourceTree = "<group>";
@@ -1101,6 +1104,7 @@
11011104
01BCDB042C9ECD010028FA94 /* ClashApiDatasStorage.swift in Sources */,
11021105
01BCDB052C9ECD010028FA94 /* RulesView.swift in Sources */,
11031106
01BCDB062C9ECD010028FA94 /* RuleProviderView.swift in Sources */,
1107+
0114F0CF2E5B60CB007C7AAC /* LogRateLimiter.swift in Sources */,
11041108
01BCDB072C9ECD010028FA94 /* SidebarItem.swift in Sources */,
11051109
01BCDB092C9ECD010028FA94 /* DBProxyStorage.swift in Sources */,
11061110
01BCDB0A2C9ECD010028FA94 /* SwiftUIViewExtensions.swift in Sources */,

ClashX/AppDelegate.swift

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -860,28 +860,9 @@ extension AppDelegate {
860860
}
861861
}
862862

863-
@IBAction func flushFakeipCache(_ sender: NSMenuItem) {
864-
let group = DispatchGroup()
865-
866-
var flushFakeipCacheResult = false
867-
var flushDNSCacheResult = false
868-
869-
group.enter()
870-
ApiRequest.flushFakeipCache {
871-
flushFakeipCacheResult = $0
872-
group.leave()
873-
}
874-
875-
group.enter()
876-
ApiRequest.flushDNSCache {
877-
flushDNSCacheResult = $0
878-
group.leave()
879-
}
880-
881-
group.notify(queue: .main) {
882-
let info = (flushFakeipCacheResult && flushDNSCacheResult) ? "Success" : "Failed"
883-
UserNotificationCenter.shared.post(title: NSLocalizedString("Flush dns cache", comment: ""), info: info)
884-
}
863+
@IBAction func flushDNSCache(_ sender: NSMenuItem) {
864+
ApiRequest.flushDNSCache()
865+
PrivilegedHelperManager.shared.helper()?.flushDnsCache()
885866
}
886867

887868
@IBAction func updateSniffing(_ sender: NSMenuItem) {

ClashX/Base.lproj/Main.storyboard

Lines changed: 48 additions & 49 deletions
Large diffs are not rendered by default.

ClashX/Dashboard/Views/ContentTabs/Config/ConfigView.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,7 @@ struct ConfigView: View {
242242

243243
ConfigItemView(name: "FakeIP") {
244244
Button {
245-
ApiRequest.flushFakeipCache()
246-
ApiRequest.flushDNSCache()
245+
AppDelegate.shared.flushDNSCache(NSMenuItem())
247246
} label: {
248247
Text("Flush dns cache")
249248
}

ClashX/General/ApiRequest.swift

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ class ApiRequest {
9494
private var trafficWebSocketRetryTimer: Timer?
9595
private var loggingWebSocketRetryTimer: Timer?
9696
private var memoryWebSocketRetryTimer: Timer?
97+
98+
private var logRateLimiter = LogRateLimiter {
99+
let alert = NSAlert()
100+
alert.messageText = NSLocalizedString("Log system crashed.", comment: "")
101+
alert.addButton(withTitle: NSLocalizedString("Quit", comment: ""))
102+
alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
103+
let response = alert.runModal()
104+
if response == .alertFirstButtonReturn {
105+
NSApplication.shared.terminate(nil)
106+
}
107+
}
97108

98109
private var alamoFireManager: Session
99110

@@ -488,8 +499,32 @@ extension ApiRequest {
488499
completeHandler?()
489500
}
490501
}
502+
503+
static func flushDNSCache() {
504+
let group = DispatchGroup()
505+
506+
var flushFakeipCacheResult = false
507+
var flushDNSCacheResult = false
508+
509+
group.enter()
510+
ApiRequest.flushFakeipCache {
511+
flushFakeipCacheResult = $0
512+
group.leave()
513+
}
514+
515+
group.enter()
516+
ApiRequest.flushDNSCache {
517+
flushDNSCacheResult = $0
518+
group.leave()
519+
}
520+
521+
group.notify(queue: .main) {
522+
let info = (flushFakeipCacheResult && flushDNSCacheResult) ? "Success" : "Failed"
523+
UserNotificationCenter.shared.post(title: NSLocalizedString("Flush dns cache", comment: ""), info: info)
524+
}
525+
}
491526

492-
static func flushFakeipCache(completeHandler: ((Bool) -> Void)? = nil) {
527+
private static func flushFakeipCache(completeHandler: ((Bool) -> Void)? = nil) {
493528
Logger.log("FlushFakeipCache")
494529
req("/cache/fakeip/flush",
495530
method: .post).response {
@@ -499,7 +534,7 @@ extension ApiRequest {
499534
}
500535
}
501536

502-
static func flushDNSCache(completeHandler: ((Bool) -> Void)? = nil) {
537+
private static func flushDNSCache(completeHandler: ((Bool) -> Void)? = nil) {
503538
Logger.log("FlushDNSCache")
504539
req("/cache/dns/flush",
505540
method: .post).response {
@@ -745,6 +780,7 @@ extension ApiRequest: WebSocketDelegate {
745780
delegate?.didUpdateTraffic(up: json["up"].intValue, down: json["down"].intValue)
746781
dashboardDelegate?.didUpdateTraffic(up: json["up"].intValue, down: json["down"].intValue)
747782
case loggingWebSocket:
783+
guard logRateLimiter.processLog() else { return }
748784
delegate?.didGetLog(log: json["payload"].stringValue, level: json["type"].string ?? "info")
749785
dashboardDelegate?.didGetLog(log: json["payload"].stringValue, level: json["type"].string ?? "info")
750786
case memoryWebSocket:
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import Foundation
2+
3+
class LogRateLimiter {
4+
private let maxLogsCount: Int = 5000
5+
private let timeDuration: TimeInterval = 5.0
6+
private var logCount: Int = 0
7+
private var startTime: Date = Date()
8+
private let queue = DispatchQueue(label: "clashx.logratelimiter", qos: .utility)
9+
private var isBlocked = false
10+
11+
private let onRateLimitTriggered: () -> Void
12+
13+
init(onRateLimitTriggered: @escaping () -> Void) {
14+
self.onRateLimitTriggered = onRateLimitTriggered
15+
}
16+
17+
// Returns true if log can be processed, false if rate limited
18+
func processLog() -> Bool {
19+
return queue.sync { [weak self] in
20+
guard let self = self, !self.isBlocked else { return false }
21+
22+
let now = Date()
23+
24+
// Reset counter if more than 5 seconds passed
25+
if now.timeIntervalSince(self.startTime) >= self.timeDuration {
26+
self.startTime = now
27+
self.logCount = 0
28+
}
29+
30+
// Check if rate limit exceeded
31+
if self.logCount >= self.maxLogsCount {
32+
self.triggerRateLimit()
33+
return false
34+
}
35+
36+
self.logCount += 1
37+
return true
38+
}
39+
}
40+
41+
private func triggerRateLimit() {
42+
isBlocked = true
43+
44+
DispatchQueue.main.async { [weak self] in
45+
self?.onRateLimitTriggered()
46+
Logger.log("⚠️ Rate limit triggered: >5000 logs/5sec, paused for 1min")
47+
}
48+
49+
// Resume after 5 seconds
50+
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { [weak self] in
51+
self?.isBlocked = false
52+
Logger.log("✅ Rate limit resumed")
53+
}
54+
}
55+
}

ProxyConfigHelper/Helper-Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
<key>CFBundleName</key>
1010
<string>com.metacubex.ClashX.ProxyConfigHelper</string>
1111
<key>CFBundleShortVersionString</key>
12-
<string>1.14</string>
12+
<string>1.15</string>
1313
<key>CFBundleVersion</key>
14-
<string>24</string>
14+
<string>25</string>
1515
<key>SMAuthorizedClients</key>
1616
<array>
1717
<string>anchor apple generic and identifier &quot;com.metacubex.ClashX.ProxyConfigHelper&quot; and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = MEWHFZ92DY)</string>

ProxyConfigHelper/ProxyConfigHelper.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,11 @@ extension ProxyConfigHelper: ProxyConfigRemoteProcessProtocol {
143143
self.metaDNS.flushDnsCache()
144144
}
145145
}
146+
147+
func flushDnsCache() {
148+
DispatchQueue.main.async {
149+
self.metaDNS.flushDnsCache()
150+
}
151+
}
152+
146153
}

ProxyConfigHelper/ProxyConfigRemoteProcessProtocol.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ protocol ProxyConfigRemoteProcessProtocol {
1616
func updateTun(state: Bool, dns: String)
1717
func getUsedPorts(reply: @escaping (String?) -> Void)
1818

19+
func flushDnsCache()
1920

2021
func enableProxy(port: Int, socksPort: Int, pac: String?, filterInterface: Bool, ignoreList: [String], reply: @escaping (String?) -> Void)
2122
func disableProxy(filterInterface: Bool, reply: @escaping (String?) -> Void)

0 commit comments

Comments
 (0)