Skip to content

Commit e5e19bf

Browse files
committed
Refactor Occupancy events
[ECO-5342]
1 parent 0f0d8fb commit e5e19bf

7 files changed

Lines changed: 46 additions & 29 deletions

File tree

Example/AblyChatExample/ContentView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,9 @@ struct ContentView: View {
350350
}
351351

352352
func subscribeToOccupancy(room: Room) {
353-
room.occupancy.subscribe { occupancy in
353+
room.occupancy.subscribe { event in
354354
withAnimation {
355-
occupancyInfo = "Connections: \(occupancy.presenceMembers) (\(occupancy.connections))"
355+
occupancyInfo = "Connections: \(event.occupancy.presenceMembers) (\(event.occupancy.connections))"
356356
}
357357
}
358358
}

Example/AblyChatExample/Mocks/MockClients.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,15 +536,16 @@ class MockOccupancy: Occupancy {
536536
mockSubscriptions.create(
537537
randomElement: {
538538
let random = Int.random(in: 1 ... 10)
539-
return OccupancyEvent(connections: random, presenceMembers: Int.random(in: 0 ... random))
539+
let occupancyData = OccupancyData(connections: random, presenceMembers: Int.random(in: 0 ... random))
540+
return OccupancyEvent(type: .updated, occupancy: occupancyData)
540541
},
541542
interval: 2,
542543
callback: callback
543544
)
544545
}
545546

546-
func get() async throws(ARTErrorInfo) -> OccupancyEvent {
547-
OccupancyEvent(connections: 10, presenceMembers: 5)
547+
func get() async throws(ARTErrorInfo) -> OccupancyData {
548+
OccupancyData(connections: 10, presenceMembers: 5)
548549
}
549550
}
550551

Sources/AblyChat/ChatAPI.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ internal final class ChatAPI: Sendable {
192192
return message
193193
}
194194

195-
internal func getOccupancy(roomName: String) async throws(InternalError) -> OccupancyEvent {
195+
internal func getOccupancy(roomName: String) async throws(InternalError) -> OccupancyData {
196196
let endpoint = "\(apiVersionV3)/rooms/\(roomName)/occupancy"
197197
return try await makeRequest(endpoint, method: "GET")
198198
}

Sources/AblyChat/DefaultOccupancy.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal final class DefaultOccupancy: Occupancy {
1212
implementation.subscribe(callback)
1313
}
1414

15-
internal func get() async throws(ARTErrorInfo) -> OccupancyEvent {
15+
internal func get() async throws(ARTErrorInfo) -> OccupancyData {
1616
try await implementation.get()
1717
}
1818

@@ -58,7 +58,8 @@ internal final class DefaultOccupancy: Occupancy {
5858
let connections = metrics["connections"] as? Int ?? 0
5959
let presenceMembers = metrics["presenceMembers"] as? Int ?? 0
6060

61-
let occupancyEvent = OccupancyEvent(connections: connections, presenceMembers: presenceMembers)
61+
let occupancyData = OccupancyData(connections: connections, presenceMembers: presenceMembers)
62+
let occupancyEvent = OccupancyEvent(type: .updated, occupancy: occupancyData)
6263
logger.log(message: "Emitting occupancy event: \(occupancyEvent)", level: .debug)
6364
callback(occupancyEvent)
6465
}
@@ -72,7 +73,7 @@ internal final class DefaultOccupancy: Occupancy {
7273
}
7374

7475
// (CHA-O3) Users can request an instantaneous occupancy check via the REST API. The request is detailed here (https://sdk.ably.com/builds/ably/specification/main/chat-features/#rest-occupancy-request), with the response format being a simple occupancy event
75-
internal func get() async throws(ARTErrorInfo) -> OccupancyEvent {
76+
internal func get() async throws(ARTErrorInfo) -> OccupancyData {
7677
do {
7778
logger.log(message: "Getting occupancy for room: \(roomName)", level: .debug)
7879
return try await chatAPI.getOccupancy(roomName: roomName)

Sources/AblyChat/Occupancy.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public protocol Occupancy: AnyObject, Sendable {
2626
*
2727
* - Returns: A current occupancy of the chat room.
2828
*/
29-
func get() async throws(ARTErrorInfo) -> OccupancyEvent
29+
func get() async throws(ARTErrorInfo) -> OccupancyData
3030
}
3131

3232
/// `AsyncSequence` variant of receiving room occupancy events.
@@ -44,8 +44,8 @@ public extension Occupancy {
4444
func subscribe(bufferingPolicy: BufferingPolicy) -> SubscriptionAsyncSequence<OccupancyEvent> {
4545
let subscriptionAsyncSequence = SubscriptionAsyncSequence<OccupancyEvent>(bufferingPolicy: bufferingPolicy)
4646

47-
let subscription = subscribe { occupancy in
48-
subscriptionAsyncSequence.emit(occupancy)
47+
let subscription = subscribe { occupancyEvent in
48+
subscriptionAsyncSequence.emit(occupancyEvent)
4949
}
5050

5151
subscriptionAsyncSequence.addTerminationHandler {
@@ -68,7 +68,7 @@ public extension Occupancy {
6868
/**
6969
* Represents the occupancy of a chat room.
7070
*/
71-
public struct OccupancyEvent: Sendable {
71+
public struct OccupancyData: Sendable {
7272
/**
7373
* The number of connections to the chat room.
7474
*/
@@ -85,7 +85,21 @@ public struct OccupancyEvent: Sendable {
8585
}
8686
}
8787

88-
extension OccupancyEvent: JSONObjectDecodable {
88+
public enum OccupancyEventType: String, Sendable {
89+
case updated
90+
}
91+
92+
public struct OccupancyEvent: Sendable {
93+
public let type: OccupancyEventType
94+
public let occupancy: OccupancyData
95+
96+
public init(type: OccupancyEventType, occupancy: OccupancyData) {
97+
self.type = type
98+
self.occupancy = occupancy
99+
}
100+
}
101+
102+
extension OccupancyData: JSONObjectDecodable {
89103
internal init(jsonObject: [String: JSONValue]) throws(InternalError) {
90104
try self.init(
91105
connections: Int(jsonObject.numberValueForKey("connections")),

Tests/AblyChatTests/DefaultRoomOccupancyTests.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,12 @@ struct DefaultRoomOccupancyTests {
5858

5959
// When
6060
let subscription = defaultOccupancy.subscribe()
61-
subscription.emit(OccupancyEvent(connections: 5, presenceMembers: 2))
61+
let occupancyData = OccupancyData(connections: 5, presenceMembers: 2)
62+
subscription.emit(OccupancyEvent(type: .updated, occupancy: occupancyData))
6263

6364
// Then
64-
let occupancyInfo = try #require(await subscription.first { @Sendable _ in true })
65-
#expect(occupancyInfo.connections == 5)
66-
#expect(occupancyInfo.presenceMembers == 2)
65+
let occupancyEvent = try #require(await subscription.first { @Sendable _ in true })
66+
#expect(occupancyEvent.occupancy.connections == 5)
67+
#expect(occupancyEvent.occupancy.presenceMembers == 2)
6768
}
6869
}

Tests/AblyChatTests/IntegrationTests.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ extension Tag {
99

1010
/// Some very basic integration tests, just to check that things are kind of working.
1111
///
12-
/// It would be nice to give this a time limit, but unfortunately the `timeLimit` trait is only available on iOS 16 etc and above. CodeRabbit suggested writing a timeout function myself and wrapping the contents of the test in it, but I didnt have time to try understanding its suggested code, so it can wait.
12+
/// It would be nice to give this a time limit, but unfortunately the `timeLimit` trait is only available on iOS 16 etc and above. CodeRabbit suggested writing a timeout function myself and wrapping the contents of the test in it, but I didn't have time to try understanding its suggested code, so it can wait.
1313
@Suite(.tags(.integration))
1414
@MainActor
1515
struct IntegrationTests {
@@ -106,7 +106,7 @@ struct IntegrationTests {
106106

107107
// (1) Send a message before subscribing to messages, so that later on we can check history works.
108108

109-
// (2) Create a throwaway subscription and wait for it to receive a message. This is to make sure that rxRoom has seen the message that we send here, so that the first message we receive on the subscription created in (5) is that which well send in (6), and not that which we send here.
109+
// (2) Create a throwaway subscription and wait for it to receive a message. This is to make sure that rxRoom has seen the message that we send here, so that the first message we receive on the subscription created in (5) is that which we'll send in (6), and not that which we send here.
110110
let throwawayRxMessageSubscription = try await rxRoom.messages.subscribe()
111111

112112
// (3) Send the message
@@ -123,7 +123,7 @@ struct IntegrationTests {
123123
// (5) Subscribe to messages
124124
let rxMessageSubscription = try await rxRoom.messages.subscribe()
125125

126-
// (6) Now that were subscribed to messages, send a message on the other client and check that we receive it on the subscription
126+
// (6) Now that we're subscribed to messages, send a message on the other client and check that we receive it on the subscription
127127
let txMessageAfterRxSubscribe = try await txRoom.messages.send(
128128
params: .init(
129129
text: "Hello from txRoom, after rxRoom subscribe",
@@ -227,15 +227,15 @@ struct IntegrationTests {
227227
https://ably-real-time.slack.com/archives/C03JDBVM5MY/p1733220395208909
228228
that
229229

230-
> new materialised history system doesnt currently support live
231-
> history (realtime implementation detail) - so were approximating the
230+
> new materialised history system doesn't currently support "live"
231+
> history (realtime implementation detail) - so we're approximating the
232232
> behaviour
233233

234234
and indicated that the right workaround for now is to introduce a
235235
wait. So we retry the fetching of history until we get a non-empty
236236
result.
237237

238-
Revert this (https://github.com/ably/ably-chat-swift/issues/175) once its fixed in Realtime.
238+
Revert this (https://github.com/ably/ably-chat-swift/issues/175) once it's fixed in Realtime.
239239
*/
240240
let rxMessagesHistory = try await {
241241
while true {
@@ -323,7 +323,7 @@ struct IntegrationTests {
323323
// (1) Subscribe to reactions
324324
let rxReactionSubscription = rxRoom.reactions.subscribe()
325325

326-
// (2) Now that were subscribed to reactions, send a reaction on the other client and check that we receive it on the subscription
326+
// (2) Now that we're subscribed to reactions, send a reaction on the other client and check that we receive it on the subscription
327327
try await txRoom.reactions.send(
328328
params: .init(
329329
type: "heart",
@@ -338,7 +338,7 @@ struct IntegrationTests {
338338

339339
// MARK: - Occupancy
340340

341-
// It can take a moment for the occupancy to update from the clients connecting above, so well wait a 2 seconds here.
341+
// It can take a moment for the occupancy to update from the clients connecting above, so we'll wait a 2 seconds here.
342342
try await Task.sleep(nanoseconds: 2_000_000_000)
343343

344344
// (1) Get current occupancy
@@ -357,7 +357,7 @@ struct IntegrationTests {
357357

358358
// (5) Check that we received an updated presence count on the subscription
359359
_ = try #require(await rxOccupancySubscription.first { @Sendable occupancyEvent in
360-
occupancyEvent.presenceMembers == 1 // 1 for txClient entering presence
360+
occupancyEvent.occupancy.presenceMembers == 1 // 1 for txClient entering presence
361361
})
362362

363363
// (6) Check that we received an updated presence count when getting the occupancy
@@ -369,7 +369,7 @@ struct IntegrationTests {
369369

370370
// (8) Check that we received an updated presence count on the subscription
371371
_ = try #require(await rxOccupancySubscription.first { @Sendable occupancyEvent in
372-
occupancyEvent.presenceMembers == 0 // 0 for txClient leaving presence
372+
occupancyEvent.occupancy.presenceMembers == 0 // 0 for txClient leaving presence
373373
})
374374

375375
// (9) Check that we received an updated presence count when getting the occupancy
@@ -509,7 +509,7 @@ struct IntegrationTests {
509509
})
510510
#expect(rxRoom.status == .released)
511511

512-
// (3) Fetch the room we just released and check its a new object
512+
// (3) Fetch the room we just released and check it's a new object
513513
let postReleaseRxRoom = try await rxClient.rooms.get(name: roomName, options: .init())
514514
#expect(postReleaseRxRoom !== rxRoom)
515515
}

0 commit comments

Comments
 (0)