diff --git a/Example/AblyChatExample/ContentView.swift b/Example/AblyChatExample/ContentView.swift index 7e27b85c..c498b2cc 100644 --- a/Example/AblyChatExample/ContentView.swift +++ b/Example/AblyChatExample/ContentView.swift @@ -314,7 +314,7 @@ struct ContentView: View { } func subscribeToPresence(room: any Room) { - room.presence.subscribe(events: [.enter, .leave, .update]) { event in + room.presence.subscribe { event in withAnimation { listItems.insert( .presence( diff --git a/Example/AblyChatExample/Mocks/MockClients.swift b/Example/AblyChatExample/Mocks/MockClients.swift index 268c5875..157989ef 100644 --- a/Example/AblyChatExample/Mocks/MockClients.swift +++ b/Example/AblyChatExample/Mocks/MockClients.swift @@ -538,14 +538,6 @@ class MockPresence: Presence { func subscribe(_ callback: @escaping @MainActor (PresenceEvent) -> Void) -> MockSubscription { createSubscription(callback: callback) } - - func subscribe(event _: PresenceEventType, _ callback: @escaping @MainActor (PresenceEvent) -> Void) -> MockSubscription { - createSubscription(callback: callback) - } - - func subscribe(events _: [PresenceEventType], _ callback: @escaping @MainActor (PresenceEvent) -> Void) -> MockSubscription { - createSubscription(callback: callback) - } } class MockOccupancy: Occupancy { diff --git a/Sources/AblyChat/DefaultPresence.swift b/Sources/AblyChat/DefaultPresence.swift index 5041003d..1a8486d4 100644 --- a/Sources/AblyChat/DefaultPresence.swift +++ b/Sources/AblyChat/DefaultPresence.swift @@ -211,32 +211,6 @@ internal final class DefaultPresence: Presence { return } - // processPresenceSubscribe is logging so we don't need to log here - let presenceEvent = processPresenceSubscribe( - PresenceMessage(ablyCocoaPresenceMessage: message), - for: event, - ) - callback(presenceEvent) - } - - return DefaultSubscription { [weak self] in - if let eventListener { - self?.channel.presence.unsubscribe(eventListener) - } - } - } - - // (CHA-PR7b) Users may provide a listener and a list of selected presence events, to subscribe to just those events in a room. - internal func subscribe(event: PresenceEventType, _ callback: @escaping @MainActor (PresenceEvent) -> Void) -> DefaultSubscription { - fatalErrorIfEnableEventsDisabled() - - logger.log(message: "Subscribing to presence events", level: .debug) - - let eventListener = channel.presence.subscribe(event.toARTPresenceAction()) { [weak self] message in - guard let self else { - return - } - logger.log(message: "Received presence message: \(message)", level: .debug) // processPresenceSubscribe is logging so we don't need to log here let presenceEvent = processPresenceSubscribe(PresenceMessage(ablyCocoaPresenceMessage: message), for: event) callback(presenceEvent) @@ -249,31 +223,6 @@ internal final class DefaultPresence: Presence { } } - internal func subscribe(events: [PresenceEventType], _ callback: @escaping @MainActor (PresenceEvent) -> Void) -> DefaultSubscription { - fatalErrorIfEnableEventsDisabled() - - logger.log(message: "Subscribing to presence events", level: .debug) - - let eventListeners = events.map { event in - channel.presence.subscribe(event.toARTPresenceAction()) { [weak self] message in - guard let self else { - return - } - logger.log(message: "Received presence message: \(message)", level: .debug) - let presenceEvent = processPresenceSubscribe(PresenceMessage(ablyCocoaPresenceMessage: message), for: event) - callback(presenceEvent) - } - } - - return DefaultSubscription { [weak self] in - for eventListener in eventListeners { - if let eventListener { - self?.channel.presence.unsubscribe(eventListener) - } - } - } - } - private func processPresenceGet(members: [PresenceMessage]) throws(InternalError) -> [PresenceMember] { let presenceMembers = try members.map { member throws(InternalError) in let presenceMember = PresenceMember( diff --git a/Sources/AblyChat/Presence.swift b/Sources/AblyChat/Presence.swift index abe066be..f2653bfd 100644 --- a/Sources/AblyChat/Presence.swift +++ b/Sources/AblyChat/Presence.swift @@ -74,7 +74,7 @@ public protocol Presence: AnyObject, Sendable { func leave(withData data: PresenceData) async throws(ARTErrorInfo) /** - * Subscribes a given listener to all presence events. + * Subscribes a given listener to all presence events in the chat room. * * Note that it is a programmer error to call this method if presence events are not enabled in the room options. Make sure to set `enableEvents: true` in your room's presence options to use this feature (this is the default value). * @@ -86,34 +86,6 @@ public protocol Presence: AnyObject, Sendable { @discardableResult func subscribe(_ callback: @escaping @MainActor (PresenceEvent) -> Void) -> Subscription - /** - * Subscribes a given listener to a particular presence event in the chat room. - * - * Note that it is a programmer error to call this method if presence events are not enabled in the room options. Make sure to set `enableEvents: true` in your room's presence options to use this feature (this is the default value). - * - * - Parameters: - * - event: A single presence event type ``PresenceEventType`` to subscribe to. - * - callback: The listener closure for capturing room ``PresenceEvent`` events. - * - * - Returns: A subscription that can be used to unsubscribe from ``PresenceEvent`` events. - */ - @discardableResult - func subscribe(event: PresenceEventType, _ callback: @escaping @MainActor (PresenceEvent) -> Void) -> Subscription - - /** - * Subscribes a given listener to different presence events in the chat room. - * - * Note that it is a programmer error to call this method if presence events are not enabled in the room options. Make sure to set `enableEvents: true` in your room's presence options to use this feature (this is the default value). - * - * - Parameters: - * - events: An array of presence event types ``PresenceEventType`` to subscribe to. - * - callback: The listener closure for capturing room ``PresenceEvent`` events. - * - * - Returns: A subscription that can be used to unsubscribe from ``PresenceEvent`` events. - */ - @discardableResult - func subscribe(events: [PresenceEventType], _ callback: @escaping @MainActor (PresenceEvent) -> Void) -> Subscription - /** * Method to join room presence, will emit an enter event to all subscribers. Repeat calls will trigger more enter events. * In oppose to ``enter(data:)`` it doesn't publish any custom presence data. @@ -142,7 +114,7 @@ public protocol Presence: AnyObject, Sendable { // swiftlint:disable:next missing_docs public extension Presence { /** - * Subscribes to all presence events. + * Subscribes to all presence events in the chat room. * * Note that it is a programmer error to call this method if presence events are not enabled in the room options. Make sure to set `enableEvents: true` in your room's presence options to use this feature (this is the default value). * @@ -167,74 +139,10 @@ public extension Presence { return subscriptionAsyncSequence } - /** - * Subscribes a given listener to a particular presence event in the chat room. - * - * Note that it is a programmer error to call this method if presence events are not enabled in the room options. Make sure to set `enableEvents: true` in your room's presence options to use this feature (this is the default value). - * - * - Parameters: - * - event: A single presence event type ``PresenceEventType`` to subscribe to. - * - bufferingPolicy: The ``BufferingPolicy`` for the created subscription. - * - * - Returns: A subscription `AsyncSequence` that can be used to iterate through ``PresenceEvent`` events. - */ - func subscribe(event: PresenceEventType, bufferingPolicy: BufferingPolicy) -> SubscriptionAsyncSequence { - let subscriptionAsyncSequence = SubscriptionAsyncSequence(bufferingPolicy: bufferingPolicy) - - let subscription = subscribe(event: event) { presence in - subscriptionAsyncSequence.emit(presence) - } - - subscriptionAsyncSequence.addTerminationHandler { - Task { @MainActor in - subscription.unsubscribe() - } - } - - return subscriptionAsyncSequence - } - - /** - * Subscribes a given listener to different presence events in the chat room. - * - * Note that it is a programmer error to call this method if presence events are not enabled in the room options. Make sure to set `enableEvents: true` in your room's presence options to use this feature (this is the default value). - * - * - Parameters: - * - events: An array of presence event types ``PresenceEventType`` to subscribe to. - * - bufferingPolicy: The ``BufferingPolicy`` for the created subscription. - * - * - Returns: A subscription `AsyncSequence` that can be used to iterate through ``PresenceEvent`` events. - */ - func subscribe(events: [PresenceEventType], bufferingPolicy: BufferingPolicy) -> SubscriptionAsyncSequence { - let subscriptionAsyncSequence = SubscriptionAsyncSequence(bufferingPolicy: bufferingPolicy) - - let subscription = subscribe(events: events) { presence in - subscriptionAsyncSequence.emit(presence) - } - - subscriptionAsyncSequence.addTerminationHandler { - Task { @MainActor in - subscription.unsubscribe() - } - } - - return subscriptionAsyncSequence - } - /// Same as calling ``subscribe(bufferingPolicy:)`` with ``BufferingPolicy/unbounded``. func subscribe() -> SubscriptionAsyncSequence { subscribe(bufferingPolicy: .unbounded) } - - /// Same as calling ``subscribe(event:bufferingPolicy:)`` with ``BufferingPolicy/unbounded``. - func subscribe(event: PresenceEventType) -> SubscriptionAsyncSequence { - subscribe(event: event, bufferingPolicy: .unbounded) - } - - /// Same as calling ``subscribe(events:bufferingPolicy:)`` with ``BufferingPolicy/unbounded``. - func subscribe(events: [PresenceEventType]) -> SubscriptionAsyncSequence { - subscribe(events: events, bufferingPolicy: .unbounded) - } } /** diff --git a/Tests/AblyChatTests/DefaultPresenceTests.swift b/Tests/AblyChatTests/DefaultPresenceTests.swift index 607af5ef..a74a06ba 100644 --- a/Tests/AblyChatTests/DefaultPresenceTests.swift +++ b/Tests/AblyChatTests/DefaultPresenceTests.swift @@ -10,7 +10,7 @@ struct DefaultPresenceTests { @Test func usersMayEnterPresence() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let defaultPresence = await DefaultPresence( channel: channel, @@ -34,7 +34,7 @@ struct DefaultPresenceTests { @Test func usersMayEnterPresenceWithoutData() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let defaultPresence = await DefaultPresence( channel: channel, @@ -58,7 +58,7 @@ struct DefaultPresenceTests { @Test func usersMayEnterPresenceWhileAttaching() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -86,7 +86,7 @@ struct DefaultPresenceTests { let attachError = ARTErrorInfo(domain: "SomeDomain", code: 123) let error = ARTErrorInfo(chatError: .roomTransitionedToInvalidStateForPresenceOperation(cause: attachError)) - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager(resultOfWaitToBeAbleToPerformPresenceOperations: .failure(error)) let defaultPresence = await DefaultPresence( @@ -120,7 +120,7 @@ struct DefaultPresenceTests { func failToEnterPresenceWhenRoomInInvalidState() async throws { // Given let error = ARTErrorInfo(chatError: .presenceOperationRequiresRoomAttach(feature: .presence)) - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager(resultOfWaitToBeAbleToPerformPresenceOperations: .failure(error)) let defaultPresence = await DefaultPresence( @@ -150,7 +150,7 @@ struct DefaultPresenceTests { @Test func usersMayUpdatePresence() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -174,7 +174,7 @@ struct DefaultPresenceTests { @Test func usersMayUpdatePresenceWhileAttaching() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -202,7 +202,7 @@ struct DefaultPresenceTests { let attachError = ARTErrorInfo(domain: "SomeDomain", code: 123) let error = ARTErrorInfo(chatError: .roomTransitionedToInvalidStateForPresenceOperation(cause: attachError)) - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager(resultOfWaitToBeAbleToPerformPresenceOperations: .failure(error)) let defaultPresence = await DefaultPresence( @@ -236,7 +236,7 @@ struct DefaultPresenceTests { func failToUpdatePresenceWhenRoomInInvalidState() async throws { // Given let error = ARTErrorInfo(chatError: .presenceOperationRequiresRoomAttach(feature: .presence)) - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager(resultOfWaitToBeAbleToPerformPresenceOperations: .failure(error)) let defaultPresence = await DefaultPresence( @@ -265,7 +265,7 @@ struct DefaultPresenceTests { @Test func usersMayLeavePresence() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -292,7 +292,7 @@ struct DefaultPresenceTests { @Test func ifUserIsPresent() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -320,7 +320,7 @@ struct DefaultPresenceTests { @Test func retrieveAllTheMembersOfThePresenceSet() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -346,7 +346,7 @@ struct DefaultPresenceTests { func failToRetrieveAllTheMembersOfThePresenceSetWhenRoomInInvalidState() async throws { // Given let error = ARTErrorInfo(chatError: .presenceOperationRequiresRoomAttach(feature: .presence)) - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager(resultOfWaitToBeAbleToPerformPresenceOperations: .failure(error)) let defaultPresence = await DefaultPresence( @@ -373,7 +373,7 @@ struct DefaultPresenceTests { @Test func retrieveAllTheMembersOfThePresenceSetWhileAttaching() async throws { // Given - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager() let defaultPresence = await DefaultPresence( @@ -401,7 +401,7 @@ struct DefaultPresenceTests { let attachError = ARTErrorInfo(domain: "SomeDomain", code: 123) let error = ARTErrorInfo(chatError: .roomTransitionedToInvalidStateForPresenceOperation(cause: attachError)) - let channel = await MockRealtimeChannel(name: "basketball::$chat::$chatMessages") + let channel = await MockRealtimeChannel(name: "basketball::$chat") let logger = TestLogger() let roomLifecycleManager = await MockRoomLifecycleManager(resultOfWaitToBeAbleToPerformPresenceOperations: .failure(error)) let defaultPresence = await DefaultPresence( diff --git a/Tests/AblyChatTests/Helpers/Helpers.swift b/Tests/AblyChatTests/Helpers/Helpers.swift index 2676e4a9..5483afe6 100644 --- a/Tests/AblyChatTests/Helpers/Helpers.swift +++ b/Tests/AblyChatTests/Helpers/Helpers.swift @@ -85,15 +85,6 @@ extension ARTPresenceMessage { } } -extension [PresenceEventType] { - static let all = [ - PresenceEventType.present, - PresenceEventType.enter, - PresenceEventType.leave, - PresenceEventType.update, - ] -} - /// Compares Any to another Any which is unavailable by default in swift for type safety, but useful to have in tests. func compareAny(_ any1: Any?, with any2: Any?) -> Bool { guard let any1, let any2 else { diff --git a/Tests/AblyChatTests/IntegrationTests.swift b/Tests/AblyChatTests/IntegrationTests.swift index cf8fc16f..c0b0644f 100644 --- a/Tests/AblyChatTests/IntegrationTests.swift +++ b/Tests/AblyChatTests/IntegrationTests.swift @@ -375,8 +375,8 @@ struct IntegrationTests { // MARK: - Presence - // (1) Subscribe to presence - let rxPresenceSubscription = rxRoom.presence.subscribe(events: [.enter, .leave, .update]) + // (1) Subscribe to all presence events + let rxPresenceSubscription = rxRoom.presence.subscribe() // (2) Send `.enter` presence event with custom data on the other client and check that we receive it on the subscription try await txRoom.presence.enter(withData: ["randomData": "randomValue"])