diff --git a/Example/AblyChatExample/Mocks/MockClients.swift b/Example/AblyChatExample/Mocks/MockClients.swift index 86c8209d..2cca15bc 100644 --- a/Example/AblyChatExample/Mocks/MockClients.swift +++ b/Example/AblyChatExample/Mocks/MockClients.swift @@ -88,7 +88,7 @@ actor MockRoom: Room { actor MockMessages: Messages { let clientID: String let roomID: String - let channel: RealtimeChannelProtocol + let channel: any RealtimeChannelProtocol private let mockSubscriptions = MockSubscriptionStorage() @@ -146,7 +146,7 @@ actor MockMessages: Messages { actor MockRoomReactions: RoomReactions { let clientID: String let roomID: String - let channel: RealtimeChannelProtocol + let channel: any RealtimeChannelProtocol private let mockSubscriptions = MockSubscriptionStorage() @@ -193,7 +193,7 @@ actor MockRoomReactions: RoomReactions { actor MockTyping: Typing { let clientID: String let roomID: String - let channel: RealtimeChannelProtocol + let channel: any RealtimeChannelProtocol private let mockSubscriptions = MockSubscriptionStorage() @@ -356,7 +356,7 @@ actor MockPresence: Presence { actor MockOccupancy: Occupancy { let clientID: String let roomID: String - let channel: RealtimeChannelProtocol + let channel: any RealtimeChannelProtocol private let mockSubscriptions = MockSubscriptionStorage() diff --git a/Example/AblyChatExample/Mocks/MockRealtime.swift b/Example/AblyChatExample/Mocks/MockRealtime.swift index e22f2581..58d5b283 100644 --- a/Example/AblyChatExample/Mocks/MockRealtime.swift +++ b/Example/AblyChatExample/Mocks/MockRealtime.swift @@ -105,9 +105,7 @@ final class MockRealtime: NSObject, RealtimeClientProtocol, Sendable { fatalError("Not implemented") } - var presence: ARTRealtimePresenceProtocol { - fatalError("Not implemented") - } + let presence = RealtimePresence() var errorReason: ARTErrorInfo? { fatalError("Not implemented") @@ -250,6 +248,102 @@ final class MockRealtime: NSObject, RealtimeClientProtocol, Sendable { } } + final class RealtimePresence: RealtimePresenceProtocol { + var syncComplete: Bool { + fatalError("Not implemented") + } + + func get(_: @escaping ARTPresenceMessagesCallback) { + fatalError("Not implemented") + } + + func get(_: ARTRealtimePresenceQuery, callback _: @escaping ARTPresenceMessagesCallback) { + fatalError("Not implemented") + } + + func enter(_: Any?) { + fatalError("Not implemented") + } + + func enter(_: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func update(_: Any?) { + fatalError("Not implemented") + } + + func update(_: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func leave(_: Any?) { + fatalError("Not implemented") + } + + func leave(_: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func enterClient(_: String, data _: Any?) { + fatalError("Not implemented") + } + + func enterClient(_: String, data _: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func updateClient(_: String, data _: Any?) { + fatalError("Not implemented") + } + + func updateClient(_: String, data _: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func leaveClient(_: String, data _: Any?) { + fatalError("Not implemented") + } + + func leaveClient(_: String, data _: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func subscribe(_: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func subscribe(attachCallback _: ARTCallback?, callback _: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func subscribe(_: ARTPresenceAction, callback _: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func subscribe(_: ARTPresenceAction, onAttach _: ARTCallback?, callback _: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func unsubscribe() { + fatalError("Not implemented") + } + + func unsubscribe(_: ARTEventListener) { + fatalError("Not implemented") + } + + func unsubscribe(_: ARTPresenceAction, listener _: ARTEventListener) { + fatalError("Not implemented") + } + + func history(_: @escaping ARTPaginatedPresenceCallback) {} + + func history(_: ARTRealtimeHistoryQuery?, callback _: @escaping ARTPaginatedPresenceCallback) throws { + fatalError("Not implemented") + } + } + required init(options _: ARTClientOptions) {} required init(key _: String) {} diff --git a/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift b/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift index 057cc2a7..e55bdb08 100644 --- a/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift +++ b/Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift @@ -6,4 +6,6 @@ extension ARTRealtimeChannels: RealtimeChannelsProtocol {} extension ARTRealtimeChannel: RealtimeChannelProtocol {} +extension ARTRealtimePresence: RealtimePresenceProtocol {} + extension ARTConnection: ConnectionProtocol {} diff --git a/Sources/AblyChat/Dependencies.swift b/Sources/AblyChat/Dependencies.swift index 13cff5f8..4f99e12b 100644 --- a/Sources/AblyChat/Dependencies.swift +++ b/Sources/AblyChat/Dependencies.swift @@ -23,7 +23,14 @@ public protocol RealtimeChannelsProtocol: ARTRealtimeChannelsProtocol, Sendable } /// Expresses the requirements of the object returned by ``RealtimeChannelsProtocol/get(_:options:)``. -public protocol RealtimeChannelProtocol: ARTRealtimeChannelProtocol, Sendable {} +public protocol RealtimeChannelProtocol: ARTRealtimeChannelProtocol, Sendable { + associatedtype Presence: RealtimePresenceProtocol + + var presence: Presence { get } +} + +/// Expresses the requirements of the object returned by ``RealtimeChannelProtocol/presence``. +public protocol RealtimePresenceProtocol: ARTRealtimePresenceProtocol, Sendable {} public protocol ConnectionProtocol: ARTConnectionProtocol, Sendable {} diff --git a/Sources/AblyChat/Messages.swift b/Sources/AblyChat/Messages.swift index 5a7114cb..366b7328 100644 --- a/Sources/AblyChat/Messages.swift +++ b/Sources/AblyChat/Messages.swift @@ -51,7 +51,7 @@ public protocol Messages: AnyObject, Sendable, EmitsDiscontinuities { * * - Returns: The realtime channel. */ - var channel: RealtimeChannelProtocol { get } + var channel: any RealtimeChannelProtocol { get } } public extension Messages { diff --git a/Sources/AblyChat/Occupancy.swift b/Sources/AblyChat/Occupancy.swift index 8d1bb75f..135e8f1a 100644 --- a/Sources/AblyChat/Occupancy.swift +++ b/Sources/AblyChat/Occupancy.swift @@ -34,7 +34,7 @@ public protocol Occupancy: AnyObject, Sendable, EmitsDiscontinuities { * * - Returns: The underlying Ably channel for occupancy events. */ - var channel: RealtimeChannelProtocol { get } + var channel: any RealtimeChannelProtocol { get } } public extension Occupancy { diff --git a/Sources/AblyChat/Room.swift b/Sources/AblyChat/Room.swift index 80e168b1..97b1b9ef 100644 --- a/Sources/AblyChat/Room.swift +++ b/Sources/AblyChat/Room.swift @@ -300,7 +300,7 @@ internal actor DefaultRoom } private struct FeatureChannelPartialDependencies { - internal var channel: RealtimeChannelProtocol + internal var channel: any RealtimeChannelProtocol internal var contributor: DefaultRoomLifecycleContributor } diff --git a/Sources/AblyChat/RoomFeature.swift b/Sources/AblyChat/RoomFeature.swift index 69ab9bf7..61d19bb2 100644 --- a/Sources/AblyChat/RoomFeature.swift +++ b/Sources/AblyChat/RoomFeature.swift @@ -46,7 +46,7 @@ internal enum RoomFeature: CaseIterable { /// - the discontinuities emitted by the room lifecycle /// - the presence-readiness wait mechanism supplied by the room lifecycle internal protocol FeatureChannel: Sendable, EmitsDiscontinuities { - var channel: RealtimeChannelProtocol { get } + var channel: any RealtimeChannelProtocol { get } /// Waits until we can perform presence operations on the contributors of this room without triggering an implicit attach. /// @@ -62,7 +62,7 @@ internal protocol FeatureChannel: Sendable, EmitsDiscontinuities { } internal struct DefaultFeatureChannel: FeatureChannel { - internal var channel: RealtimeChannelProtocol + internal var channel: any RealtimeChannelProtocol internal var contributor: DefaultRoomLifecycleContributor internal var roomLifecycleManager: RoomLifecycleManager diff --git a/Sources/AblyChat/RoomReactions.swift b/Sources/AblyChat/RoomReactions.swift index f4828b29..ff69c38e 100644 --- a/Sources/AblyChat/RoomReactions.swift +++ b/Sources/AblyChat/RoomReactions.swift @@ -22,7 +22,7 @@ public protocol RoomReactions: AnyObject, Sendable, EmitsDiscontinuities { * * - Returns: The realtime channel. */ - var channel: RealtimeChannelProtocol { get } + var channel: any RealtimeChannelProtocol { get } /** * Subscribes a given listener to receive room-level reactions. diff --git a/Sources/AblyChat/Typing.swift b/Sources/AblyChat/Typing.swift index 49b9d432..5c2065fc 100644 --- a/Sources/AblyChat/Typing.swift +++ b/Sources/AblyChat/Typing.swift @@ -54,7 +54,7 @@ public protocol Typing: AnyObject, Sendable, EmitsDiscontinuities { * * - Returns: The Ably realtime channel. */ - var channel: RealtimeChannelProtocol { get } + var channel: any RealtimeChannelProtocol { get } } public extension Typing { diff --git a/Tests/AblyChatTests/Mocks/MockFeatureChannel.swift b/Tests/AblyChatTests/Mocks/MockFeatureChannel.swift index 2b665062..e3893e98 100644 --- a/Tests/AblyChatTests/Mocks/MockFeatureChannel.swift +++ b/Tests/AblyChatTests/Mocks/MockFeatureChannel.swift @@ -2,12 +2,12 @@ import Ably @testable import AblyChat final actor MockFeatureChannel: FeatureChannel { - let channel: RealtimeChannelProtocol + let channel: any RealtimeChannelProtocol private var discontinuitySubscriptions = SubscriptionStorage() private let resultOfWaitToBeAbleToPerformPresenceOperations: Result? init( - channel: RealtimeChannelProtocol, + channel: any RealtimeChannelProtocol, resultOfWaitToBeAblePerformPresenceOperations: Result? = nil ) { self.channel = channel diff --git a/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift b/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift index 071bc4af..0f92c5aa 100644 --- a/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift +++ b/Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift @@ -2,9 +2,7 @@ import Ably import AblyChat final class MockRealtimeChannel: NSObject, RealtimeChannelProtocol { - var presence: ARTRealtimePresenceProtocol { - fatalError("Not implemented") - } + let presence = MockRealtimePresence() private let attachSerial: String? private let channelSerial: String? diff --git a/Tests/AblyChatTests/Mocks/MockRealtimePresence.swift b/Tests/AblyChatTests/Mocks/MockRealtimePresence.swift new file mode 100644 index 00000000..873e6261 --- /dev/null +++ b/Tests/AblyChatTests/Mocks/MockRealtimePresence.swift @@ -0,0 +1,98 @@ +import Ably +import AblyChat + +final class MockRealtimePresence: RealtimePresenceProtocol { + var syncComplete: Bool { + fatalError("Not implemented") + } + + func get(_: @escaping ARTPresenceMessagesCallback) { + fatalError("Not implemented") + } + + func get(_: ARTRealtimePresenceQuery, callback _: @escaping ARTPresenceMessagesCallback) { + fatalError("Not implemented") + } + + func enter(_: Any?) { + fatalError("Not implemented") + } + + func enter(_: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func update(_: Any?) { + fatalError("Not implemented") + } + + func update(_: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func leave(_: Any?) { + fatalError("Not implemented") + } + + func leave(_: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func enterClient(_: String, data _: Any?) { + fatalError("Not implemented") + } + + func enterClient(_: String, data _: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func updateClient(_: String, data _: Any?) { + fatalError("Not implemented") + } + + func updateClient(_: String, data _: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func leaveClient(_: String, data _: Any?) { + fatalError("Not implemented") + } + + func leaveClient(_: String, data _: Any?, callback _: ARTCallback? = nil) { + fatalError("Not implemented") + } + + func subscribe(_: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func subscribe(attachCallback _: ARTCallback?, callback _: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func subscribe(_: ARTPresenceAction, callback _: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func subscribe(_: ARTPresenceAction, onAttach _: ARTCallback?, callback _: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { + fatalError("Not implemented") + } + + func unsubscribe() { + fatalError("Not implemented") + } + + func unsubscribe(_: ARTEventListener) { + fatalError("Not implemented") + } + + func unsubscribe(_: ARTPresenceAction, listener _: ARTEventListener) { + fatalError("Not implemented") + } + + func history(_: @escaping ARTPaginatedPresenceCallback) {} + + func history(_: ARTRealtimeHistoryQuery?, callback _: @escaping ARTPaginatedPresenceCallback) throws { + fatalError("Not implemented") + } +}