Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add presence to RealtimeChannelProtocol #212

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Example/AblyChatExample/Mocks/MockClients.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Message>()

Expand Down Expand Up @@ -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<Reaction>()

Expand Down Expand Up @@ -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<TypingEvent>()

Expand Down Expand Up @@ -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<OccupancyEvent>()

Expand Down
100 changes: 97 additions & 3 deletions Example/AblyChatExample/Mocks/MockRealtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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) {}
Expand Down
2 changes: 2 additions & 0 deletions Sources/AblyChat/AblyCocoaExtensions/Ably+Dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ extension ARTRealtimeChannels: RealtimeChannelsProtocol {}

extension ARTRealtimeChannel: RealtimeChannelProtocol {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix protocol conformance for ARTRealtimeChannel.

The pipeline is failing with the error: "type 'ARTRealtimeChannel' does not conform to protocol 'RealtimeChannelProtocol'". This is likely because ARTRealtimeChannel is missing required members of RealtimeChannelProtocol, specifically the presence property of type any RealtimePresenceProtocol. To resolve this, you need to ensure that ARTRealtimeChannel provides an implementation for the presence property that conforms to RealtimePresenceProtocol.

Apply this diff to fix the issue:

 extension ARTRealtimeChannel: RealtimeChannelProtocol {
+    public var presence: any RealtimePresenceProtocol {
+        return self.presence as any RealtimePresenceProtocol
+    }
 }

Ensure that self.presence correctly returns an instance conforming to RealtimePresenceProtocol. This should satisfy the protocol requirements and fix the pipeline failure.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Actions: Check

[error] 7-7: type 'ARTRealtimeChannel' does not conform to protocol 'RealtimeChannelProtocol'


extension ARTRealtimePresence: RealtimePresenceProtocol {}

extension ARTConnection: ConnectionProtocol {}
9 changes: 8 additions & 1 deletion Sources/AblyChat/Dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/Occupancy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ internal actor DefaultRoom<LifecycleManagerFactory: RoomLifecycleManagerFactory>
}

private struct FeatureChannelPartialDependencies {
internal var channel: RealtimeChannelProtocol
internal var channel: any RealtimeChannelProtocol
internal var contributor: DefaultRoomLifecycleContributor
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/AblyChat/RoomFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/RoomReactions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Sources/AblyChat/Typing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions Tests/AblyChatTests/Mocks/MockFeatureChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import Ably
@testable import AblyChat

final actor MockFeatureChannel: FeatureChannel {
let channel: RealtimeChannelProtocol
let channel: any RealtimeChannelProtocol
private var discontinuitySubscriptions = SubscriptionStorage<DiscontinuityEvent>()
private let resultOfWaitToBeAbleToPerformPresenceOperations: Result<Void, ARTErrorInfo>?

init(
channel: RealtimeChannelProtocol,
channel: any RealtimeChannelProtocol,
resultOfWaitToBeAblePerformPresenceOperations: Result<Void, ARTErrorInfo>? = nil
) {
self.channel = channel
Expand Down
4 changes: 1 addition & 3 deletions Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
98 changes: 98 additions & 0 deletions Tests/AblyChatTests/Mocks/MockRealtimePresence.swift
Original file line number Diff line number Diff line change
@@ -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")
}
}
Comment on lines +4 to +98
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve mock implementation consistency and documentation.

Issues found:

  1. The history(_:) method has an empty implementation while all other methods throw fatalError. This inconsistency could lead to confusion.
  2. Missing documentation explaining the mock's intended use and which methods are expected to be implemented.
  3. Consider using a more descriptive error message in fatalError calls.

Consider these improvements:

  1. Add documentation:
/// A mock implementation of RealtimePresenceProtocol for testing purposes.
/// This mock currently throws fatalError for all methods as they are not yet implemented.
final class MockRealtimePresence: RealtimePresenceProtocol {
  1. Make implementation consistent:
-    func history(_: @escaping ARTPaginatedPresenceCallback) {}
+    func history(_: @escaping ARTPaginatedPresenceCallback) {
+        fatalError("Not implemented")
+    }
  1. Add more descriptive error messages:
-        fatalError("Not implemented")
+        fatalError("MockRealtimePresence.syncComplete is not implemented")

Loading