Skip to content

Commit

Permalink
use withThrowingTaskGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
yanue authored and yanue committed May 28, 2024
1 parent 68a3211 commit 6beb9e6
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 104 deletions.
2 changes: 1 addition & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 3e6393519555a41d4672846cccbb38ef2c16f21f

COCOAPODS: 1.12.1
COCOAPODS: 1.15.2
28 changes: 15 additions & 13 deletions V2rayU.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -756,7 +756,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -815,7 +815,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
Expand All @@ -833,20 +833,21 @@
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.1.0;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = RJYEH6TCJD;
DEVELOPMENT_TEAM = "";
ENABLE_ONLY_ACTIVE_RESOURCES = YES;
INFOPLIST_FILE = V2rayU/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = V2rayU;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 4.1.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU;
Expand All @@ -855,7 +856,7 @@
SKIP_INSTALL = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Common/V2rayU-Bridging-header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
Expand All @@ -866,20 +867,21 @@
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.1.0;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = RJYEH6TCJD;
DEVELOPMENT_TEAM = "";
ENABLE_ONLY_ACTIVE_RESOURCES = YES;
INFOPLIST_FILE = V2rayU/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = V2rayU;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 4.1.0;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU;
Expand All @@ -888,7 +890,7 @@
SKIP_INSTALL = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Common/V2rayU-Bridging-header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
};
name = Release;
};
Expand All @@ -899,9 +901,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = RJYEH6TCJD;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
Expand All @@ -914,9 +916,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = RJYEH6TCJD;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
Expand Down
115 changes: 66 additions & 49 deletions V2rayU/Ping.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@ let second: Double = 1000000
let pingURL = URL(string: "http://www.gstatic.com/generate_204")!

class PingSpeed: NSObject {
let lock = NSLock()
let semaphore = DispatchSemaphore(value: 30) // work pool
var group = DispatchGroup()

func pingAll() {
NSLog("ping start")
if inPing {
NSLog("ping inPing")
return
}

// make sure core file
V2rayLaunch.checkV2rayCore()
// in ping
Expand All @@ -51,26 +50,47 @@ class PingSpeed: NSObject {
DispatchQueue.main.async {
menuController.setStatusMenuTip(pingTip: pingTip)
}
let thread = Thread{
self.runTask(items: itemList)
Task {
do {
try await pingTaskGroup(items: itemList)
} catch let error {
NSLog("pingTaskGroup error: \(error)")
}
}
thread.start()
}

func runTask(items: [V2rayItem]) {
self.group = DispatchGroup()
let pingQueue = DispatchQueue(label: "pingQueue", qos: .background, attributes: .concurrent)
for item in items {
self.group.enter() // 进入DispatchGroup
pingQueue.async {
// 信号量,限制最大并发
self.semaphore.wait()
// run ping by async queue
self.pingEachServer(item: item)

func pingTaskGroup(items: [V2rayItem]) async throws {
await withThrowingTaskGroup(of: Int.self) { group in
for item in items {
group.addTask {
do {
await self.semaphore.wait()
defer {
self.semaphore.signal()
}
try await self.pingEachServer(item: item)
} catch let error {
NSLog("pingEachServer error: \(error)")
}
return 1
}
}
}
self.group.wait() // 等待所有任务完成
print("All tasks finished")
print("pingTaskGroup end")
self.pingEnd()
}

func pingEachServer(item: V2rayItem) async throws {
NSLog("ping \(item.name) - \(item.remark)")
if !item.isValid {
return
}
// ping
let t = PingServer(item: item)
try await t.doPing()
}

func pingEnd() {
inPing = false
let langStr = Locale.current.languageCode
var pingTip: String = ""
Expand All @@ -79,33 +99,14 @@ class PingSpeed: NSObject {
} else {
pingTip = "Ping"
}
print("pingTaskGroup pingEnd", pingTip)
DispatchQueue.main.async {
menuController.setStatusMenuTip(pingTip: pingTip)
}
DispatchQueue.main.async {
menuController.showServers()
}
// kill
killAllPing()
}

func pingEachServer(item: V2rayItem) {
NSLog("ping \(item.name) - \(item.remark)")
if !item.isValid {
// refresh servers
ping.pingEnd(item: item)
return
}
// ping
PingServer(item: item).doPing()
}

func pingEnd(item: V2rayItem) {
lock.lock()
self.semaphore.signal() // 释放信号量
self.group.leave() // 离开DispatchGroup
lock.unlock()
}
}

class PingServer: NSObject, URLSessionDataDelegate {
Expand All @@ -120,7 +121,7 @@ class PingServer: NSObject, URLSessionDataDelegate {
super.init() // can actually be omitted in this example because will happen automatically.
}

func doPing() {
func doPing() async throws {
let (_, _bindPort) = getUsablePort(port: uint16(Int.random(in: 9000 ... 36500)))

NSLog("doPing: \(item.name)-\(item.remark) - \(_bindPort)")
Expand Down Expand Up @@ -154,10 +155,13 @@ class PingServer: NSObject, URLSessionDataDelegate {
// sleep for wait v2ray process instanse
usleep(useconds_t(2 * second))

// url request
let session = URLSession(configuration: getProxyUrlSessionConfigure(httpProxyPort: bindPort), delegate: self, delegateQueue: nil)
let task = session.dataTask(with: URLRequest(url: pingURL))
task.resume()
do {
let (_,_) = try await session.data(for: URLRequest(url: pingURL))
} catch let error {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
NSLog("session request fail: \(error)")
}
}

func createV2rayJsonFileForPing() {
Expand Down Expand Up @@ -226,9 +230,6 @@ class PingServer: NSObject, URLSessionDataDelegate {
} catch let error {
print("remove ping config error: \(error)")
}

// refresh servers
ping.pingEnd(item: item)
}
}

Expand All @@ -241,17 +242,34 @@ class PingCurrent: NSObject, URLSessionDataDelegate {
super.init() // can actually be omitted in this example because will happen automatically.
}

func doPing() {
func doPing() {
Task {
do {
try await _doPing()
pingCurrentEnd()
} catch let error {
NSLog("doPing error: \(error)")
}
}
}

func _doPing() async throws {
inPingCurrent = true
usleep(useconds_t(1 * second))
NSLog("PingCurrent start: try=\(tryPing),item=\(item.remark)")
// set URLSessionDataDelegate
let config = getProxyUrlSessionConfigure()
config.timeoutIntervalForRequest = 3
// url request
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
let task = session.dataTask(with: URLRequest(url: pingURL))
task.resume()
tryPing += 1
do {
let (data, response) = try await session.data(for: URLRequest(url: pingURL))
print("doPing: ", data, response)
} catch let error {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
NSLog("save json file fail: \(error)")
}
}

// MARK: - URLSessionDataDelegate
Expand All @@ -272,7 +290,6 @@ class PingCurrent: NSObject, URLSessionDataDelegate {
}
// save
item.store()
pingCurrentEnd()
}

func pingCurrentEnd() {
Expand Down
Loading

0 comments on commit 6beb9e6

Please sign in to comment.