Skip to content

Commit efe9132

Browse files
committed
Replace semaphore with DispatchGroup
This makes UnknownType the one to wait until the registration is complete. Once the registration is complete, UnknownType will be free to begin encoding and decoding. This is a better solution, but it's still not perfect. A better solution might be to make APIClientService wait until the registration is complete.
1 parent 1c91146 commit efe9132

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

Sources/ATProtoKit/ATProtoKit.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,22 +167,20 @@ public class ATProtoKit: ATProtoKitConfiguration, ATRecordConfiguration {
167167
self.sessionConfiguration = sessionConfiguration
168168
self.logger = session?.logger
169169

170+
// Mark the beginning of registration.
170171
// This is to fix a bug from the following issue: https://github.com/MasterJ93/ATProtoKit/issues/75
171-
// The thread may be blocked if the code within the Task block doesn't complete in a reasonable timeframe.
172-
// This should hopefully be a temporary fix until there's a better solution that doesn't block the
173-
// UI-related threads.
174-
let semaphore = DispatchSemaphore(value: 0)
172+
// as well as this issue: https://github.com/MasterJ93/ATProtoKit/issues/102
173+
ATRecordTypeRegistry.registrationGroup.enter()
175174

176175
Task { [recordLexicons] in
177176
if canUseBlueskyRecords && !(ATRecordTypeRegistry.areBlueskyRecordsRegistered) {
178177
_ = await ATRecordTypeRegistry(blueskyLexiconTypes: recordLexicons)
179178
await ATRecordTypeRegistry.setBlueskyRecordsRegistered(true)
180179
}
181180

182-
semaphore.signal()
181+
// Registration complete – signal waiting threads.
182+
ATRecordTypeRegistry.registrationGroup.leave()
183183
}
184-
185-
semaphore.wait()
186184
}
187185

188186
/// Determines the appropriate Personal Data Server (PDS) URL.

Sources/ATProtoKit/Utilities/ATRecordProtocol.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ public actor ATRecordTypeRegistry {
129129
/// - Warning: Don't touch this property; this should only be used for ``ATProtoKit``.
130130
public static var areBlueskyRecordsRegistered = false
131131

132+
/// Global dispatch group to signal when registration is complete.
133+
public static let registrationGroup = DispatchGroup()
134+
132135
/// Initializes the registry with an array of record types.
133136
///
134137
/// - Parameter types: An array of ``ATRecordProtocol``-conforming `struct`s.
@@ -266,6 +269,16 @@ public enum UnknownType: Sendable, Codable {
266269
/// \- the JSON object is invalid
267270
@_documentation(visibility: private)
268271
public init(from decoder: Decoder) throws {
272+
// Before we decode anything, we need to check that ATRecordTypeRegistry is ready.
273+
// It shouldn't ever take more than 3 seconds to be ready, but in the rare case that it is,
274+
// indeed, not ready, we need to end this early.
275+
let waitResult = ATRecordTypeRegistry.registrationGroup.wait(timeout: .now() + 3)
276+
if waitResult == .timedOut {
277+
throw DecodingError.dataCorrupted(
278+
DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Record registry not ready")
279+
)
280+
}
281+
269282
let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
270283

271284
if let typeKey = DynamicCodingKeys(stringValue: "$type"),
@@ -425,6 +438,16 @@ public enum UnknownType: Sendable, Codable {
425438
/// Inherited from `Encoder`.
426439
@_documentation(visibility: private)
427440
public func encode(to encoder: Encoder) throws {
441+
// Before we encode anything, we need to check that ATRecordTypeRegistry is ready.
442+
// It shouldn't ever take more than 3 seconds to be ready, but in the rare case that it is,
443+
// indeed, not ready, we need to end this early.
444+
let waitResult = ATRecordTypeRegistry.registrationGroup.wait(timeout: .now() + 3)
445+
if waitResult == .timedOut {
446+
throw EncodingError.invalidValue(self,
447+
EncodingError.Context(codingPath: encoder.codingPath,
448+
debugDescription: "Record registry not ready"))
449+
}
450+
428451
var container = encoder.singleValueContainer()
429452

430453
switch self {

0 commit comments

Comments
 (0)