Skip to content

Commit 604a89e

Browse files
Merge pull request #69 from ably/ECO-5531-move-plugin-API-to-separate-repo
[ECO-5531] Get ably-cocoa plugin APIs from an external repo
2 parents 07a771e + b4e1899 commit 604a89e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+339
-213
lines changed

.cursor/rules/swift.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ When writing Swift:
1414
- When writing a JSON string, favour using Swift raw string literals instead of escaping double quotes.
1515
- 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:
1616
- Ably: use `import Ably`
17-
- AblyPlugin: use `internal import AblyPlugin`
17+
- `_AblyPluginSupportPrivate`: use `internal import _AblyPluginSupportPrivate`
1818
- 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:
1919
```swift
2020
objectMessages: [InboundObjectMessage(

.cursor/rules/testing.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ When writing tests:
1414
- When you need to import the following modules in the tests, do so in the following way:
1515
- Ably: use `import Ably`
1616
- AblyLiveObjects: use `@testable import AblyLiveObjects`
17-
- AblyPlugin: use `import AblyPlugin`; _do not_ do `internal import`
17+
- `_AblyPluginSupportPrivate`: use `import _AblyPluginSupportPrivate`; _do not_ do `internal import`
1818
- When you need to pass a logger to internal components in the tests, pass `TestLogger()`.
1919
- When you need to unwrap an optional value in the tests, favour using `#require` instead of `guard let`.
2020
- 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.

AblyLiveObjects.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.resolved

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ let package = Package(
2121
.package(
2222
path: "ably-cocoa",
2323
),
24+
.package(
25+
url: "https://github.com/ably/ably-cocoa-plugin-support",
26+
from: "0.1.0",
27+
),
2428
.package(
2529
url: "https://github.com/apple/swift-argument-parser",
2630
from: "1.5.0",
@@ -47,8 +51,8 @@ let package = Package(
4751
package: "ably-cocoa",
4852
),
4953
.product(
50-
name: "AblyPlugin",
51-
package: "ably-cocoa",
54+
name: "_AblyPluginSupportPrivate",
55+
package: "ably-cocoa-plugin-support",
5256
),
5357
],
5458
),
@@ -61,8 +65,8 @@ let package = Package(
6165
package: "ably-cocoa",
6266
),
6367
.product(
64-
name: "AblyPlugin",
65-
package: "ably-cocoa",
68+
name: "_AblyPluginSupportPrivate",
69+
package: "ably-cocoa-plugin-support",
6670
),
6771
],
6872
resources: [

Sources/AblyLiveObjects/Internal/ARTClientOptions+Objects.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
internal import AblyPlugin
1+
internal import _AblyPluginSupportPrivate
2+
import Ably
23

34
internal extension ARTClientOptions {
45
private class Box<T> {
@@ -14,9 +15,9 @@ internal extension ARTClientOptions {
1415
/// Can be overriden for testing purposes.
1516
var garbageCollectionOptions: InternalDefaultRealtimeObjects.GarbageCollectionOptions? {
1617
get {
17-
let optionsValue = PluginAPI.sharedInstance().pluginOptionsValue(
18+
let optionsValue = Plugin.defaultPluginAPI.pluginOptionsValue(
1819
forKey: Self.garbageCollectionOptionsKey,
19-
clientOptions: self,
20+
clientOptions: asPluginPublicClientOptions,
2021
)
2122

2223
guard let optionsValue else {
@@ -35,10 +36,10 @@ internal extension ARTClientOptions {
3536
preconditionFailure("Not implemented the ability to un-set GC options")
3637
}
3738

38-
PluginAPI.sharedInstance().setPluginOptionsValue(
39+
Plugin.defaultPluginAPI.setPluginOptionsValue(
3940
Box<InternalDefaultRealtimeObjects.GarbageCollectionOptions>(boxed: newValue),
4041
forKey: Self.garbageCollectionOptionsKey,
41-
clientOptions: self,
42+
clientOptions: asPluginPublicClientOptions,
4243
)
4344
}
4445
}

Sources/AblyLiveObjects/Internal/CoreSDK.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
internal import _AblyPluginSupportPrivate
12
import Ably
2-
internal import AblyPlugin
33

44
/// 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).
55
///
6-
/// 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).
6+
/// 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).
77
internal protocol CoreSDK: AnyObject, Sendable {
88
/// Implements the internal `#publish` method of RTO15.
99
func publish(objectMessages: [OutboundObjectMessage]) async throws(InternalError)
@@ -14,17 +14,17 @@ internal protocol CoreSDK: AnyObject, Sendable {
1414
func testsOnly_overridePublish(with newImplementation: @escaping ([OutboundObjectMessage]) async throws(InternalError) -> Void)
1515

1616
/// Returns the current state of the Realtime channel that this wraps.
17-
var channelState: ARTRealtimeChannelState { get }
17+
var channelState: _AblyPluginSupportPrivate.RealtimeChannelState { get }
1818
}
1919

2020
internal final class DefaultCoreSDK: CoreSDK {
2121
/// Used to synchronize access to internal mutable state.
2222
private let mutex = NSLock()
2323

24-
private let channel: AblyPlugin.RealtimeChannel
25-
private let client: AblyPlugin.RealtimeClient
24+
private let channel: _AblyPluginSupportPrivate.RealtimeChannel
25+
private let client: _AblyPluginSupportPrivate.RealtimeClient
2626
private let pluginAPI: PluginAPIProtocol
27-
private let logger: AblyPlugin.Logger
27+
private let logger: Logger
2828

2929
/// If set to true, ``publish(objectMessages:)`` will behave like a no-op.
3030
///
@@ -34,10 +34,10 @@ internal final class DefaultCoreSDK: CoreSDK {
3434
private nonisolated(unsafe) var overriddenPublishImplementation: (([OutboundObjectMessage]) async throws -> Void)?
3535

3636
internal init(
37-
channel: AblyPlugin.RealtimeChannel,
38-
client: AblyPlugin.RealtimeClient,
37+
channel: _AblyPluginSupportPrivate.RealtimeChannel,
38+
client: _AblyPluginSupportPrivate.RealtimeClient,
3939
pluginAPI: PluginAPIProtocol,
40-
logger: AblyPlugin.Logger
40+
logger: Logger
4141
) {
4242
self.channel = channel
4343
self.client = client
@@ -81,8 +81,8 @@ internal final class DefaultCoreSDK: CoreSDK {
8181
}
8282
}
8383

84-
internal var channelState: ARTRealtimeChannelState {
85-
channel.state
84+
internal var channelState: _AblyPluginSupportPrivate.RealtimeChannelState {
85+
pluginAPI.state(for: channel)
8686
}
8787
}
8888

@@ -97,7 +97,7 @@ internal extension CoreSDK {
9797
/// - operationDescription: A description of the operation being performed, used in error messages
9898
/// - Throws: `ARTErrorInfo` with code 90001 and statusCode 400 if the channel is in any of the invalid states
9999
func validateChannelState(
100-
notIn invalidStates: [ARTRealtimeChannelState],
100+
notIn invalidStates: [_AblyPluginSupportPrivate.RealtimeChannelState],
101101
operationDescription: String,
102102
) throws(ARTErrorInfo) {
103103
let currentChannelState = channelState

Sources/AblyLiveObjects/Internal/DefaultInternalPlugin.swift

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
internal import AblyPlugin
1+
internal import _AblyPluginSupportPrivate
2+
import Ably
23

3-
// 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".
4+
// 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".
45
import ObjectiveC.NSObject
56

6-
/// The default implementation of `AblyPlugin`'s `LiveObjectsInternalPluginProtocol`. Implements the interface that ably-cocoa uses to access the functionality provided by the LiveObjects plugin.
7+
/// The default implementation of `_AblyPluginSupportPrivate`'s `LiveObjectsInternalPluginProtocol`. Implements the interface that ably-cocoa uses to access the functionality provided by the LiveObjects plugin.
78
@objc
8-
internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInternalPluginProtocol {
9-
private let pluginAPI: AblyPlugin.PluginAPIProtocol
9+
internal final class DefaultInternalPlugin: NSObject, _AblyPluginSupportPrivate.LiveObjectsInternalPluginProtocol {
10+
private let pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol
1011

11-
internal init(pluginAPI: AblyPlugin.PluginAPIProtocol) {
12+
internal init(pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol) {
1213
self.pluginAPI = pluginAPI
1314
}
1415

@@ -20,7 +21,7 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte
2021
/// Retrieves the `RealtimeObjects` for this channel.
2122
///
2223
/// We expect this value to have been previously set by ``prepare(_:)``.
23-
internal static func realtimeObjects(for channel: AblyPlugin.RealtimeChannel, pluginAPI: AblyPlugin.PluginAPIProtocol) -> InternalDefaultRealtimeObjects {
24+
internal static func realtimeObjects(for channel: _AblyPluginSupportPrivate.RealtimeChannel, pluginAPI: _AblyPluginSupportPrivate.PluginAPIProtocol) -> InternalDefaultRealtimeObjects {
2425
guard let pluginData = pluginAPI.pluginDataValue(forKey: pluginDataKey, channel: channel) else {
2526
// InternalPlugin.prepare was not called
2627
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
3334
// MARK: - LiveObjectsInternalPluginProtocol
3435

3536
// Populates the channel's `objects` property.
36-
internal func prepare(_ channel: AblyPlugin.RealtimeChannel, client: AblyPlugin.RealtimeClient) {
37-
let logger = pluginAPI.logger(for: channel)
37+
internal func prepare(_ channel: _AblyPluginSupportPrivate.RealtimeChannel, client: _AblyPluginSupportPrivate.RealtimeClient) {
38+
let pluginLogger = pluginAPI.logger(for: channel)
3839
let callbackQueue = pluginAPI.callbackQueue(for: client)
39-
let options = pluginAPI.options(for: client)
40+
let options = ARTClientOptions.castPluginPublicClientOptions(pluginAPI.options(for: client))
4041

42+
let logger = DefaultLogger(pluginLogger: pluginLogger, pluginAPI: pluginAPI)
4143
logger.log("LiveObjects.DefaultInternalPlugin received prepare(_:)", level: .debug)
4244
let liveObjects = InternalDefaultRealtimeObjects(
4345
logger: logger,
@@ -49,14 +51,14 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte
4951
}
5052

5153
/// Retrieves the internally-typed `objects` property for the channel.
52-
private func realtimeObjects(for channel: AblyPlugin.RealtimeChannel) -> InternalDefaultRealtimeObjects {
54+
private func realtimeObjects(for channel: _AblyPluginSupportPrivate.RealtimeChannel) -> InternalDefaultRealtimeObjects {
5355
Self.realtimeObjects(for: channel, pluginAPI: pluginAPI)
5456
}
5557

5658
/// A class that wraps an object message.
5759
///
58-
/// 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`.
59-
private final class ObjectMessageBox<T>: AblyPlugin.ObjectMessageProtocol where T: Sendable {
60+
/// 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`.
61+
private final class ObjectMessageBox<T>: _AblyPluginSupportPrivate.ObjectMessageProtocol where T: Sendable {
6062
internal let objectMessage: T
6163

6264
init(objectMessage: T) {
@@ -68,9 +70,9 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte
6870
_ serialized: [String: Any],
6971
context: DecodingContextProtocol,
7072
format: EncodingFormat,
71-
error errorPtr: AutoreleasingUnsafeMutablePointer<ARTErrorInfo?>?,
73+
error errorPtr: AutoreleasingUnsafeMutablePointer<_AblyPluginSupportPrivate.PublicErrorInfo?>?,
7274
) -> (any ObjectMessageProtocol)? {
73-
let wireObject = WireValue.objectFromAblyPluginData(serialized)
75+
let wireObject = WireValue.objectFromPluginSupportData(serialized)
7476

7577
do {
7678
let wireObjectMessage = try InboundWireObjectMessage(
@@ -83,28 +85,28 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte
8385
)
8486
return ObjectMessageBox(objectMessage: objectMessage)
8587
} catch {
86-
errorPtr?.pointee = error.toARTErrorInfo()
88+
errorPtr?.pointee = error.toARTErrorInfo().asPluginPublicErrorInfo
8789
return nil
8890
}
8991
}
9092

9193
internal func encodeObjectMessage(
92-
_ publicObjectMessage: any AblyPlugin.ObjectMessageProtocol,
94+
_ publicObjectMessage: any _AblyPluginSupportPrivate.ObjectMessageProtocol,
9395
format: EncodingFormat,
9496
) -> [String: Any] {
9597
guard let outboundObjectMessageBox = publicObjectMessage as? ObjectMessageBox<OutboundObjectMessage> else {
9698
preconditionFailure("Expected to receive the same OutboundObjectMessage type as we emit")
9799
}
98100

99101
let wireObjectMessage = outboundObjectMessageBox.objectMessage.toWire(format: format)
100-
return wireObjectMessage.toWireObject.toAblyPluginDataDictionary
102+
return wireObjectMessage.toWireObject.toPluginSupportDataDictionary
101103
}
102104

103-
internal func onChannelAttached(_ channel: AblyPlugin.RealtimeChannel, hasObjects: Bool) {
105+
internal func onChannelAttached(_ channel: _AblyPluginSupportPrivate.RealtimeChannel, hasObjects: Bool) {
104106
realtimeObjects(for: channel).onChannelAttached(hasObjects: hasObjects)
105107
}
106108

107-
internal func handleObjectProtocolMessage(withObjectMessages publicObjectMessages: [any AblyPlugin.ObjectMessageProtocol], channel: AblyPlugin.RealtimeChannel) {
109+
internal func handleObjectProtocolMessage(withObjectMessages publicObjectMessages: [any _AblyPluginSupportPrivate.ObjectMessageProtocol], channel: _AblyPluginSupportPrivate.RealtimeChannel) {
108110
guard let inboundObjectMessageBoxes = publicObjectMessages as? [ObjectMessageBox<InboundObjectMessage>] else {
109111
preconditionFailure("Expected to receive the same InboundObjectMessage type as we emit")
110112
}
@@ -116,7 +118,7 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte
116118
)
117119
}
118120

119-
internal func handleObjectSyncProtocolMessage(withObjectMessages publicObjectMessages: [any AblyPlugin.ObjectMessageProtocol], protocolMessageChannelSerial: String?, channel: AblyPlugin.RealtimeChannel) {
121+
internal func handleObjectSyncProtocolMessage(withObjectMessages publicObjectMessages: [any _AblyPluginSupportPrivate.ObjectMessageProtocol], protocolMessageChannelSerial: String?, channel: _AblyPluginSupportPrivate.RealtimeChannel) {
120122
guard let inboundObjectMessageBoxes = publicObjectMessages as? [ObjectMessageBox<InboundObjectMessage>] else {
121123
preconditionFailure("Expected to receive the same InboundObjectMessage type as we emit")
122124
}
@@ -133,8 +135,8 @@ internal final class DefaultInternalPlugin: NSObject, AblyPlugin.LiveObjectsInte
133135

134136
internal static func sendObject(
135137
objectMessages: [OutboundObjectMessage],
136-
channel: AblyPlugin.RealtimeChannel,
137-
client: AblyPlugin.RealtimeClient,
138+
channel: _AblyPluginSupportPrivate.RealtimeChannel,
139+
client: _AblyPluginSupportPrivate.RealtimeClient,
138140
pluginAPI: PluginAPIProtocol,
139141
) async throws(InternalError) {
140142
let objectMessageBoxes: [ObjectMessageBox<OutboundObjectMessage>] = objectMessages.map { .init(objectMessage: $0) }

Sources/AblyLiveObjects/Internal/InternalDefaultLiveCounter.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
internal import _AblyPluginSupportPrivate
12
import Ably
2-
internal import AblyPlugin
33
import Foundation
44

55
/// This provides the implementation behind ``PublicDefaultLiveCounter``, via internal versions of the ``LiveCounter`` API.
@@ -21,7 +21,7 @@ internal final class InternalDefaultLiveCounter: Sendable {
2121
}
2222
}
2323

24-
private let logger: AblyPlugin.Logger
24+
private let logger: Logger
2525
private let userCallbackQueue: DispatchQueue
2626
private let clock: SimpleClock
2727

@@ -30,7 +30,7 @@ internal final class InternalDefaultLiveCounter: Sendable {
3030
internal convenience init(
3131
testsOnly_data data: Double,
3232
objectID: String,
33-
logger: AblyPlugin.Logger,
33+
logger: Logger,
3434
userCallbackQueue: DispatchQueue,
3535
clock: SimpleClock
3636
) {
@@ -40,7 +40,7 @@ internal final class InternalDefaultLiveCounter: Sendable {
4040
private init(
4141
data: Double,
4242
objectID: String,
43-
logger: AblyPlugin.Logger,
43+
logger: Logger,
4444
userCallbackQueue: DispatchQueue,
4545
clock: SimpleClock
4646
) {
@@ -56,7 +56,7 @@ internal final class InternalDefaultLiveCounter: Sendable {
5656
/// - objectID: The value for the "private objectId field" of RTO5c1b1a.
5757
internal static func createZeroValued(
5858
objectID: String,
59-
logger: AblyPlugin.Logger,
59+
logger: Logger,
6060
userCallbackQueue: DispatchQueue,
6161
clock: SimpleClock,
6262
) -> Self {

0 commit comments

Comments
 (0)