diff --git a/.cursor/rules/swift.mdc b/.cursor/rules/swift.mdc index 3fa734a6..b4a23b5b 100644 --- a/.cursor/rules/swift.mdc +++ b/.cursor/rules/swift.mdc @@ -14,7 +14,7 @@ When writing Swift: - When writing a JSON string, favour using Swift raw string literals instead of escaping double quotes. - When you need to import the following modules inside the AblyLiveObjects library code (that is, in non-test code), do so in the following way: - Ably: use `import Ably` - - AblyPlugin: use `internal import AblyPlugin` + - `_AblyPluginSupportPrivate`: use `internal import _AblyPluginSupportPrivate` - When writing an array literal that starts with an initializer expression, start the initializer expression on the line after the opening square bracket of the array literal. That is, instead of writing: ```swift objectMessages: [InboundObjectMessage( diff --git a/.cursor/rules/testing.mdc b/.cursor/rules/testing.mdc index 07362939..f21ef642 100644 --- a/.cursor/rules/testing.mdc +++ b/.cursor/rules/testing.mdc @@ -14,7 +14,7 @@ When writing tests: - When you need to import the following modules in the tests, do so in the following way: - Ably: use `import Ably` - AblyLiveObjects: use `@testable import AblyLiveObjects` - - AblyPlugin: use `import AblyPlugin`; _do not_ do `internal import` + - `_AblyPluginSupportPrivate`: use `import _AblyPluginSupportPrivate`; _do not_ do `internal import` - When you need to pass a logger to internal components in the tests, pass `TestLogger()`. - When you need to unwrap an optional value in the tests, favour using `#require` instead of `guard let`. - When creating `testsOnly_` property declarations, do not write generic comments of the form "Test-only access to the private createOperationIsMerged property"; the meaning of these properties is already well understood. diff --git a/AblyLiveObjects.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AblyLiveObjects.xcworkspace/xcshareddata/swiftpm/Package.resolved index bfe1d581..cd28d5ba 100644 --- a/AblyLiveObjects.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/AblyLiveObjects.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "6884be3a1fb838d3f9a3288b0cb994d0dfce4e90c7d648bca08e61fb802c9cda", + "originHash" : "7ffc8893e3a0652bc31d38d048052def20308c84ae9888411b48b5c89c2ec6c6", "pins" : [ + { + "identity" : "ably-cocoa-plugin-support", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ably/ably-cocoa-plugin-support", + "state" : { + "revision" : "cec94ed123d60e39e3f8df665c30a57482d37612", + "version" : "0.1.0" + } + }, { "identity" : "delta-codec-cocoa", "kind" : "remoteSourceControl", diff --git a/Package.resolved b/Package.resolved index 773dea53..44dc3735 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "9d42be7ef9d81adeb6ac28ccc2a7a4dd43dbf0d952b6f8331e73ab665d36df3a", + "originHash" : "cf81894c95bf31f3c45009841b1a7ee58b50fdcf93ceeecdade367eef5e57c58", "pins" : [ + { + "identity" : "ably-cocoa-plugin-support", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ably/ably-cocoa-plugin-support", + "state" : { + "revision" : "cec94ed123d60e39e3f8df665c30a57482d37612", + "version" : "0.1.0" + } + }, { "identity" : "delta-codec-cocoa", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 25fd4fce..ce7b62f2 100644 --- a/Package.swift +++ b/Package.swift @@ -21,6 +21,10 @@ let package = Package( .package( path: "ably-cocoa", ), + .package( + url: "https://github.com/ably/ably-cocoa-plugin-support", + from: "0.1.0", + ), .package( url: "https://github.com/apple/swift-argument-parser", from: "1.5.0", @@ -47,8 +51,8 @@ let package = Package( package: "ably-cocoa", ), .product( - name: "AblyPlugin", - package: "ably-cocoa", + name: "_AblyPluginSupportPrivate", + package: "ably-cocoa-plugin-support", ), ], ), @@ -61,8 +65,8 @@ let package = Package( package: "ably-cocoa", ), .product( - name: "AblyPlugin", - package: "ably-cocoa", + name: "_AblyPluginSupportPrivate", + package: "ably-cocoa-plugin-support", ), ], resources: [ diff --git a/Sources/AblyLiveObjects/Internal/ARTClientOptions+Objects.swift b/Sources/AblyLiveObjects/Internal/ARTClientOptions+Objects.swift index dac94d1a..68554345 100644 --- a/Sources/AblyLiveObjects/Internal/ARTClientOptions+Objects.swift +++ b/Sources/AblyLiveObjects/Internal/ARTClientOptions+Objects.swift @@ -1,4 +1,5 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate +import Ably internal extension ARTClientOptions { private class Box { @@ -14,9 +15,9 @@ internal extension ARTClientOptions { /// Can be overriden for testing purposes. var garbageCollectionOptions: InternalDefaultRealtimeObjects.GarbageCollectionOptions? { get { - let optionsValue = PluginAPI.sharedInstance().pluginOptionsValue( + let optionsValue = Plugin.defaultPluginAPI.pluginOptionsValue( forKey: Self.garbageCollectionOptionsKey, - clientOptions: self, + clientOptions: asPluginPublicClientOptions, ) guard let optionsValue else { @@ -35,10 +36,10 @@ internal extension ARTClientOptions { preconditionFailure("Not implemented the ability to un-set GC options") } - PluginAPI.sharedInstance().setPluginOptionsValue( + Plugin.defaultPluginAPI.setPluginOptionsValue( Box(boxed: newValue), forKey: Self.garbageCollectionOptionsKey, - clientOptions: self, + clientOptions: asPluginPublicClientOptions, ) } } diff --git a/Sources/AblyLiveObjects/Internal/CoreSDK.swift b/Sources/AblyLiveObjects/Internal/CoreSDK.swift index 51f05460..1e99994e 100644 --- a/Sources/AblyLiveObjects/Internal/CoreSDK.swift +++ b/Sources/AblyLiveObjects/Internal/CoreSDK.swift @@ -1,9 +1,9 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin /// The API that the internal components of the SDK (that is, `DefaultLiveObjects` and down) use to interact with our core SDK (i.e. ably-cocoa). /// -/// This provides us with a mockable interface to ably-cocoa, and it also allows internal components and their tests not to need to worry about some of the boring details of how we bridge Swift types to AblyPlugin's Objective-C API (i.e. boxing). +/// This provides us with a mockable interface to ably-cocoa, and it also allows internal components and their tests not to need to worry about some of the boring details of how we bridge Swift types to `_AblyPluginSupportPrivate`'s Objective-C API (i.e. boxing). internal protocol CoreSDK: AnyObject, Sendable { /// Implements the internal `#publish` method of RTO15. func publish(objectMessages: [OutboundObjectMessage]) async throws(InternalError) @@ -14,17 +14,17 @@ internal protocol CoreSDK: AnyObject, Sendable { func testsOnly_overridePublish(with newImplementation: @escaping ([OutboundObjectMessage]) async throws(InternalError) -> Void) /// Returns the current state of the Realtime channel that this wraps. - var channelState: ARTRealtimeChannelState { get } + var channelState: _AblyPluginSupportPrivate.RealtimeChannelState { get } } internal final class DefaultCoreSDK: CoreSDK { /// Used to synchronize access to internal mutable state. private let mutex = NSLock() - private let channel: AblyPlugin.RealtimeChannel - private let client: AblyPlugin.RealtimeClient + private let channel: _AblyPluginSupportPrivate.RealtimeChannel + private let client: _AblyPluginSupportPrivate.RealtimeClient private let pluginAPI: PluginAPIProtocol - private let logger: AblyPlugin.Logger + private let logger: Logger /// If set to true, ``publish(objectMessages:)`` will behave like a no-op. /// @@ -34,10 +34,10 @@ internal final class DefaultCoreSDK: CoreSDK { private nonisolated(unsafe) var overriddenPublishImplementation: (([OutboundObjectMessage]) async throws -> Void)? internal init( - channel: AblyPlugin.RealtimeChannel, - client: AblyPlugin.RealtimeClient, + channel: _AblyPluginSupportPrivate.RealtimeChannel, + client: _AblyPluginSupportPrivate.RealtimeClient, pluginAPI: PluginAPIProtocol, - logger: AblyPlugin.Logger + logger: Logger ) { self.channel = channel self.client = client @@ -81,8 +81,8 @@ internal final class DefaultCoreSDK: CoreSDK { } } - internal var channelState: ARTRealtimeChannelState { - channel.state + internal var channelState: _AblyPluginSupportPrivate.RealtimeChannelState { + pluginAPI.state(for: channel) } } @@ -97,7 +97,7 @@ internal extension CoreSDK { /// - operationDescription: A description of the operation being performed, used in error messages /// - Throws: `ARTErrorInfo` with code 90001 and statusCode 400 if the channel is in any of the invalid states func validateChannelState( - notIn invalidStates: [ARTRealtimeChannelState], + notIn invalidStates: [_AblyPluginSupportPrivate.RealtimeChannelState], operationDescription: String, ) throws(ARTErrorInfo) { let currentChannelState = channelState diff --git a/Sources/AblyLiveObjects/Internal/DefaultInternalPlugin.swift b/Sources/AblyLiveObjects/Internal/DefaultInternalPlugin.swift index 207ffd80..ac081fc2 100644 --- a/Sources/AblyLiveObjects/Internal/DefaultInternalPlugin.swift +++ b/Sources/AblyLiveObjects/Internal/DefaultInternalPlugin.swift @@ -1,14 +1,15 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate +import Ably -// We explicitly import the NSObject class, else it seems to get transitively imported from `internal import AblyPlugin`, leading to the error "Class cannot be declared public because its superclass is internal". +// We explicitly import the NSObject class, else it seems to get transitively imported from `internal import _AblyPluginSupportPrivate`, leading to the error "Class cannot be declared public because its superclass is internal". import ObjectiveC.NSObject -/// The default implementation of `AblyPlugin`'s `LiveObjectsInternalPluginProtocol`. Implements the interface that ably-cocoa uses to access the functionality provided by the LiveObjects plugin. +/// The default implementation of `_AblyPluginSupportPrivate`'s `LiveObjectsInternalPluginProtocol`. Implements the interface that ably-cocoa uses to access the functionality provided by the LiveObjects plugin. @objc -internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInternalPluginProtocol { - private let pluginAPI: AblyPlugin.PluginAPIProtocol +internal final class DefaultInternalPlugin: NSObject, _AblyPluginSupportPrivate.LiveObjectsInternalPluginProtocol { + private let pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol - internal init(pluginAPI: AblyPlugin.PluginAPIProtocol) { + internal init(pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol) { self.pluginAPI = pluginAPI } @@ -20,7 +21,7 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte /// Retrieves the `RealtimeObjects` for this channel. /// /// We expect this value to have been previously set by ``prepare(_:)``. - internal static func realtimeObjects(for channel: AblyPlugin.RealtimeChannel, pluginAPI: AblyPlugin.PluginAPIProtocol) -> InternalDefaultRealtimeObjects { + internal static func realtimeObjects(for channel: _AblyPluginSupportPrivate.RealtimeChannel, pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol) -> InternalDefaultRealtimeObjects { guard let pluginData = pluginAPI.pluginDataValue(forKey: pluginDataKey, channel: channel) else { // InternalPlugin.prepare was not called fatalError("To access LiveObjects functionality, you must pass the LiveObjects plugin in the client options when creating the ARTRealtime instance: `clientOptions.plugins = [.liveObjects: AblyLiveObjects.Plugin.self]`") @@ -33,11 +34,12 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte // MARK: - LiveObjectsInternalPluginProtocol // Populates the channel's `objects` property. - internal func prepare(_ channel: AblyPlugin.RealtimeChannel, client: AblyPlugin.RealtimeClient) { - let logger = pluginAPI.logger(for: channel) + internal func prepare(_ channel: _AblyPluginSupportPrivate.RealtimeChannel, client: _AblyPluginSupportPrivate.RealtimeClient) { + let pluginLogger = pluginAPI.logger(for: channel) let callbackQueue = pluginAPI.callbackQueue(for: client) - let options = pluginAPI.options(for: client) + let options = ARTClientOptions.castPluginPublicClientOptions(pluginAPI.options(for: client)) + let logger = DefaultLogger(pluginLogger: pluginLogger, pluginAPI: pluginAPI) logger.log("LiveObjects.DefaultInternalPlugin received prepare(_:)", level: .debug) let liveObjects = InternalDefaultRealtimeObjects( logger: logger, @@ -49,14 +51,14 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte } /// Retrieves the internally-typed `objects` property for the channel. - private func realtimeObjects(for channel: AblyPlugin.RealtimeChannel) -> InternalDefaultRealtimeObjects { + private func realtimeObjects(for channel: _AblyPluginSupportPrivate.RealtimeChannel) -> InternalDefaultRealtimeObjects { Self.realtimeObjects(for: channel, pluginAPI: pluginAPI) } /// A class that wraps an object message. /// - /// We need this intermediate type because we want object messages to be structs — because they're nicer to work with internally — but a struct can't conform to the class-bound `AblyPlugin.ObjectMessageProtocol`. - private final class ObjectMessageBox: AblyPlugin.ObjectMessageProtocol where T: Sendable { + /// We need this intermediate type because we want object messages to be structs — because they're nicer to work with internally — but a struct can't conform to the class-bound `_AblyPluginSupportPrivate.ObjectMessageProtocol`. + private final class ObjectMessageBox: _AblyPluginSupportPrivate.ObjectMessageProtocol where T: Sendable { internal let objectMessage: T init(objectMessage: T) { @@ -68,9 +70,9 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte _ serialized: [String: Any], context: DecodingContextProtocol, format: EncodingFormat, - error errorPtr: AutoreleasingUnsafeMutablePointer?, + error errorPtr: AutoreleasingUnsafeMutablePointer<_AblyPluginSupportPrivate.PublicErrorInfo?>?, ) -> (any ObjectMessageProtocol)? { - let wireObject = WireValue.objectFromAblyPluginData(serialized) + let wireObject = WireValue.objectFromPluginSupportData(serialized) do { let wireObjectMessage = try InboundWireObjectMessage( @@ -83,13 +85,13 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte ) return ObjectMessageBox(objectMessage: objectMessage) } catch { - errorPtr?.pointee = error.toARTErrorInfo() + errorPtr?.pointee = error.toARTErrorInfo().asPluginPublicErrorInfo return nil } } internal func encodeObjectMessage( - _ publicObjectMessage: any AblyPlugin.ObjectMessageProtocol, + _ publicObjectMessage: any _AblyPluginSupportPrivate.ObjectMessageProtocol, format: EncodingFormat, ) -> [String: Any] { guard let outboundObjectMessageBox = publicObjectMessage as? ObjectMessageBox else { @@ -97,14 +99,14 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte } let wireObjectMessage = outboundObjectMessageBox.objectMessage.toWire(format: format) - return wireObjectMessage.toWireObject.toAblyPluginDataDictionary + return wireObjectMessage.toWireObject.toPluginSupportDataDictionary } - internal func onChannelAttached(_ channel: AblyPlugin.RealtimeChannel, hasObjects: Bool) { + internal func onChannelAttached(_ channel: _AblyPluginSupportPrivate.RealtimeChannel, hasObjects: Bool) { realtimeObjects(for: channel).onChannelAttached(hasObjects: hasObjects) } - internal func handleObjectProtocolMessage(withObjectMessages publicObjectMessages: [any AblyPlugin.ObjectMessageProtocol], channel: AblyPlugin.RealtimeChannel) { + internal func handleObjectProtocolMessage(withObjectMessages publicObjectMessages: [any _AblyPluginSupportPrivate.ObjectMessageProtocol], channel: _AblyPluginSupportPrivate.RealtimeChannel) { guard let inboundObjectMessageBoxes = publicObjectMessages as? [ObjectMessageBox] else { preconditionFailure("Expected to receive the same InboundObjectMessage type as we emit") } @@ -116,7 +118,7 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte ) } - internal func handleObjectSyncProtocolMessage(withObjectMessages publicObjectMessages: [any AblyPlugin.ObjectMessageProtocol], protocolMessageChannelSerial: String?, channel: AblyPlugin.RealtimeChannel) { + internal func handleObjectSyncProtocolMessage(withObjectMessages publicObjectMessages: [any _AblyPluginSupportPrivate.ObjectMessageProtocol], protocolMessageChannelSerial: String?, channel: _AblyPluginSupportPrivate.RealtimeChannel) { guard let inboundObjectMessageBoxes = publicObjectMessages as? [ObjectMessageBox] else { preconditionFailure("Expected to receive the same InboundObjectMessage type as we emit") } @@ -133,8 +135,8 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte internal static func sendObject( objectMessages: [OutboundObjectMessage], - channel: AblyPlugin.RealtimeChannel, - client: AblyPlugin.RealtimeClient, + channel: _AblyPluginSupportPrivate.RealtimeChannel, + client: _AblyPluginSupportPrivate.RealtimeClient, pluginAPI: PluginAPIProtocol, ) async throws(InternalError) { let objectMessageBoxes: [ObjectMessageBox] = objectMessages.map { .init(objectMessage: $0) } diff --git a/Sources/AblyLiveObjects/Internal/InternalDefaultLiveCounter.swift b/Sources/AblyLiveObjects/Internal/InternalDefaultLiveCounter.swift index a5d7058a..9c314bc0 100644 --- a/Sources/AblyLiveObjects/Internal/InternalDefaultLiveCounter.swift +++ b/Sources/AblyLiveObjects/Internal/InternalDefaultLiveCounter.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin import Foundation /// This provides the implementation behind ``PublicDefaultLiveCounter``, via internal versions of the ``LiveCounter`` API. @@ -21,7 +21,7 @@ internal final class InternalDefaultLiveCounter: Sendable { } } - private let logger: AblyPlugin.Logger + private let logger: Logger private let userCallbackQueue: DispatchQueue private let clock: SimpleClock @@ -30,7 +30,7 @@ internal final class InternalDefaultLiveCounter: Sendable { internal convenience init( testsOnly_data data: Double, objectID: String, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock ) { @@ -40,7 +40,7 @@ internal final class InternalDefaultLiveCounter: Sendable { private init( data: Double, objectID: String, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock ) { @@ -56,7 +56,7 @@ internal final class InternalDefaultLiveCounter: Sendable { /// - objectID: The value for the "private objectId field" of RTO5c1b1a. internal static func createZeroValued( objectID: String, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> Self { diff --git a/Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift b/Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift index 312affaa..84a94c25 100644 --- a/Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift +++ b/Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin /// Protocol for accessing objects from the ObjectsPool. This is used by a LiveMap when it needs to return an object given an object ID. internal protocol LiveMapObjectPoolDelegate: AnyObject, Sendable { @@ -38,7 +38,7 @@ internal final class InternalDefaultLiveMap: Sendable { } } - private let logger: AblyPlugin.Logger + private let logger: Logger private let userCallbackQueue: DispatchQueue private let clock: SimpleClock @@ -48,7 +48,7 @@ internal final class InternalDefaultLiveMap: Sendable { testsOnly_data data: [String: InternalObjectsMapEntry], objectID: String, testsOnly_semantics semantics: WireEnum? = nil, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) { @@ -66,7 +66,7 @@ internal final class InternalDefaultLiveMap: Sendable { data: [String: InternalObjectsMapEntry], objectID: String, semantics: WireEnum?, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) { @@ -84,7 +84,7 @@ internal final class InternalDefaultLiveMap: Sendable { internal static func createZeroValued( objectID: String, semantics: WireEnum? = nil, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> Self { @@ -398,7 +398,7 @@ internal final class InternalDefaultLiveMap: Sendable { using state: ObjectState, objectMessageSerialTimestamp: Date?, objectsPool: inout ObjectsPool, - logger: AblyPlugin.Logger, + logger: Logger, clock: SimpleClock, userCallbackQueue: DispatchQueue, ) -> LiveObjectUpdate { @@ -467,7 +467,7 @@ internal final class InternalDefaultLiveMap: Sendable { internal mutating func mergeInitialValue( from operation: ObjectOperation, objectsPool: inout ObjectsPool, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> LiveObjectUpdate { @@ -621,7 +621,7 @@ internal final class InternalDefaultLiveMap: Sendable { operationTimeserial: String?, operationData: ObjectData?, objectsPool: inout ObjectsPool, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> LiveObjectUpdate { @@ -744,7 +744,7 @@ internal final class InternalDefaultLiveMap: Sendable { internal mutating func applyMapCreateOperation( _ operation: ObjectOperation, objectsPool: inout ObjectsPool, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> LiveObjectUpdate { diff --git a/Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift b/Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift index af12e8a5..c989756c 100644 --- a/Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift +++ b/Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin /// This provides the implementation behind ``PublicDefaultRealtimeObjects``, via internal versions of the ``RealtimeObjects`` API. internal final class InternalDefaultRealtimeObjects: Sendable, LiveMapObjectPoolDelegate { @@ -8,7 +8,7 @@ internal final class InternalDefaultRealtimeObjects: Sendable, LiveMapObjectPool private nonisolated(unsafe) var mutableState: MutableState! - private let logger: AblyPlugin.Logger + private let logger: Logger private let userCallbackQueue: DispatchQueue private let clock: SimpleClock @@ -91,7 +91,7 @@ internal final class InternalDefaultRealtimeObjects: Sendable, LiveMapObjectPool } } - internal init(logger: AblyPlugin.Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, garbageCollectionOptions: GarbageCollectionOptions = .init()) { + internal init(logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, garbageCollectionOptions: GarbageCollectionOptions = .init()) { self.logger = logger self.userCallbackQueue = userCallbackQueue self.clock = clock diff --git a/Sources/AblyLiveObjects/Internal/InternalLiveObject.swift b/Sources/AblyLiveObjects/Internal/InternalLiveObject.swift index d80d53b4..27b0d7e8 100644 --- a/Sources/AblyLiveObjects/Internal/InternalLiveObject.swift +++ b/Sources/AblyLiveObjects/Internal/InternalLiveObject.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate /// Provides RTLO spec point functionality common to all LiveObjects. /// diff --git a/Sources/AblyLiveObjects/Internal/LiveObjectMutableState.swift b/Sources/AblyLiveObjects/Internal/LiveObjectMutableState.swift index f3326208..191d312c 100644 --- a/Sources/AblyLiveObjects/Internal/LiveObjectMutableState.swift +++ b/Sources/AblyLiveObjects/Internal/LiveObjectMutableState.swift @@ -1,4 +1,5 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate +import Ably /// This is the equivalent of the `LiveObject` abstract class described in RTLO. /// diff --git a/Sources/AblyLiveObjects/Internal/ObjectCreationHelpers.swift b/Sources/AblyLiveObjects/Internal/ObjectCreationHelpers.swift index b82f7d84..f061302e 100644 --- a/Sources/AblyLiveObjects/Internal/ObjectCreationHelpers.swift +++ b/Sources/AblyLiveObjects/Internal/ObjectCreationHelpers.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate import CryptoKit import Foundation diff --git a/Sources/AblyLiveObjects/Internal/ObjectsPool.swift b/Sources/AblyLiveObjects/Internal/ObjectsPool.swift index d2ff6481..3cef1dea 100644 --- a/Sources/AblyLiveObjects/Internal/ObjectsPool.swift +++ b/Sources/AblyLiveObjects/Internal/ObjectsPool.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate /// Maintains the list of objects present on a channel, as described by RTO3. /// @@ -137,7 +137,7 @@ internal struct ObjectsPool { /// Creates an `ObjectsPool` whose root is a zero-value `LiveMap`. internal init( - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, testsOnly_otherEntries otherEntries: [String: Entry]? = nil, @@ -151,7 +151,7 @@ internal struct ObjectsPool { } private init( - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, otherEntries: [String: Entry]? @@ -187,7 +187,7 @@ internal struct ObjectsPool { /// - userCallbackQueue: The callback queue to use for any created LiveObject /// - clock: The clock to use for any created LiveObject /// - Returns: The existing or newly created object - internal mutating func createZeroValueObject(forObjectID objectID: String, logger: AblyPlugin.Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock) -> Entry? { + internal mutating func createZeroValueObject(forObjectID objectID: String, logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock) -> Entry? { // RTO6a: If an object with objectId exists in ObjectsPool, do not create a new object if let existingEntry = entries[objectID] { return existingEntry @@ -220,7 +220,7 @@ internal struct ObjectsPool { /// Applies the objects gathered during an `OBJECT_SYNC` to this `ObjectsPool`, per RTO5c1 and RTO5c2. internal mutating func applySyncObjectsPool( _ syncObjectsPool: [SyncObjectsPoolEntry], - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) { @@ -316,7 +316,7 @@ internal struct ObjectsPool { /// - Returns: The existing or newly created counter object internal mutating func getOrCreateCounter( creationOperation: ObjectCreationHelpers.CounterCreationOperation, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> InternalDefaultLiveCounter { @@ -360,7 +360,7 @@ internal struct ObjectsPool { /// - Returns: The existing or newly created map object internal mutating func getOrCreateMap( creationOperation: ObjectCreationHelpers.MapCreationOperation, - logger: AblyPlugin.Logger, + logger: Logger, userCallbackQueue: DispatchQueue, clock: SimpleClock, ) -> InternalDefaultLiveMap { diff --git a/Sources/AblyLiveObjects/Protocol/ObjectMessage.swift b/Sources/AblyLiveObjects/Protocol/ObjectMessage.swift index 0a240199..ac846fcd 100644 --- a/Sources/AblyLiveObjects/Protocol/ObjectMessage.swift +++ b/Sources/AblyLiveObjects/Protocol/ObjectMessage.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate import Foundation // This file contains the ObjectMessage types that we use within the codebase. We convert them to and from the corresponding wire types (e.g. `InboundWireObjectMessage`) for sending and receiving over the wire. @@ -97,7 +97,7 @@ internal extension InboundObjectMessage { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectMessage: InboundWireObjectMessage, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { id = wireObjectMessage.id clientId = wireObjectMessage.clientId @@ -121,7 +121,7 @@ internal extension OutboundObjectMessage { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> OutboundWireObjectMessage { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> OutboundWireObjectMessage { .init( id: id, clientId: clientId, @@ -145,7 +145,7 @@ internal extension ObjectOperation { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectOperation: WireObjectOperation, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { // Decode the action and objectId first they're not part of PartialObjectOperation action = wireObjectOperation.action @@ -177,7 +177,7 @@ internal extension ObjectOperation { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> WireObjectOperation { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> WireObjectOperation { let partialWireOperation = PartialObjectOperation( mapOp: mapOp, counterOp: counterOp, @@ -209,7 +209,7 @@ internal extension PartialObjectOperation { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( partialWireObjectOperation: PartialWireObjectOperation, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { mapOp = try partialWireObjectOperation.mapOp.map { wireObjectsMapOp throws(InternalError) in try .init(wireObjectsMapOp: wireObjectsMapOp, format: format) @@ -230,7 +230,7 @@ internal extension PartialObjectOperation { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> PartialWireObjectOperation { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> PartialWireObjectOperation { .init( mapOp: mapOp?.toWire(format: format), counterOp: counterOp, @@ -250,7 +250,7 @@ internal extension ObjectData { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectData: WireObjectData, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { objectId = wireObjectData.objectId boolean = wireObjectData.boolean @@ -302,7 +302,7 @@ internal extension ObjectData { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> WireObjectData { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> WireObjectData { // OD4: Encode data based on format let wireBytes: StringOrData? = if let bytes { switch format { @@ -354,7 +354,7 @@ internal extension ObjectsMapOp { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectsMapOp: WireObjectsMapOp, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { key = wireObjectsMapOp.key data = try wireObjectsMapOp.data.map { wireObjectData throws(InternalError) in @@ -366,7 +366,7 @@ internal extension ObjectsMapOp { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> WireObjectsMapOp { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> WireObjectsMapOp { .init( key: key, data: data?.toWire(format: format), @@ -382,7 +382,7 @@ internal extension ObjectsMapEntry { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectsMapEntry: WireObjectsMapEntry, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { tombstone = wireObjectsMapEntry.tombstone timeserial = wireObjectsMapEntry.timeserial @@ -398,7 +398,7 @@ internal extension ObjectsMapEntry { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> WireObjectsMapEntry { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> WireObjectsMapEntry { .init( tombstone: tombstone, timeserial: timeserial, @@ -415,7 +415,7 @@ internal extension ObjectsMap { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectsMap: WireObjectsMap, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { semantics = wireObjectsMap.semantics entries = try wireObjectsMap.entries?.ablyLiveObjects_mapValuesWithTypedThrow { wireMapEntry throws(InternalError) in @@ -427,7 +427,7 @@ internal extension ObjectsMap { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> WireObjectsMap { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> WireObjectsMap { .init( semantics: semantics, entries: entries?.mapValues { $0.toWire(format: format) }, @@ -443,7 +443,7 @@ internal extension ObjectState { /// - Throws: `InternalError` if JSON or Base64 decoding fails. init( wireObjectState: WireObjectState, - format: AblyPlugin.EncodingFormat + format: _AblyPluginSupportPrivate.EncodingFormat ) throws(InternalError) { objectId = wireObjectState.objectId siteTimeserials = wireObjectState.siteTimeserials @@ -461,7 +461,7 @@ internal extension ObjectState { /// /// - Parameters: /// - format: The format to use when applying the encoding rules of OD4. - func toWire(format: AblyPlugin.EncodingFormat) -> WireObjectState { + func toWire(format: _AblyPluginSupportPrivate.EncodingFormat) -> WireObjectState { .init( objectId: objectId, siteTimeserials: siteTimeserials, diff --git a/Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift b/Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift index fad740a3..a8c55d53 100644 --- a/Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift +++ b/Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate import Foundation // This file contains the ObjectMessage types that we send and receive over the wire. We convert them to and from the corresponding non-wire types (e.g. `InboundObjectMessage`) for use within the codebase. @@ -61,7 +61,7 @@ internal extension InboundWireObjectMessage { /// Decodes the `ObjectMessage` and then uses the containing `ProtocolMessage` to populate some absent fields per the rules of the specification. init( wireObject: [String: WireValue], - decodingContext: AblyPlugin.DecodingContextProtocol + decodingContext: _AblyPluginSupportPrivate.DecodingContextProtocol ) throws(InternalError) { // OM2a if let id = try wireObject.optionalStringValueForKey(WireObjectMessageWireKey.id.rawValue) { diff --git a/Sources/AblyLiveObjects/Public/ARTRealtimeChannel+Objects.swift b/Sources/AblyLiveObjects/Public/ARTRealtimeChannel+Objects.swift index da479178..cec5ca94 100644 --- a/Sources/AblyLiveObjects/Public/ARTRealtimeChannel+Objects.swift +++ b/Sources/AblyLiveObjects/Public/ARTRealtimeChannel+Objects.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin public extension ARTRealtimeChannel { /// A ``RealtimeObjects`` object. @@ -9,10 +9,11 @@ public extension ARTRealtimeChannel { private var nonTypeErasedObjects: PublicDefaultRealtimeObjects { let pluginAPI = Plugin.defaultPluginAPI - let underlyingObjects = pluginAPI.underlyingObjects(forPublicRealtimeChannel: self) + let underlyingObjects = pluginAPI.underlyingObjects(for: asPluginPublicRealtimeChannel) let internalObjects = DefaultInternalPlugin.realtimeObjects(for: underlyingObjects.channel, pluginAPI: pluginAPI) - let logger = pluginAPI.logger(for: underlyingObjects.channel) + let pluginLogger = pluginAPI.logger(for: underlyingObjects.channel) + let logger = DefaultLogger(pluginLogger: pluginLogger, pluginAPI: pluginAPI) let coreSDK = DefaultCoreSDK( channel: underlyingObjects.channel, diff --git a/Sources/AblyLiveObjects/Public/Plugin.swift b/Sources/AblyLiveObjects/Public/Plugin.swift index 26a377d4..799c3542 100644 --- a/Sources/AblyLiveObjects/Public/Plugin.swift +++ b/Sources/AblyLiveObjects/Public/Plugin.swift @@ -1,6 +1,6 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate -// We explicitly import the NSObject class, else it seems to get transitively imported from `internal import AblyPlugin`, leading to the error "Class cannot be declared public because its superclass is internal". +// We explicitly import the NSObject class, else it seems to get transitively imported from `internal import _AblyPluginSupportPrivate`, leading to the error "Class cannot be declared public because its superclass is internal". import ObjectiveC.NSObject /// This plugin enables LiveObjects functionality in ably-cocoa. Set the `.liveObjects` key in the ably-cocoa `plugins` client option to this class in order to enable LiveObjects. @@ -22,10 +22,10 @@ import ObjectiveC.NSObject /// ``` @objc public class Plugin: NSObject { - /// The `AblyPlugin.PluginAPIProtocol` that the LiveObjects plugin should use by default (i.e. when one hasn't been injected for test purposes). - internal static let defaultPluginAPI: AblyPlugin.PluginAPIProtocol = AblyPlugin.PluginAPI.sharedInstance() + /// The `_AblyPluginSupportPrivate.PluginAPIProtocol` that the LiveObjects plugin should use by default (i.e. when one hasn't been injected for test purposes). + internal static let defaultPluginAPI = _AblyPluginSupportPrivate.DependencyStore.sharedInstance().fetchPluginAPI() - // MARK: - Informal conformance to AblyPlugin.LiveObjectsPluginProtocol + // MARK: - Informal conformance to _AblyPluginSupportPrivate.LiveObjectsPluginProtocol @objc private static let internalPlugin = DefaultInternalPlugin(pluginAPI: defaultPluginAPI) } diff --git a/Sources/AblyLiveObjects/Public/Public Proxy Objects/InternalLiveMapValue+ToPublic.swift b/Sources/AblyLiveObjects/Public/Public Proxy Objects/InternalLiveMapValue+ToPublic.swift index bd88d2fb..fa7e7bb3 100644 --- a/Sources/AblyLiveObjects/Public/Public Proxy Objects/InternalLiveMapValue+ToPublic.swift +++ b/Sources/AblyLiveObjects/Public/Public Proxy Objects/InternalLiveMapValue+ToPublic.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate internal extension InternalLiveMapValue { // MARK: - Mapping to public types @@ -6,7 +6,7 @@ internal extension InternalLiveMapValue { struct PublicValueCreationArgs { internal var coreSDK: CoreSDK internal var mapDelegate: LiveMapObjectPoolDelegate - internal var logger: AblyPlugin.Logger + internal var logger: Logger internal var toCounterCreationArgs: PublicObjectsStore.CounterCreationArgs { .init(coreSDK: coreSDK, logger: logger) diff --git a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveCounter.swift b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveCounter.swift index 146d05e6..90a408da 100644 --- a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveCounter.swift +++ b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveCounter.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin /// Our default implementation of ``LiveCounter``. /// @@ -10,9 +10,9 @@ internal final class PublicDefaultLiveCounter: LiveCounter { // MARK: - Dependencies that hold a strong reference to `proxied` private let coreSDK: CoreSDK - private let logger: AblyPlugin.Logger + private let logger: Logger - internal init(proxied: InternalDefaultLiveCounter, coreSDK: CoreSDK, logger: AblyPlugin.Logger) { + internal init(proxied: InternalDefaultLiveCounter, coreSDK: CoreSDK, logger: Logger) { self.proxied = proxied self.coreSDK = coreSDK self.logger = logger diff --git a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveMap.swift b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveMap.swift index 52e207d2..5aad18fa 100644 --- a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveMap.swift +++ b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultLiveMap.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin /// Our default implementation of ``LiveMap``. /// @@ -11,9 +11,9 @@ internal final class PublicDefaultLiveMap: LiveMap { private let coreSDK: CoreSDK private let delegate: LiveMapObjectPoolDelegate - private let logger: AblyPlugin.Logger + private let logger: Logger - internal init(proxied: InternalDefaultLiveMap, coreSDK: CoreSDK, delegate: LiveMapObjectPoolDelegate, logger: AblyPlugin.Logger) { + internal init(proxied: InternalDefaultLiveMap, coreSDK: CoreSDK, delegate: LiveMapObjectPoolDelegate, logger: Logger) { self.proxied = proxied self.coreSDK = coreSDK self.delegate = delegate diff --git a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultRealtimeObjects.swift b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultRealtimeObjects.swift index 3d97b8b5..34221ad6 100644 --- a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultRealtimeObjects.swift +++ b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicDefaultRealtimeObjects.swift @@ -1,5 +1,5 @@ +internal import _AblyPluginSupportPrivate import Ably -internal import AblyPlugin /// The class that provides the public API for interacting with LiveObjects, via the ``ARTRealtimeChannel/objects`` property. /// @@ -13,9 +13,9 @@ internal final class PublicDefaultRealtimeObjects: RealtimeObjects { // MARK: - Dependencies that hold a strong reference to `proxied` private let coreSDK: CoreSDK - private let logger: AblyPlugin.Logger + private let logger: Logger - internal init(proxied: InternalDefaultRealtimeObjects, coreSDK: CoreSDK, logger: AblyPlugin.Logger) { + internal init(proxied: InternalDefaultRealtimeObjects, coreSDK: CoreSDK, logger: Logger) { self.proxied = proxied self.coreSDK = coreSDK self.logger = logger diff --git a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicObjectsStore.swift b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicObjectsStore.swift index 4be07534..264a92cc 100644 --- a/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicObjectsStore.swift +++ b/Sources/AblyLiveObjects/Public/Public Proxy Objects/PublicObjectsStore.swift @@ -1,4 +1,4 @@ -internal import AblyPlugin +internal import _AblyPluginSupportPrivate import Foundation /// Stores the public objects that wrap the SDK's internal components. @@ -21,7 +21,7 @@ internal final class PublicObjectsStore: Sendable { internal struct RealtimeObjectsCreationArgs { internal var coreSDK: CoreSDK - internal var logger: AblyPlugin.Logger + internal var logger: Logger } /// Fetches the cached `PublicDefaultRealtimeObjects` that wraps a given `InternalDefaultRealtimeObjects`, creating a new public object if there isn't already one. @@ -33,7 +33,7 @@ internal final class PublicObjectsStore: Sendable { internal struct CounterCreationArgs { internal var coreSDK: CoreSDK - internal var logger: AblyPlugin.Logger + internal var logger: Logger } /// Fetches the cached `PublicDefaultLiveCounter` that wraps a given `InternalDefaultLiveCounter`, creating a new public object if there isn't already one. @@ -46,7 +46,7 @@ internal final class PublicObjectsStore: Sendable { internal struct MapCreationArgs { internal var coreSDK: CoreSDK internal var delegate: LiveMapObjectPoolDelegate - internal var logger: AblyPlugin.Logger + internal var logger: Logger } /// Fetches the cached `PublicDefaultLiveMap` that wraps a given `InternalDefaultLiveMap`, creating a new public object if there isn't already one. @@ -68,7 +68,7 @@ internal final class PublicObjectsStore: Sendable { /// Fetches the proxy that wraps `proxied`, creating a new proxy if there isn't already one. Stores a weak reference to the proxy. mutating func getOrCreate( proxying proxied: some AnyObject, - logger: AblyPlugin.Logger, + logger: Logger, logObjectType: String, createProxy: () -> Proxy, ) -> Proxy { @@ -90,7 +90,7 @@ internal final class PublicObjectsStore: Sendable { return created } - private mutating func removeDeallocatedEntries(logger: AblyPlugin.Logger, logObjectType: String) { + private mutating func removeDeallocatedEntries(logger: Logger, logObjectType: String) { var keysToRemove: Set = [] for (proxiedObjectIdentifier, weakProxyRef) in proxiesByProxiedObjectIdentifier where weakProxyRef.referenced == nil { logger.log("Clearing unused \(logObjectType) proxy from cache (proxied: \(proxiedObjectIdentifier))", level: .debug) diff --git a/Sources/AblyLiveObjects/Utility/APLogger+Swift.swift b/Sources/AblyLiveObjects/Utility/APLogger+Swift.swift deleted file mode 100644 index 276621d1..00000000 --- a/Sources/AblyLiveObjects/Utility/APLogger+Swift.swift +++ /dev/null @@ -1,8 +0,0 @@ -internal import AblyPlugin - -internal extension AblyPlugin.Logger { - /// A convenience method that provides default values for `file` and `line`. - func log(_ message: String, level: ARTLogLevel, fileID: String = #fileID, line: Int = #line) { - log(message, with: level, file: fileID, line: line) - } -} diff --git a/Sources/AblyLiveObjects/Utility/Errors.swift b/Sources/AblyLiveObjects/Utility/Errors.swift index 941d3e8b..1ab2e661 100644 --- a/Sources/AblyLiveObjects/Utility/Errors.swift +++ b/Sources/AblyLiveObjects/Utility/Errors.swift @@ -1,3 +1,4 @@ +internal import _AblyPluginSupportPrivate import Ably /** @@ -5,7 +6,7 @@ import Ably */ internal enum LiveObjectsError { // operationDescription should be a description of a method like "LiveCounter.value"; it will be interpolated into an error message - case objectsOperationFailedInvalidChannelState(operationDescription: String, channelState: ARTRealtimeChannelState) + case objectsOperationFailedInvalidChannelState(operationDescription: String, channelState: _AblyPluginSupportPrivate.RealtimeChannelState) case counterInitialValueInvalid(value: Double) case counterIncrementAmountInvalid(amount: Double) diff --git a/Sources/AblyLiveObjects/Utility/InternalError.swift b/Sources/AblyLiveObjects/Utility/InternalError.swift index e9fbf705..4492cf6a 100644 --- a/Sources/AblyLiveObjects/Utility/InternalError.swift +++ b/Sources/AblyLiveObjects/Utility/InternalError.swift @@ -1,3 +1,4 @@ +internal import _AblyPluginSupportPrivate import Ably /// An error thrown by the internals of the LiveObjects SDK. @@ -35,3 +36,9 @@ internal extension ARTErrorInfo { .errorInfo(self) } } + +internal extension _AblyPluginSupportPrivate.PublicErrorInfo { + func toInternalError() -> InternalError { + ARTErrorInfo.castPluginPublicErrorInfo(self).toInternalError() + } +} diff --git a/Sources/AblyLiveObjects/Utility/Logger.swift b/Sources/AblyLiveObjects/Utility/Logger.swift new file mode 100644 index 00000000..94cfca9a --- /dev/null +++ b/Sources/AblyLiveObjects/Utility/Logger.swift @@ -0,0 +1,41 @@ +internal import _AblyPluginSupportPrivate + +/// A reference to a line within a source code file. +internal struct CodeLocation: Equatable { + /// A file identifier in the format used by Swift’s `#fileID` macro. For example, `"AblyChat/Room.swift"`. + internal var fileID: String + /// The line number in the source code file referred to by ``fileID``. + internal var line: Int +} + +internal protocol Logger: Sendable { + func log(_ message: String, level: _AblyPluginSupportPrivate.LogLevel, codeLocation: CodeLocation) +} + +internal extension AblyLiveObjects.Logger { + /// A convenience method that provides default values for `file` and `line`. + func log(_ message: String, level: _AblyPluginSupportPrivate.LogLevel, fileID: String = #fileID, line: Int = #line) { + let codeLocation = CodeLocation(fileID: fileID, line: line) + log(message, level: level, codeLocation: codeLocation) + } +} + +internal final class DefaultLogger: Logger { + private let pluginLogger: _AblyPluginSupportPrivate.Logger + private let pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol + + internal init(pluginLogger: _AblyPluginSupportPrivate.Logger, pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol) { + self.pluginLogger = pluginLogger + self.pluginAPI = pluginAPI + } + + internal func log(_ message: String, level: LogLevel, codeLocation: CodeLocation) { + pluginAPI.log( + message, + with: level, + file: codeLocation.fileID, + line: codeLocation.line, + logger: pluginLogger, + ) + } +} diff --git a/Sources/AblyLiveObjects/Utility/MarkerProtocolHelpers.swift b/Sources/AblyLiveObjects/Utility/MarkerProtocolHelpers.swift new file mode 100644 index 00000000..28bf619c --- /dev/null +++ b/Sources/AblyLiveObjects/Utility/MarkerProtocolHelpers.swift @@ -0,0 +1,54 @@ +internal import _AblyPluginSupportPrivate +import Ably + +/// Upcasts an instance of an `_AblyPluginSupportPrivate` marker protocol to the concrete type that this marker protocol represents. +internal func castPluginPublicMarkerProtocolValue(_ pluginMarkerProtocolValue: Any, to _: T.Type) -> T { + guard let actualPublicValue = pluginMarkerProtocolValue as? T else { + preconditionFailure("Expected \(T.self), got \(type(of: pluginMarkerProtocolValue))") + } + + return actualPublicValue +} + +internal extension ARTRealtimeChannel { + /// Downcasts this `ARTRealtimeChannel` to its `_AblyPluginSupportPrivate` equivalent type `PublicRealtimeChannel`. + /// + /// - Note: Swift compiler restrictions prevent us from declaring `ARTRealtimeChannel` as conforming to `PublicRealtimeChannel` (this is due to our use of `internal import`). + var asPluginPublicRealtimeChannel: _AblyPluginSupportPrivate.PublicRealtimeChannel { + // In order for this cast to succeed, we rely on the fact that ably-cocoa internally declares ARTRealtimeChannel as conforming to PublicRealtimeChannel. + // swiftlint:disable:next force_cast + self as! _AblyPluginSupportPrivate.PublicRealtimeChannel + } +} + +internal extension ARTClientOptions { + /// Downcasts this `ARTClientOptions` to its `_AblyPluginSupportPrivate` marker protocol type `PublicClientOptions`. + /// + /// - Note: Swift compiler restrictions prevent us from declaring `ARTClientOptions` as conforming to `PublicClientOptions` (this is due to our use of `internal import`). + var asPluginPublicClientOptions: _AblyPluginSupportPrivate.PublicClientOptions { + // In order for this cast to succeed, we rely on the fact that ably-cocoa internally declares ARTClientOptions as conforming to PublicClientOptions. + // swiftlint:disable:next force_cast + self as! _AblyPluginSupportPrivate.PublicClientOptions + } + + /// Upcasts an instance of `_AblyPluginSupportPrivate`'s `PublicClientOptions`, which is the marker protocol that it uses to represent an `ARTClientOptions`, to an `ARTClientOptions`. + static func castPluginPublicClientOptions(_ pluginPublicClientOptions: PublicClientOptions) -> Self { + castPluginPublicMarkerProtocolValue(pluginPublicClientOptions, to: Self.self) + } +} + +internal extension ARTErrorInfo { + /// Downcasts this `ARTErrorInfo` to its `_AblyPluginSupportPrivate` marker protocol type `PublicErrorInfo`. + /// + /// - Note: Swift compiler restrictions prevent us from declaring `ARTErrorInfo` as conforming to `PublicErrorInfo` (this is due to our use of `internal import`). + var asPluginPublicErrorInfo: _AblyPluginSupportPrivate.PublicErrorInfo { + // In order for this cast to succeed, we rely on the fact that ably-cocoa internally declares ARTErrorInfo as conforming to PublicErrorInfo. + // swiftlint:disable:next force_cast + self as! _AblyPluginSupportPrivate.PublicErrorInfo + } + + /// Upcasts an instance of `_AblyPluginSupportPrivate`'s `PublicErrorInfo`, which is the marker protocol that it uses to represent an `ARTErrorInfo`, to an `ARTErrorInfo`. + static func castPluginPublicErrorInfo(_ pluginPublicErrorInfo: PublicErrorInfo) -> Self { + castPluginPublicMarkerProtocolValue(pluginPublicErrorInfo, to: Self.self) + } +} diff --git a/Sources/AblyLiveObjects/Utility/WireValue.swift b/Sources/AblyLiveObjects/Utility/WireValue.swift index e2e6f5d8..6e82a258 100644 --- a/Sources/AblyLiveObjects/Utility/WireValue.swift +++ b/Sources/AblyLiveObjects/Utility/WireValue.swift @@ -1,7 +1,7 @@ import Ably import Foundation -/// A wire value that can be represents the kinds of data that we expect to find inside a deserialized wire object received from AblyPlugin, or which we may put inside a serialized wire object that we send to AblyPlugin. +/// A wire value that can be represents the kinds of data that we expect to find inside a deserialized wire object received from `_AblyPluginSupportPrivate`, or which we may put inside a serialized wire object that we send to `_AblyPluginSupportPrivate`. /// /// Its cases are a superset of those of ``JSONValue``, adding a further `data` case for binary data (we expect to be able to send and receive binary data in the case where ably-cocoa is using the MessagePack format). internal indirect enum WireValue: Sendable, Equatable { @@ -118,27 +118,27 @@ extension WireValue: ExpressibleByBooleanLiteral { // MARK: - Bridging with ably-cocoa internal extension WireValue { - /// Creates a `WireValue` from an AblyPlugin deserialized wire object. + /// Creates a `WireValue` from an `_AblyPluginSupportPrivate` deserialized wire object. /// - /// Specifically, `ablyPluginData` can be a value that was passed to `LiveObjectsPlugin.decodeObjectMessage:…`. - init(ablyPluginData: Any) { + /// Specifically, `pluginSupportData` can be a value that was passed to `LiveObjectsPlugin.decodeObjectMessage:…`. + init(pluginSupportData: Any) { // swiftlint:disable:next trailing_closure - let extendedJSONValue = ExtendedJSONValue(deserialized: ablyPluginData, createExtraValue: { deserializedExtraValue in + let extendedJSONValue = ExtendedJSONValue(deserialized: pluginSupportData, createExtraValue: { deserializedExtraValue in // We support binary data (used for MessagePack format) in addition to JSON values if let data = deserializedExtraValue as? Data { return .data(data) } // ably-cocoa is not conforming to our assumptions; our assumptions are probably wrong. Either way, bring this loudly to our attention instead of trying to carry on - preconditionFailure("WireValue(ablyPluginData:) was given unsupported value \(deserializedExtraValue)") + preconditionFailure("WireValue(pluginSupportData:) was given unsupported value \(deserializedExtraValue)") }) self.init(extendedJSONValue: extendedJSONValue) } - /// Creates a `WireValue` from an AblyPlugin deserialized wire object. Specifically, `ablyPluginData` can be a value that was passed to `LiveObjectsPlugin.decodeObjectMessage:…`. - static func objectFromAblyPluginData(_ ablyPluginData: [String: Any]) -> [String: WireValue] { - let wireValue = WireValue(ablyPluginData: ablyPluginData) + /// Creates a `WireValue` from an `_AblyPluginSupportPrivate` deserialized wire object. Specifically, `pluginSupportData` can be a value that was passed to `LiveObjectsPlugin.decodeObjectMessage:…`. + static func objectFromPluginSupportData(_ pluginSupportData: [String: Any]) -> [String: WireValue] { + let wireValue = WireValue(pluginSupportData: pluginSupportData) guard case let .object(wireObject) = wireValue else { preconditionFailure() } @@ -146,10 +146,10 @@ internal extension WireValue { return wireObject } - /// Creates an AblyPlugin deserialized wire object from a `WireValue`. + /// Creates an `_AblyPluginSupportPrivate` deserialized wire object from a `WireValue`. /// - /// Used by `[String: WireValue].toAblyPluginDataDictionary`. - var toAblyPluginData: Any { + /// Used by `[String: WireValue].toPluginSupportDataDictionary`. + var toPluginSupportData: Any { // swiftlint:disable:next trailing_closure toExtendedJSONValue.serialized(serializeExtraValue: { extendedValue in switch extendedValue { @@ -161,11 +161,11 @@ internal extension WireValue { } internal extension [String: WireValue] { - /// Creates an AblyPlugin deserialized wire object from a dictionary that has string keys and `WireValue` values. + /// Creates an `_AblyPluginSupportPrivate` deserialized wire object from a dictionary that has string keys and `WireValue` values. /// /// Specifically, the value of this property can be returned from `APLiveObjectsPlugin.encodeObjectMessage:`. - var toAblyPluginDataDictionary: [String: Any] { - mapValues(\.toAblyPluginData) + var toPluginSupportDataDictionary: [String: Any] { + mapValues(\.toPluginSupportData) } } diff --git a/Tests/AblyLiveObjectsTests/AblyLiveObjectsTests.swift b/Tests/AblyLiveObjectsTests/AblyLiveObjectsTests.swift index e71959de..feaa8719 100644 --- a/Tests/AblyLiveObjectsTests/AblyLiveObjectsTests.swift +++ b/Tests/AblyLiveObjectsTests/AblyLiveObjectsTests.swift @@ -1,6 +1,6 @@ +import _AblyPluginSupportPrivate import Ably @testable import AblyLiveObjects -import AblyPlugin import Testing struct AblyLiveObjectsTests { diff --git a/Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift b/Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift index 441bf12f..89b2ddb5 100644 --- a/Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift +++ b/Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift @@ -1,5 +1,5 @@ +import _AblyPluginSupportPrivate @testable import AblyLiveObjects -import AblyPlugin import Foundation // Note that this file was created entirely by Cursor upon my giving it some guidelines — I have not checked its contents in any detail and it may well turn out that there are mistakes here which we need to fix in the future. diff --git a/Tests/AblyLiveObjectsTests/Helpers/TestLogger.swift b/Tests/AblyLiveObjectsTests/Helpers/TestLogger.swift index 59c51e17..3d53bdad 100644 --- a/Tests/AblyLiveObjectsTests/Helpers/TestLogger.swift +++ b/Tests/AblyLiveObjectsTests/Helpers/TestLogger.swift @@ -1,23 +1,24 @@ -import AblyPlugin +import _AblyPluginSupportPrivate +@testable import AblyLiveObjects import os -/// An implementation of `AblyPlugin.Logger` to use when testing internal components of the LiveObjects plugin. -final class TestLogger: NSObject, AblyPlugin.Logger { +/// An implementation of `Logger` to use when testing internal components of the LiveObjects plugin. +final class TestLogger: NSObject, AblyLiveObjects.Logger { // By default, we don’t log in tests to keep the test logs easy to read. You can set this property to `true` to temporarily turn logging on if you want to debug a test. static let loggingEnabled = false private let underlyingLogger = os.Logger() - func log(_ message: String, with level: ARTLogLevel, file fileName: UnsafePointer, line: Int) { + func log(_ message: String, level: LogLevel, codeLocation: CodeLocation) { guard Self.loggingEnabled else { return } - underlyingLogger.log(level: level.toOSLogType, "(\(String(cString: fileName)):\(line)): \(message)") + underlyingLogger.log(level: level.toOSLogType, "(\(codeLocation.fileID):\(codeLocation.line)): \(message)") } } -private extension ARTLogLevel { +private extension _AblyPluginSupportPrivate.LogLevel { var toOSLogType: OSLogType { // Not much thought has gone into this conversion switch self { diff --git a/Tests/AblyLiveObjectsTests/InternalDefaultLiveCounterTests.swift b/Tests/AblyLiveObjectsTests/InternalDefaultLiveCounterTests.swift index 039ec517..048a64ce 100644 --- a/Tests/AblyLiveObjectsTests/InternalDefaultLiveCounterTests.swift +++ b/Tests/AblyLiveObjectsTests/InternalDefaultLiveCounterTests.swift @@ -1,5 +1,6 @@ +import _AblyPluginSupportPrivate +import Ably @testable import AblyLiveObjects -import AblyPlugin import Foundation import Testing @@ -7,8 +8,8 @@ struct InternalDefaultLiveCounterTests { /// Tests for the `value` property, covering RTLC5 specification points struct ValueTests { // @spec RTLC5b - @Test(arguments: [.detached, .failed] as [ARTRealtimeChannelState]) - func valueThrowsIfChannelIsDetachedOrFailed(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func valueThrowsIfChannelIsDetachedOrFailed(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let logger = TestLogger() let counter = InternalDefaultLiveCounter.createZeroValued(objectID: "arbitrary", logger: logger, userCallbackQueue: .main, clock: MockSimpleClock()) let coreSDK = MockCoreSDK(channelState: channelState) @@ -426,8 +427,8 @@ struct InternalDefaultLiveCounterTests { /// Tests for the `increment` method, covering RTLC12 specification points struct IncrementTests { // @spec RTLC12c - @Test(arguments: [.detached, .failed, .suspended] as [ARTRealtimeChannelState]) - func throwsErrorForInvalidChannelState(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed, .suspended] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func throwsErrorForInvalidChannelState(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let logger = TestLogger() let counter = InternalDefaultLiveCounter.createZeroValued(objectID: "arbitrary", logger: logger, userCallbackQueue: .main, clock: MockSimpleClock()) let coreSDK = MockCoreSDK(channelState: channelState) diff --git a/Tests/AblyLiveObjectsTests/InternalDefaultLiveMapTests.swift b/Tests/AblyLiveObjectsTests/InternalDefaultLiveMapTests.swift index 9d982e99..f5b88904 100644 --- a/Tests/AblyLiveObjectsTests/InternalDefaultLiveMapTests.swift +++ b/Tests/AblyLiveObjectsTests/InternalDefaultLiveMapTests.swift @@ -1,5 +1,6 @@ +import _AblyPluginSupportPrivate +import Ably @testable import AblyLiveObjects -import AblyPlugin import Foundation import Testing @@ -7,8 +8,8 @@ struct InternalDefaultLiveMapTests { /// Tests for the `get` method, covering RTLM5 specification points struct GetTests { // @spec RTLM5c - @Test(arguments: [.detached, .failed] as [ARTRealtimeChannelState]) - func getThrowsIfChannelIsDetachedOrFailed(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func getThrowsIfChannelIsDetachedOrFailed(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let logger = TestLogger() let map = InternalDefaultLiveMap.createZeroValued(objectID: "arbitrary", logger: logger, userCallbackQueue: .main, clock: MockSimpleClock()) @@ -275,8 +276,8 @@ struct InternalDefaultLiveMapTests { // @spec RTLM11c // @spec RTLM12b // @spec RTLM13b - @Test(arguments: [.detached, .failed] as [ARTRealtimeChannelState]) - func allPropertiesThrowIfChannelIsDetachedOrFailed(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func allPropertiesThrowIfChannelIsDetachedOrFailed(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let logger = TestLogger() let map = InternalDefaultLiveMap.createZeroValued(objectID: "arbitrary", logger: logger, userCallbackQueue: .main, clock: MockSimpleClock()) let coreSDK = MockCoreSDK(channelState: channelState) @@ -1230,8 +1231,8 @@ struct InternalDefaultLiveMapTests { /// Tests for the `set` method, covering RTLM20 specification points struct SetTests { // @spec RTLM20c - @Test(arguments: [.detached, .failed, .suspended] as [ARTRealtimeChannelState]) - func throwsErrorForInvalidChannelState(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed, .suspended] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func throwsErrorForInvalidChannelState(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let logger = TestLogger() let map = InternalDefaultLiveMap.createZeroValued(objectID: "arbitrary", logger: logger, userCallbackQueue: .main, clock: MockSimpleClock()) let coreSDK = MockCoreSDK(channelState: channelState) @@ -1330,8 +1331,8 @@ struct InternalDefaultLiveMapTests { /// Tests for the `remove` method, covering RTLM21 specification points struct RemoveTests { // @spec RTLM21c - @Test(arguments: [.detached, .failed, .suspended] as [ARTRealtimeChannelState]) - func throwsErrorForInvalidChannelState(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed, .suspended] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func throwsErrorForInvalidChannelState(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let logger = TestLogger() let map = InternalDefaultLiveMap.createZeroValued(objectID: "arbitrary", logger: logger, userCallbackQueue: .main, clock: MockSimpleClock()) let coreSDK = MockCoreSDK(channelState: channelState) diff --git a/Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift b/Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift index b4bedee9..0406224e 100644 --- a/Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift +++ b/Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift @@ -1,6 +1,6 @@ +import _AblyPluginSupportPrivate import Ably @testable import AblyLiveObjects -import AblyPlugin import Testing /// Tests for `InternalDefaultRealtimeObjects`. @@ -672,8 +672,8 @@ struct InternalDefaultRealtimeObjectsTests { // MARK: - RTO1b Tests // @spec RTO1b - @Test(arguments: [.detached, .failed] as [ARTRealtimeChannelState]) - func getRootThrowsIfChannelIsDetachedOrFailed(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func getRootThrowsIfChannelIsDetachedOrFailed(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let realtimeObjects = InternalDefaultRealtimeObjectsTests.createDefaultRealtimeObjects() let coreSDK = MockCoreSDK(channelState: channelState) @@ -1044,8 +1044,8 @@ struct InternalDefaultRealtimeObjectsTests { /// Tests for `InternalDefaultRealtimeObjects.createMap`, covering RTO11 specification points (these are largely a smoke test, the rest being tested in ObjectCreationHelpers tests) struct CreateMapTests { // @spec RTO11d - @Test(arguments: [.detached, .failed, .suspended] as [ARTRealtimeChannelState]) - func throwsIfChannelIsInInvalidState(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed, .suspended] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func throwsIfChannelIsInInvalidState(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let realtimeObjects = InternalDefaultRealtimeObjectsTests.createDefaultRealtimeObjects() let coreSDK = MockCoreSDK(channelState: channelState) let entries: [String: InternalLiveMapValue] = ["testKey": .string("testValue")] @@ -1175,8 +1175,8 @@ struct InternalDefaultRealtimeObjectsTests { /// Tests for `InternalDefaultRealtimeObjects.createCounter`, covering RTO12 specification points (these are largely a smoke test, the rest being tested in ObjectCreationHelpers tests) struct CreateCounterTests { // @spec RTO12d - @Test(arguments: [.detached, .failed, .suspended] as [ARTRealtimeChannelState]) - func throwsIfChannelIsInInvalidState(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed, .suspended] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func throwsIfChannelIsInInvalidState(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { let realtimeObjects = InternalDefaultRealtimeObjectsTests.createDefaultRealtimeObjects() let coreSDK = MockCoreSDK(channelState: channelState) diff --git a/Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsHelper.swift b/Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsHelper.swift index 9f6671e5..77b78e16 100644 --- a/Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsHelper.swift +++ b/Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsHelper.swift @@ -1,6 +1,6 @@ +import _AblyPluginSupportPrivate import Ably @testable import AblyLiveObjects -import AblyPlugin import Foundation // This file is copied from the file objects.test.js in ably-js. @@ -330,7 +330,7 @@ final class ObjectsHelper: Sendable { logger: channel.internal.logger, ) - let foundationObject = deserialized.toAblyPluginDataDictionary + let foundationObject = deserialized.toPluginSupportDataDictionary let protocolMessage = withExtendedLifetime(jsonLikeEncoderDelegate) { encoder.protocolMessage(from: foundationObject)! } diff --git a/Tests/AblyLiveObjectsTests/LiveObjectMutableStateTests.swift b/Tests/AblyLiveObjectsTests/LiveObjectMutableStateTests.swift index ff39d7d4..dbb8857e 100644 --- a/Tests/AblyLiveObjectsTests/LiveObjectMutableStateTests.swift +++ b/Tests/AblyLiveObjectsTests/LiveObjectMutableStateTests.swift @@ -1,6 +1,6 @@ +import _AblyPluginSupportPrivate import Ably @testable import AblyLiveObjects -import AblyPlugin import Testing /// Tests for `LiveObjectMutableState`. @@ -119,8 +119,8 @@ struct LiveObjectMutableStateTests { // @spec RTLO4b2 @available(iOS 17.0.0, tvOS 17.0.0, *) - @Test(arguments: [.detached, .failed] as [ARTRealtimeChannelState]) - func subscribeThrowsIfChannelIsDetachedOrFailed(channelState: ARTRealtimeChannelState) async throws { + @Test(arguments: [.detached, .failed] as [_AblyPluginSupportPrivate.RealtimeChannelState]) + func subscribeThrowsIfChannelIsDetachedOrFailed(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) async throws { var mutableState = LiveObjectMutableState(objectID: "foo") let queue = DispatchQueue.main let subscriber = Subscriber(callbackQueue: queue) diff --git a/Tests/AblyLiveObjectsTests/Mocks/MockCoreSDK.swift b/Tests/AblyLiveObjectsTests/Mocks/MockCoreSDK.swift index 3bb48bbf..0c3980a6 100644 --- a/Tests/AblyLiveObjectsTests/Mocks/MockCoreSDK.swift +++ b/Tests/AblyLiveObjectsTests/Mocks/MockCoreSDK.swift @@ -1,3 +1,4 @@ +import _AblyPluginSupportPrivate import Ably @testable import AblyLiveObjects @@ -5,10 +6,10 @@ final class MockCoreSDK: CoreSDK { /// Synchronizes access to all of this instance's mutable state. private let mutex = NSLock() - private nonisolated(unsafe) var _channelState: ARTRealtimeChannelState + private nonisolated(unsafe) var _channelState: _AblyPluginSupportPrivate.RealtimeChannelState private nonisolated(unsafe) var _publishHandler: (([OutboundObjectMessage]) async throws(InternalError) -> Void)? - init(channelState: ARTRealtimeChannelState) { + init(channelState: _AblyPluginSupportPrivate.RealtimeChannelState) { _channelState = channelState } @@ -24,7 +25,7 @@ final class MockCoreSDK: CoreSDK { protocolRequirementNotImplemented() } - var channelState: ARTRealtimeChannelState { + var channelState: _AblyPluginSupportPrivate.RealtimeChannelState { get { mutex.withLock { _channelState diff --git a/Tests/AblyLiveObjectsTests/ObjectMessageTests.swift b/Tests/AblyLiveObjectsTests/ObjectMessageTests.swift index a973dea7..85fd9f49 100644 --- a/Tests/AblyLiveObjectsTests/ObjectMessageTests.swift +++ b/Tests/AblyLiveObjectsTests/ObjectMessageTests.swift @@ -1,5 +1,5 @@ +import _AblyPluginSupportPrivate @testable import AblyLiveObjects -import AblyPlugin import Foundation import Testing diff --git a/Tests/AblyLiveObjectsTests/ObjectsPoolTests.swift b/Tests/AblyLiveObjectsTests/ObjectsPoolTests.swift index 89514d5f..8a350029 100644 --- a/Tests/AblyLiveObjectsTests/ObjectsPoolTests.swift +++ b/Tests/AblyLiveObjectsTests/ObjectsPoolTests.swift @@ -1,5 +1,5 @@ +import _AblyPluginSupportPrivate @testable import AblyLiveObjects -import AblyPlugin import Testing struct ObjectsPoolTests { diff --git a/Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift b/Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift index 16c28f12..d2228142 100644 --- a/Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift +++ b/Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift @@ -1,11 +1,11 @@ +import _AblyPluginSupportPrivate @testable import AblyLiveObjects -import AblyPlugin import Foundation import Testing enum WireObjectMessageTests { // Helper: Fake decoding context - final class FakeDecodingContext: AblyPlugin.DecodingContextProtocol, @unchecked Sendable { + final class FakeDecodingContext: _AblyPluginSupportPrivate.DecodingContextProtocol, @unchecked Sendable { let parentID: String? let parentConnectionID: String? let parentTimestamp: Date? diff --git a/Tests/AblyLiveObjectsTests/WireValueTests.swift b/Tests/AblyLiveObjectsTests/WireValueTests.swift index 91e557e0..74a31d32 100644 --- a/Tests/AblyLiveObjectsTests/WireValueTests.swift +++ b/Tests/AblyLiveObjectsTests/WireValueTests.swift @@ -4,35 +4,35 @@ import Foundation import Testing struct WireValueTests { - // MARK: Conversion from AblyPlugin data + // MARK: Conversion from _AblyPluginSupportPrivate data @Test(arguments: [ // object - (ablyPluginData: ["someKey": "someValue"], expectedResult: ["someKey": "someValue"]), + (pluginSupportData: ["someKey": "someValue"], expectedResult: ["someKey": "someValue"]), // array - (ablyPluginData: ["someElement"], expectedResult: ["someElement"]), + (pluginSupportData: ["someElement"], expectedResult: ["someElement"]), // string - (ablyPluginData: "someString", expectedResult: "someString"), + (pluginSupportData: "someString", expectedResult: "someString"), // number - (ablyPluginData: NSNumber(value: 0), expectedResult: 0), - (ablyPluginData: NSNumber(value: 1), expectedResult: 1), - (ablyPluginData: NSNumber(value: 123), expectedResult: 123), - (ablyPluginData: NSNumber(value: 123.456), expectedResult: 123.456), + (pluginSupportData: NSNumber(value: 0), expectedResult: 0), + (pluginSupportData: NSNumber(value: 1), expectedResult: 1), + (pluginSupportData: NSNumber(value: 123), expectedResult: 123), + (pluginSupportData: NSNumber(value: 123.456), expectedResult: 123.456), // bool - (ablyPluginData: NSNumber(value: true), expectedResult: true), - (ablyPluginData: NSNumber(value: false), expectedResult: false), + (pluginSupportData: NSNumber(value: true), expectedResult: true), + (pluginSupportData: NSNumber(value: false), expectedResult: false), // null - (ablyPluginData: NSNull(), expectedResult: .null), + (pluginSupportData: NSNull(), expectedResult: .null), // data - (ablyPluginData: Data([0x01, 0x02, 0x03]), expectedResult: .data(Data([0x01, 0x02, 0x03]))), - ] as[(ablyPluginData: Sendable, expectedResult: WireValue?)]) - func initWithAblyPluginData(ablyPluginData: Sendable, expectedResult: WireValue?) { - #expect(WireValue(ablyPluginData: ablyPluginData) == expectedResult) + (pluginSupportData: Data([0x01, 0x02, 0x03]), expectedResult: .data(Data([0x01, 0x02, 0x03]))), + ] as[(pluginSupportData: Sendable, expectedResult: WireValue?)]) + func initWithPluginSupportData(pluginSupportData: Sendable, expectedResult: WireValue?) { + #expect(WireValue(pluginSupportData: pluginSupportData) == expectedResult) } // Tests that it correctly handles an object deserialized by `JSONSerialization` (which is what ably-cocoa uses for JSON deserialization). @Test - func initWithAblyPluginData_endToEnd_json() throws { + func initWithPluginSupportData_endToEnd_json() throws { let jsonString = """ { "someArray": [ @@ -54,7 +54,7 @@ struct WireValueTests { } """ - let ablyPluginData = try JSONSerialization.jsonObject(with: #require(jsonString.data(using: .utf8))) + let pluginSupportData = try JSONSerialization.jsonObject(with: #require(jsonString.data(using: .utf8))) let expected: WireValue = [ "someArray": [ @@ -75,12 +75,12 @@ struct WireValueTests { ], ] - #expect(WireValue(ablyPluginData: ablyPluginData) == expected) + #expect(WireValue(pluginSupportData: pluginSupportData) == expected) } // Tests that it correctly handles an object deserialized by `ARTMsgPackEncoder` (which is what ably-cocoa uses for MessagePack deserialization). @Test - func initWithAblyPluginData_endToEnd_msgpack() throws { + func initWithPluginSupportData_endToEnd_msgpack() throws { // MessagePack representation of the same data structure as in the JSON test above, plus binary data // This represents: // { @@ -167,7 +167,7 @@ struct WireValueTests { 0xAE, 0x73, 0x6F, 0x6D, 0x65, 0x4F, 0x74, 0x68, 0x65, 0x72, 0x56, 0x61, 0x6C, 0x75, 0x65, // value (14 chars) ]) - let ablyPluginData = try ARTMsgPackEncoder().decode(msgpackData) + let pluginSupportData = try ARTMsgPackEncoder().decode(msgpackData) let expected: WireValue = [ "someArray": [ @@ -189,10 +189,10 @@ struct WireValueTests { ], ] - #expect(WireValue(ablyPluginData: ablyPluginData) == expected) + #expect(WireValue(pluginSupportData: pluginSupportData) == expected) } - // MARK: Conversion to AblyPlugin data + // MARK: Conversion to _AblyPluginSupportPrivate data @Test(arguments: [ // object @@ -214,15 +214,15 @@ struct WireValueTests { // data (value: .data(Data([0x01, 0x02, 0x03])), expectedResult: Data([0x01, 0x02, 0x03])), ] as[(value: WireValue, expectedResult: Sendable)]) - func toAblyPluginData(value: WireValue, expectedResult: Sendable) throws { - let resultAsNSObject = try #require(value.toAblyPluginData as? NSObject) + func toPluginSupportData(value: WireValue, expectedResult: Sendable) throws { + let resultAsNSObject = try #require(value.toPluginSupportData as? NSObject) let expectedResultAsNSObject = try #require(expectedResult as? NSObject) #expect(resultAsNSObject == expectedResultAsNSObject) } // Tests that it creates an object that can be serialized by `JSONSerialization` (which is what ably-cocoa uses for JSON serialization), and that the result of this serialization is what we’d expect. @Test - func toAblyPluginData_endToEnd_json() throws { + func toPluginSupportData_endToEnd_json() throws { let value: WireValue = [ "someArray": [ [ @@ -265,7 +265,7 @@ struct WireValueTests { let jsonSerializationOptions: JSONSerialization.WritingOptions = [.sortedKeys] - let valueData = try JSONSerialization.data(withJSONObject: value.toAblyPluginData, options: jsonSerializationOptions) + let valueData = try JSONSerialization.data(withJSONObject: value.toPluginSupportData, options: jsonSerializationOptions) let expectedData = try { let serialized = try JSONSerialization.jsonObject(with: #require(expectedJSONString.data(using: .utf8))) return try JSONSerialization.data(withJSONObject: serialized, options: jsonSerializationOptions) @@ -276,7 +276,7 @@ struct WireValueTests { // Tests that it creates an object that can be serialized by `ARTMsgPackEncoder` (which is what ably-cocoa uses for MessagePack serialization), and that the result of this serialization is what we’d expect. @Test - func toAblyPluginData_endToEnd_msgpack() throws { + func toPluginSupportData_endToEnd_msgpack() throws { let value: WireValue = [ "someArray": [ [ @@ -365,7 +365,7 @@ struct WireValueTests { 0xAE, 0x73, 0x6F, 0x6D, 0x65, 0x4F, 0x74, 0x68, 0x65, 0x72, 0x56, 0x61, 0x6C, 0x75, 0x65, // value (14 chars) ]) - let actualMsgPackData = try ARTMsgPackEncoder().encode(value.toAblyPluginData) + let actualMsgPackData = try ARTMsgPackEncoder().encode(value.toPluginSupportData) // Verify that both decode to the same Foundation object structure let expectedDecoded = try ARTMsgPackEncoder().decode(expectedMsgPackData) diff --git a/ably-cocoa b/ably-cocoa index 5096ca37..9e172dd3 160000 --- a/ably-cocoa +++ b/ably-cocoa @@ -1 +1 @@ -Subproject commit 5096ca37c6c39f8f33e261f49faf2a6f9d03e529 +Subproject commit 9e172dd3e744c6d8c2bb0be09a22853aa702005b