Skip to content

Commit a500358

Browse files
authored
Merge pull request #285 from ably/ECO-5241-part2
[ECO-5241] Finish Ephemeral Typing
2 parents 6e736d4 + e89e367 commit a500358

File tree

7 files changed

+514
-25
lines changed

7 files changed

+514
-25
lines changed

Example/AblyChatExample/Mocks/MockClients.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,17 @@ class MockTyping: Typing {
230230
let clientID: String
231231
let roomID: String
232232

233-
private let mockSubscriptions = MockSubscriptionStorage<TypingEvent>()
233+
private let mockSubscriptions = MockSubscriptionStorage<TypingSetEvent>()
234234

235235
init(clientID: String, roomID: String) {
236236
self.clientID = clientID
237237
self.roomID = roomID
238238
}
239239

240-
private func createSubscription() -> MockSubscription<TypingEvent> {
240+
private func createSubscription() -> MockSubscription<TypingSetEvent> {
241241
mockSubscriptions.create(randomElement: {
242-
TypingEvent(
242+
TypingSetEvent(
243+
type: .setChanged,
243244
currentlyTyping: [
244245
MockStrings.names.randomElement()!,
245246
MockStrings.names.randomElement()!,
@@ -249,7 +250,7 @@ class MockTyping: Typing {
249250
}, interval: 2)
250251
}
251252

252-
func subscribe(bufferingPolicy _: BufferingPolicy) -> Subscription<TypingEvent> {
253+
func subscribe(bufferingPolicy _: BufferingPolicy) -> Subscription<TypingSetEvent> {
253254
.init(mockAsyncSequence: createSubscription())
254255
}
255256

@@ -258,11 +259,23 @@ class MockTyping: Typing {
258259
}
259260

260261
func keystroke() async throws(ARTErrorInfo) {
261-
mockSubscriptions.emit(TypingEvent(currentlyTyping: [clientID], change: .init(clientId: clientID, type: .started)))
262+
mockSubscriptions.emit(
263+
TypingSetEvent(
264+
type: .setChanged,
265+
currentlyTyping: [clientID],
266+
change: .init(clientId: clientID, type: .started)
267+
)
268+
)
262269
}
263270

264271
func stop() async throws(ARTErrorInfo) {
265-
mockSubscriptions.emit(TypingEvent(currentlyTyping: [], change: .init(clientId: clientID, type: .stopped)))
272+
mockSubscriptions.emit(
273+
TypingSetEvent(
274+
type: .setChanged,
275+
currentlyTyping: [],
276+
change: .init(clientId: clientID, type: .stopped)
277+
)
278+
)
266279
}
267280
}
268281

Sources/AblyChat/DefaultTyping.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ internal final class DefaultTyping: Typing {
88
}
99

1010
// (CHA-T6) Users may subscribe to typing events – updates to a set of clientIDs that are typing. This operation, like all subscription operations, has no side-effects in relation to room lifecycle.
11-
internal func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription<TypingEvent> {
11+
internal func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription<TypingSetEvent> {
1212
implementation.subscribe(bufferingPolicy: bufferingPolicy)
1313
}
1414

@@ -70,11 +70,11 @@ internal final class DefaultTyping: Typing {
7070
)
7171
}
7272

73-
internal func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription<TypingEvent> {
73+
internal func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription<TypingSetEvent> {
7474
// (CHA-T6a) Users may provide a listener to subscribe to typing event V2 in a chat room.
75-
let subscription = Subscription<TypingEvent>(bufferingPolicy: bufferingPolicy)
75+
let subscription = Subscription<TypingSetEvent>(bufferingPolicy: bufferingPolicy)
7676

77-
let startedEventListener = channel.subscribe(TypingEvents.started.rawValue) { [weak self] message in
77+
let startedEventListener = channel.subscribe(TypingEventType.started.rawValue) { [weak self] message in
7878
guard let self, let messageClientID = message.clientId else {
7979
return
8080
}
@@ -91,21 +91,26 @@ internal final class DefaultTyping: Typing {
9191
}
9292
// (CHA-T13b3) (2/2) If the (CHA-T13b1) timeout expires, the client shall remove the clientId from the typing set and emit a synthetic typing stop event for the given client.
9393
subscription.emit(
94-
TypingEvent(currentlyTyping: typingTimerManager.currentlyTypingClientIDs(), change: .init(clientId: messageClientID, type: .stopped))
94+
TypingSetEvent(
95+
type: .setChanged,
96+
currentlyTyping: typingTimerManager.currentlyTypingClientIDs(),
97+
change: .init(clientId: messageClientID, type: .stopped)
98+
)
9599
)
96100
}
97101

98102
// (CHA-T13) When a typing event (typing.start or typing.stop) is received from the realtime client, the Chat client shall emit appropriate events to the user.
99103
subscription.emit(
100-
TypingEvent(
104+
TypingSetEvent(
105+
type: .setChanged,
101106
currentlyTyping: typingTimerManager.currentlyTypingClientIDs(),
102107
change: .init(clientId: messageClientID, type: .started)
103108
)
104109
)
105110
}
106111
}
107112

108-
let stoppedEventListener = channel.subscribe(TypingEvents.stopped.rawValue) { [weak self] message in
113+
let stoppedEventListener = channel.subscribe(TypingEventType.stopped.rawValue) { [weak self] message in
109114
guard let self, let messageClientID = message.clientId else {
110115
return
111116
}
@@ -119,7 +124,8 @@ internal final class DefaultTyping: Typing {
119124

120125
// (CHA-T13) When a typing event (typing.start or typing.stop) is received from the realtime client, the Chat client shall emit appropriate events to the user.
121126
subscription.emit(
122-
TypingEvent(
127+
TypingSetEvent(
128+
type: .setChanged,
123129
currentlyTyping: typingTimerManager.currentlyTypingClientIDs(),
124130
change: .init(clientId: messageClientID, type: .stopped)
125131
)
@@ -171,7 +177,7 @@ internal final class DefaultTyping: Typing {
171177
// (CHA-T4a3) The client shall publish an ephemeral message to the channel with the name field set to typing.started, the format of which is detailed here.
172178
// (CHA-T4a5) The client must wait for the publish to succeed or fail before returning the result to the caller. If the publish fails, the client must throw an ErrorInfo.
173179
try await channel.publish(
174-
TypingEvents.started.rawValue,
180+
TypingEventType.started.rawValue,
175181
data: nil,
176182
extras: ["ephemeral": true]
177183
)
@@ -191,7 +197,7 @@ internal final class DefaultTyping: Typing {
191197
logger.log(message: "Stopping typing indicator for client: \(clientID)", level: .debug)
192198
// (CHA-T5d) The client shall publish an ephemeral message to the channel with the name field set to typing.stopped, the format of which is detailed here.
193199
try await channel.publish(
194-
TypingEvents.stopped.rawValue,
200+
TypingEventType.stopped.rawValue,
195201
data: nil,
196202
extras: ["ephemeral": true]
197203
)

Sources/AblyChat/Events.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ internal enum OccupancyEvents: String {
4343
case meta = "[meta]occupancy"
4444
}
4545

46-
public enum TypingEvents: String, Sendable {
46+
/// Enum representing the typing event types.
47+
public enum TypingEventType: String, Sendable {
4748
case started = "typing.started"
4849
case stopped = "typing.stopped"
4950
}
51+
52+
/// Enum representing the typing set event types.
53+
public enum TypingSetEventType: String, Sendable {
54+
case setChanged = "typing.set.changed"
55+
}

Sources/AblyChat/Typing.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ public protocol Typing: AnyObject, Sendable {
1616
*
1717
* - Returns: A subscription `AsyncSequence` that can be used to iterate through ``TypingEvent`` events.
1818
*/
19-
func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription<TypingEvent>
19+
func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription<TypingSetEvent>
2020

2121
/// Same as calling ``subscribe(bufferingPolicy:)`` with ``BufferingPolicy/unbounded``.
2222
///
2323
/// The `Typing` protocol provides a default implementation of this method.
24-
func subscribe() -> Subscription<TypingEvent>
24+
func subscribe() -> Subscription<TypingSetEvent>
2525

2626
/**
2727
* Get the current typers, a set of clientIds.
@@ -53,15 +53,17 @@ public protocol Typing: AnyObject, Sendable {
5353
}
5454

5555
public extension Typing {
56-
func subscribe() -> Subscription<TypingEvent> {
56+
func subscribe() -> Subscription<TypingSetEvent> {
5757
subscribe(bufferingPolicy: .unbounded)
5858
}
5959
}
6060

6161
/**
6262
* Represents a typing event.
6363
*/
64-
public struct TypingEvent: Sendable {
64+
public struct TypingSetEvent: Sendable {
65+
public var type: TypingSetEventType
66+
6567
/**
6668
* Get a set of clientIds that are currently typing.
6769
*/
@@ -72,16 +74,17 @@ public struct TypingEvent: Sendable {
7274
*/
7375
public var change: Change
7476

75-
public init(currentlyTyping: Set<String>, change: Change) {
77+
public init(type: TypingSetEventType, currentlyTyping: Set<String>, change: Change) {
78+
self.type = type
7679
self.currentlyTyping = currentlyTyping
7780
self.change = change
7881
}
7982

8083
public struct Change: Sendable {
8184
public var clientId: String
82-
public var type: TypingEvents
85+
public var type: TypingEventType
8386

84-
public init(clientId: String, type: TypingEvents) {
87+
public init(clientId: String, type: TypingEventType) {
8588
self.clientId = clientId
8689
self.type = type
8790
}

0 commit comments

Comments
 (0)