Skip to content

Commit e50dce5

Browse files
committed
Refactor URLSessionProxy
1 parent 091b09e commit e50dce5

File tree

1 file changed

+29
-76
lines changed

1 file changed

+29
-76
lines changed

Sources/Pulse/NetworkLogger/URLSessionProxy.swift

Lines changed: 29 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,6 @@
44

55
import Foundation
66

7-
final class NetworkLoggerURLSessionSwizzlerDelegate: URLSessionSwizzlerDelegate {
8-
private let logger: NetworkLogger
9-
10-
init(logger: NetworkLogger = .init()) {
11-
self.logger = logger
12-
}
13-
14-
func swizzlerSessionDidCallResume(task: URLSessionTask) {
15-
logger.logTaskCreated(task)
16-
}
17-
18-
func swizzlerSessionDidComplete(task: URLSessionTask, error: (any Error)?) {
19-
logger.logTask(task, didCompleteWithError: error)
20-
}
21-
22-
func swizzlerSessionDidFinishCollectingMetrics(task: URLSessionTask, metrics: URLSessionTaskMetrics) {
23-
logger.logTask(task, didFinishCollecting: metrics)
24-
}
25-
26-
func swizzlerSessionDidReceiveData(dataTask: URLSessionDataTask, data: Data) {
27-
logger.logDataTask(dataTask, didReceive: data)
28-
}
29-
}
30-
31-
protocol URLSessionSwizzlerDelegate: AnyObject {
32-
func swizzlerSessionDidCallResume(task: URLSessionTask)
33-
func swizzlerSessionDidComplete(task: URLSessionTask, error: (any Error)?)
34-
func swizzlerSessionDidFinishCollectingMetrics(task: URLSessionTask, metrics: URLSessionTaskMetrics)
35-
func swizzlerSessionDidReceiveData(dataTask: URLSessionDataTask, data: Data)
36-
}
37-
387
@MainActor
398
public final class URLSessionProxy {
409
static var proxy: URLSessionProxy?
@@ -59,32 +28,29 @@ public final class URLSessionProxy {
5928
}
6029

6130
func enable() {
62-
injectIntoNSURLSessionTaskResume()
63-
if let sessionClass = NSClassFromString("__NSCFURLLocalSessionConnection") {
64-
injectIntoURLSessionDelegate(anyClass: sessionClass)
31+
swizzleURLSessionTaskResume()
32+
// "__NSCFURLLocalSessionConnection"
33+
if let sessionClass = NSClassFromString(["__", "NS", "CFURL", "Local", "Session", "Connection"].joined()) {
34+
swizzleDataTaskDidReceiveData(baseClass: sessionClass)
35+
swizzleDataDataDidCompleteWithError(baseClass: sessionClass)
36+
} else {
37+
NSLog("URLSessionProxy failed to initialize. Please report at https://github.com/kean/Pulse/issues.")
6538
}
6639
}
6740

68-
private func injectIntoURLSessionDelegate(anyClass: AnyClass) {
69-
swizzleDataTaskDidReceiveData(baseClass: anyClass)
70-
swizzleDataDataDidCompleteWithError(baseClass: anyClass)
71-
}
72-
73-
private func injectIntoNSURLSessionTaskResume() {
74-
var methodsToSwizzle = [Method]()
75-
41+
// - `resume` (optional)
42+
private func swizzleURLSessionTaskResume() {
43+
var methods = [Method]()
7644
if let method = class_getInstanceMethod(URLSessionTask.self, #selector(URLSessionTask.resume)) {
77-
methodsToSwizzle.append(method)
45+
methods.append(method)
7846
}
79-
80-
if let cfURLSession = NSClassFromString("__NSCFURLSessionTask"),
81-
let method = class_getInstanceMethod(cfURLSession, NSSelectorFromString("resume")) {
82-
methodsToSwizzle.append(method)
47+
// "__NSCFURLSessionTask"
48+
if let sessionTaskClass = NSClassFromString(["__", "NS", "CFURL", "Session", "Task"].joined()),
49+
let method = class_getInstanceMethod(sessionTaskClass, NSSelectorFromString("resume")) {
50+
methods.append(method)
8351
}
84-
85-
methodsToSwizzle.forEach {
52+
methods.forEach {
8653
let method = $0
87-
8854
var originalImplementation: IMP?
8955
let block: @convention(block) (URLSessionTask) -> Void = { [weak self] task in
9056
self?.logger.logTaskCreated(task)
@@ -99,15 +65,11 @@ public final class URLSessionProxy {
9965
originalImplementation = method_setImplementation(method, swizzledIMP)
10066
}
10167
}
102-
}
103-
104-
extension URLSessionProxy {
10568

106-
/// Swizzles the folowing methods:
107-
///
108-
/// - urlSession(_:task:didCompleteWithError:)
69+
// - `urlSession(_:task:didCompleteWithError:)`
10970
func swizzleDataDataDidCompleteWithError(baseClass: AnyClass) {
110-
let selector = NSSelectorFromString("_didFinishWithError:")
71+
// "_didFinishWithError:"
72+
let selector = NSSelectorFromString(["_", "didFinish", "With", "Error", ":"].joined())
11173
guard let method = class_getInstanceMethod(baseClass, selector),
11274
baseClass.instancesRespond(to: selector) else {
11375
return
@@ -119,25 +81,21 @@ extension URLSessionProxy {
11981
original(object, selector, error)
12082

12183
if let task = object.value(forKey: "task") as? URLSessionTask {
122-
if let metrics = task.value(forKey: "_incompleteTaskMetrics") as? URLSessionTaskMetrics {
123-
#warning("FIX")
84+
// "_incompleteTaskMetrics"
85+
if let metrics = task.value(forKey: ["_", "incomplete", "Task", "Metrics"].joined()) as? URLSessionTaskMetrics {
12486
self?.logger.logTask(task, didFinishCollecting: metrics)
12587
}
12688
let error = error as? Error
12789
self?.logger.logTask(task, didCompleteWithError: error)
128-
} else {
129-
NSLog("Could not get data from _swizzleURLSessionTaskDidCompleteWithError. It might causes due to the latest iOS changes. \(object)")
13090
}
13191
}
132-
13392
method_setImplementation(method, imp_implementationWithBlock(closure))
13493
}
13594

136-
/// Swizzles the folowing methods:
137-
///
138-
/// urlSession(_:dataTask:didReceive:)
95+
// - `urlSession(_:dataTask:didReceive:)`
13996
func swizzleDataTaskDidReceiveData(baseClass: AnyClass) {
140-
let selector = NSSelectorFromString("_didReceiveData:")
97+
// "_didReceiveData"
98+
let selector = NSSelectorFromString(["_", "did", "Receive", "Data", ":"].joined())
14199
guard let method = class_getInstanceMethod(baseClass, selector),
142100
baseClass.instancesRespond(to: selector) else {
143101
return
@@ -150,23 +108,18 @@ extension URLSessionProxy {
150108
original(object, selector, data)
151109

152110
if let task = object.value(forKey: "task") as? URLSessionDataTask {
153-
if let data = data as? Data {
154-
self?.logger.logDataTask(task, didReceive: data)
155-
} else {
156-
// TODO: what should it do?
157-
}
158-
} else {
159-
// TODO: update who to call
160-
NSLog("Could not get data from _swizzleURLSessionDataTaskDidReceiveData. It might causes due to the latest iOS changes. \(object)")
111+
let data = (data as? Data) ?? Data()
112+
self?.logger.logDataTask(task, didReceive: data)
161113
}
162114
}
163115
method_setImplementation(method, imp_implementationWithBlock(closure))
164116
}
165117
}
166118

119+
// MARK: - Experimental (Deprecated)
120+
167121
@available(*, deprecated, message: "Experimental.URLSessionProxy is replaced with a reworked URLSessionProxy")
168-
public enum Experimental {
169-
}
122+
public enum Experimental {}
170123

171124
@available(*, deprecated, message: "Experimental.URLSessionProxy is replaced with a reworked URLSessionProxy")
172125
public extension Experimental {

0 commit comments

Comments
 (0)