Skip to content

Commit 8d61226

Browse files
committed
Add MainActor to RemoteLogger
1 parent 4b57cae commit 8d61226

File tree

6 files changed

+37
-30
lines changed

6 files changed

+37
-30
lines changed

Sources/Pulse/LoggerStore/LoggerStore.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ public final class LoggerStore: @unchecked Sendable, Identifiable {
7575
guard Thread.isMainThread else {
7676
return DispatchQueue.main.async { register(store: store) }
7777
}
78+
MainActor.assumeIsolated {
79+
_register(store: store)
80+
}
81+
}
82+
83+
@MainActor
84+
private static func _register(store: LoggerStore) {
7885
if RemoteLogger.shared.store == nil {
7986
RemoteLogger.shared.initialize(store: store)
8087
}

Sources/Pulse/RemoteLogger/RemoteLogger-Connection.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ extension RemoteLogger {
212212
// MARK: Helpers
213213

214214
extension RemoteLogger {
215-
static func encode(code: UInt8, body: Data) throws -> Data {
215+
nonisolated static func encode(code: UInt8, body: Data) throws -> Data {
216216
guard body.count < UInt32.max else {
217217
throw PacketParsingError.unsupportedContentSize
218218
}
@@ -225,7 +225,7 @@ extension RemoteLogger {
225225
return data
226226
}
227227

228-
static func decode(buffer: Data) throws -> (Connection.Packet, Int) {
228+
nonisolated static func decode(buffer: Data) throws -> (Connection.Packet, Int) {
229229
let header = try PacketHeader(data: buffer)
230230
guard buffer.count >= header.compressedPacketLength else {
231231
throw PacketParsingError.notEnoughData

Sources/Pulse/RemoteLogger/RemoteLogger.swift

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import OSLog
1010

1111
/// Connects to the remote server and sends logs remotely. In the current version,
1212
/// a server is a Pulse Pro app for macOS).
13-
///
14-
/// - warning: Has to be used from the main thread.
13+
@MainActor
1514
public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegate {
1615
/// The store that the logger was initialized with.
1716
public private(set) var store: LoggerStore?
@@ -46,10 +45,14 @@ public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegat
4645

4746
@Published
4847
public private(set) var connectionState: ConnectionState = .disconnected {
49-
didSet { os_log("Set public connection state %{public}@", log: log, "\(oldValue)\(connectionState)") }
50-
48+
didSet {
49+
os_log("Set public connection state %{public}@", log: log, "\(oldValue)\(connectionState)")
50+
RemoteLogger.latestConnectionState.value = connectionState
51+
}
5152
}
5253

54+
nonisolated static let latestConnectionState = Mutex<ConnectionState>(.disconnected)
55+
5356
// Browsing
5457
private var browser: NWBrowser?
5558
private var selectedServerPasscode: String?
@@ -101,8 +104,7 @@ public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegat
101104
}
102105
}
103106

104-
public static var shared: RemoteLogger { _shared.value }
105-
private static let _shared = Mutex(RemoteLogger())
107+
public static let shared = RemoteLogger()
106108

107109
/// - parameter store: The store to be synced with the server. By default,
108110
/// ``LoggerStore/shared``. Only one store can be synced at at time.
@@ -128,9 +130,8 @@ public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegat
128130

129131
// The buffer is used to cover the time between the app launch and the
130132
// initial (automatic) connection to the server.
131-
let box = SendableBox(value: self)
132-
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
133-
box.value?.clearBuffer()
133+
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { [weak self] in
134+
self?.clearBuffer()
134135
}
135136
}
136137

@@ -201,12 +202,15 @@ public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegat
201202
parameters.includePeerToPeer = true
202203

203204
let browser = NWBrowser(for: .bonjourWithTXTRecord(type: RemoteLogger.serviceType, domain: nil), using: parameters)
204-
let box = SendableBox(value: self)
205-
browser.stateUpdateHandler = {
206-
box.value?.browserDidUpdateState($0)
205+
browser.stateUpdateHandler = { [weak self] state in
206+
MainActor.assumeIsolated {
207+
self?.browserDidUpdateState(state)
208+
}
207209
}
208-
browser.browseResultsChangedHandler = { results, _ in
209-
box.value?.browserDidUpdateResults(results)
210+
browser.browseResultsChangedHandler = { [weak self] results, _ in
211+
MainActor.assumeIsolated {
212+
self?.browserDidUpdateResults(results)
213+
}
210214
}
211215
browser.start(queue: .main)
212216

@@ -249,9 +253,8 @@ public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegat
249253
os_log("Did scheduled browser retry", log: log)
250254

251255
// Automatically retry until the user cancels
252-
let box = SendableBox(value: self)
253-
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
254-
guard let self = box.value, self.isEnabled else { return }
256+
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) { [weak self] in
257+
guard let self, self.isEnabled else { return }
255258
self.stopBrowser()
256259
self.startBrowser()
257260
}
@@ -440,9 +443,8 @@ public final class RemoteLogger: ObservableObject, RemoteLoggerConnectionDelegat
440443
connection?.send(code: .clientHello, entity: body)
441444

442445
// Set timeout and retry in case there was no response from the server
443-
let box = SendableBox(value: self)
444-
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(10)) {
445-
box.value?.handshakeDidTimeout()
446+
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(10)) { [weak self] in
447+
self?.handshakeDidTimeout()
446448
}
447449
}
448450

@@ -692,10 +694,6 @@ private func getFallbackDeviceId() -> UUID {
692694
return id
693695
}
694696

695-
private struct SendableBox<T: AnyObject>: @unchecked Sendable {
696-
weak var value: T?
697-
}
698-
699697
private extension NWBrowser.Result {
700698
var name: String? {
701699
switch endpoint {

Sources/Pulse/RemoteLogger/RemoteLoggerURLProtocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public final class RemoteLoggerURLProtocol: URLProtocol {
4848
}
4949

5050
public override class func canInit(with request: URLRequest) -> Bool {
51-
guard RemoteLogger.shared.connectionState == .connected else {
51+
guard RemoteLogger.latestConnectionState.value == .connected else {
5252
return false
5353
}
5454
return RemoteDebugger.shared.shouldMock(request)

Sources/PulseUI/Features/Remote/RemoteLoggerSettingsViewModel.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Combine
88
import Pulse
99
import Network
1010

11+
@MainActor
1112
final class RemoteLoggerSettingsViewModel: ObservableObject {
1213
@Published var isEnabled = false
1314
@Published var pendingPasscodeProtectedServer: RemoteLoggerServerViewModel?
@@ -19,10 +20,10 @@ final class RemoteLoggerSettingsViewModel: ObservableObject {
1920

2021
static var shared = RemoteLoggerSettingsViewModel()
2122

22-
init(logger: RemoteLogger = .shared) {
23-
self.logger = logger
23+
init(logger: RemoteLogger? = nil) {
24+
self.logger = logger ?? .shared
2425

25-
isEnabled = logger.isEnabled
26+
isEnabled = self.logger.isEnabled
2627

2728
$isEnabled.dropFirst().removeDuplicates().receive(on: DispatchQueue.main)
2829
.throttle(for: .milliseconds(500), scheduler: DispatchQueue.main, latest: true)

Sources/PulseUI/Views/ContextMenus.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ struct ButtonOpenOnMac: View {
291291
}
292292
}
293293

294+
@MainActor
294295
private func openOnMac(_ entity: NSManagedObject) {
295296
switch LoggerEntity(entity) {
296297
case .message(let message):

0 commit comments

Comments
 (0)