Skip to content

Commit ed4c028

Browse files
Merge pull request #163 from ably/CHA-PR3h-etc
[ECO-5144] Implement CHA-PR3h etc
2 parents 6a2b03f + ba4658d commit ed4c028

File tree

7 files changed

+170
-116
lines changed

7 files changed

+170
-116
lines changed

Sources/AblyChat/DefaultMessages.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,11 @@ internal final class DefaultMessages: Messages, EmitsDiscontinuities {
234234
case .failed, .suspended:
235235
// TODO: Revisit as part of https://github.com/ably-labs/ably-chat-swift/issues/32
236236
logger.log(message: "Channel failed to attach", level: .error)
237+
let errorCodeCase = ErrorCode.CaseThatImpliesFixedStatusCode.messagesAttachmentFailed
237238
nillableContinuation?.resume(
238239
throwing: ARTErrorInfo.create(
239-
withCode: ErrorCode.messagesAttachmentFailed.rawValue,
240-
status: ErrorCode.messagesAttachmentFailed.statusCode,
240+
withCode: errorCodeCase.toNumericErrorCode.rawValue,
241+
status: errorCodeCase.statusCode,
241242
message: "Channel failed to attach"
242243
)
243244
)

Sources/AblyChat/Errors.swift

Lines changed: 136 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ public let errorDomain = "AblyChatErrorDomain"
1111
The error codes for errors in the ``errorDomain`` error domain.
1212
*/
1313
public enum ErrorCode: Int {
14-
case nonspecific = 40000
15-
1614
/// ``Rooms.get(roomID:options:)`` was called with a different set of room options than was used on a previous call. You must first release the existing room instance using ``Rooms.release(roomID:)``.
1715
///
1816
/// TODO this code is a guess, revisit in https://github.com/ably-labs/ably-chat-swift/issues/32
@@ -36,30 +34,118 @@ public enum ErrorCode: Int {
3634

3735
case roomInInvalidState = 102_107
3836

37+
/// Has a case for each of the ``ErrorCode`` cases that imply a fixed status code.
38+
internal enum CaseThatImpliesFixedStatusCode {
39+
case inconsistentRoomOptions
40+
case messagesAttachmentFailed
41+
case presenceAttachmentFailed
42+
case reactionsAttachmentFailed
43+
case occupancyAttachmentFailed
44+
case typingAttachmentFailed
45+
case messagesDetachmentFailed
46+
case presenceDetachmentFailed
47+
case reactionsDetachmentFailed
48+
case occupancyDetachmentFailed
49+
case typingDetachmentFailed
50+
case roomInFailedState
51+
case roomIsReleasing
52+
case roomIsReleased
53+
54+
internal var toNumericErrorCode: ErrorCode {
55+
switch self {
56+
case .inconsistentRoomOptions:
57+
.inconsistentRoomOptions
58+
case .messagesAttachmentFailed:
59+
.messagesAttachmentFailed
60+
case .presenceAttachmentFailed:
61+
.presenceAttachmentFailed
62+
case .reactionsAttachmentFailed:
63+
.reactionsAttachmentFailed
64+
case .occupancyAttachmentFailed:
65+
.occupancyAttachmentFailed
66+
case .typingAttachmentFailed:
67+
.typingAttachmentFailed
68+
case .messagesDetachmentFailed:
69+
.messagesDetachmentFailed
70+
case .presenceDetachmentFailed:
71+
.presenceDetachmentFailed
72+
case .reactionsDetachmentFailed:
73+
.reactionsDetachmentFailed
74+
case .occupancyDetachmentFailed:
75+
.occupancyDetachmentFailed
76+
case .typingDetachmentFailed:
77+
.typingDetachmentFailed
78+
case .roomInFailedState:
79+
.roomInFailedState
80+
case .roomIsReleasing:
81+
.roomIsReleasing
82+
case .roomIsReleased:
83+
.roomIsReleased
84+
}
85+
}
86+
87+
/// The ``ARTErrorInfo.statusCode`` that should be returned for this error.
88+
internal var statusCode: Int {
89+
// These status codes are taken from the "Chat-specific Error Codes" section of the spec.
90+
switch self {
91+
case .inconsistentRoomOptions,
92+
.roomInFailedState,
93+
.roomIsReleasing,
94+
.roomIsReleased:
95+
400
96+
case
97+
.messagesAttachmentFailed,
98+
.presenceAttachmentFailed,
99+
.reactionsAttachmentFailed,
100+
.occupancyAttachmentFailed,
101+
.typingAttachmentFailed,
102+
.messagesDetachmentFailed,
103+
.presenceDetachmentFailed,
104+
.reactionsDetachmentFailed,
105+
.occupancyDetachmentFailed,
106+
.typingDetachmentFailed:
107+
500
108+
}
109+
}
110+
}
111+
112+
/// Has a case for each of the ``ErrorCode`` cases that do not imply a fixed status code.
113+
internal enum CaseThatImpliesVariableStatusCode {
114+
case roomInInvalidState
115+
116+
internal var toNumericErrorCode: ErrorCode {
117+
switch self {
118+
case .roomInInvalidState:
119+
.roomInInvalidState
120+
}
121+
}
122+
}
123+
}
124+
125+
/**
126+
* Represents a case of ``ErrorCode`` plus a status code.
127+
*/
128+
internal enum ErrorCodeAndStatusCode {
129+
case fixedStatusCode(ErrorCode.CaseThatImpliesFixedStatusCode)
130+
case variableStatusCode(ErrorCode.CaseThatImpliesVariableStatusCode, statusCode: Int)
131+
132+
/// The ``ARTErrorInfo.code`` that should be returned for this error.
133+
internal var code: ErrorCode {
134+
switch self {
135+
case let .fixedStatusCode(code):
136+
code.toNumericErrorCode
137+
case let .variableStatusCode(code, _):
138+
code.toNumericErrorCode
139+
}
140+
}
141+
39142
/// The ``ARTErrorInfo.statusCode`` that should be returned for this error.
40143
internal var statusCode: Int {
41-
// These status codes are taken from the "Chat-specific Error Codes" section of the spec.
42144
switch self {
43-
case .nonspecific,
44-
.inconsistentRoomOptions,
45-
.roomInFailedState,
46-
.roomIsReleasing,
47-
.roomIsReleased:
48-
400
49-
case
50-
.messagesAttachmentFailed,
51-
.presenceAttachmentFailed,
52-
.reactionsAttachmentFailed,
53-
.occupancyAttachmentFailed,
54-
.typingAttachmentFailed,
55-
.messagesDetachmentFailed,
56-
.presenceDetachmentFailed,
57-
.reactionsDetachmentFailed,
58-
.occupancyDetachmentFailed,
59-
.typingDetachmentFailed,
60-
// CHA-RL9c
61-
.roomInInvalidState:
62-
500
145+
case let .fixedStatusCode(code):
146+
code.statusCode
147+
case let .variableStatusCode(_, statusCode):
148+
statusCode
63149
}
64150
}
65151
}
@@ -77,51 +163,50 @@ internal enum ChatError {
77163
case roomIsReleasing
78164
case roomIsReleased
79165
case presenceOperationRequiresRoomAttach(feature: RoomFeature)
80-
case presenceOperationDisallowedForCurrentRoomStatus(feature: RoomFeature)
81-
case roomInInvalidState(cause: ARTErrorInfo?)
166+
case roomTransitionedToInvalidStateForPresenceOperation(cause: ARTErrorInfo?)
82167

83-
/// The ``ARTErrorInfo.code`` that should be returned for this error.
84-
internal var code: ErrorCode {
168+
internal var codeAndStatusCode: ErrorCodeAndStatusCode {
85169
switch self {
86170
case .inconsistentRoomOptions:
87-
.inconsistentRoomOptions
171+
.fixedStatusCode(.inconsistentRoomOptions)
88172
case let .attachmentFailed(feature, _):
89173
switch feature {
90174
case .messages:
91-
.messagesAttachmentFailed
175+
.fixedStatusCode(.messagesAttachmentFailed)
92176
case .occupancy:
93-
.occupancyAttachmentFailed
177+
.fixedStatusCode(.occupancyAttachmentFailed)
94178
case .presence:
95-
.presenceAttachmentFailed
179+
.fixedStatusCode(.presenceAttachmentFailed)
96180
case .reactions:
97-
.reactionsAttachmentFailed
181+
.fixedStatusCode(.reactionsAttachmentFailed)
98182
case .typing:
99-
.typingAttachmentFailed
183+
.fixedStatusCode(.typingAttachmentFailed)
100184
}
101185
case let .detachmentFailed(feature, _):
102186
switch feature {
103187
case .messages:
104-
.messagesDetachmentFailed
188+
.fixedStatusCode(.messagesDetachmentFailed)
105189
case .occupancy:
106-
.occupancyDetachmentFailed
190+
.fixedStatusCode(.occupancyDetachmentFailed)
107191
case .presence:
108-
.presenceDetachmentFailed
192+
.fixedStatusCode(.presenceDetachmentFailed)
109193
case .reactions:
110-
.reactionsDetachmentFailed
194+
.fixedStatusCode(.reactionsDetachmentFailed)
111195
case .typing:
112-
.typingDetachmentFailed
196+
.fixedStatusCode(.typingDetachmentFailed)
113197
}
114198
case .roomInFailedState:
115-
.roomInFailedState
199+
.fixedStatusCode(.roomInFailedState)
116200
case .roomIsReleasing:
117-
.roomIsReleasing
201+
.fixedStatusCode(.roomIsReleasing)
118202
case .roomIsReleased:
119-
.roomIsReleased
120-
case .roomInInvalidState:
121-
.roomInInvalidState
122-
case .presenceOperationRequiresRoomAttach,
123-
.presenceOperationDisallowedForCurrentRoomStatus:
124-
.nonspecific
203+
.fixedStatusCode(.roomIsReleased)
204+
case .roomTransitionedToInvalidStateForPresenceOperation:
205+
// CHA-RL9c
206+
.variableStatusCode(.roomInInvalidState, statusCode: 500)
207+
case .presenceOperationRequiresRoomAttach:
208+
// CHA-PR3h, CHA-PR10h, CHA-PR6h, CHA-T2g
209+
.variableStatusCode(.roomInInvalidState, statusCode: 400)
125210
}
126211
}
127212

@@ -177,9 +262,7 @@ internal enum ChatError {
177262
"Cannot perform operation because the room is in a released state."
178263
case let .presenceOperationRequiresRoomAttach(feature):
179264
"To perform this \(Self.descriptionOfFeature(feature)) operation, you must first attach the room."
180-
case let .presenceOperationDisallowedForCurrentRoomStatus(feature):
181-
"This \(Self.descriptionOfFeature(feature)) operation can not be performed given the current room status."
182-
case .roomInInvalidState:
265+
case .roomTransitionedToInvalidStateForPresenceOperation:
183266
"The room operation failed because the room was in an invalid state."
184267
}
185268
}
@@ -191,14 +274,13 @@ internal enum ChatError {
191274
underlyingError
192275
case let .detachmentFailed(_, underlyingError):
193276
underlyingError
194-
case let .roomInInvalidState(cause):
277+
case let .roomTransitionedToInvalidStateForPresenceOperation(cause):
195278
cause
196279
case .inconsistentRoomOptions,
197280
.roomInFailedState,
198281
.roomIsReleasing,
199282
.roomIsReleased,
200-
.presenceOperationRequiresRoomAttach,
201-
.presenceOperationDisallowedForCurrentRoomStatus:
283+
.presenceOperationRequiresRoomAttach:
202284
nil
203285
}
204286
}
@@ -208,7 +290,7 @@ internal extension ARTErrorInfo {
208290
convenience init(chatError: ChatError) {
209291
var userInfo: [String: Any] = [:]
210292
// TODO: copied and pasted from implementation of -[ARTErrorInfo createWithCode:status:message:requestId:] because there’s no way to pass domain; revisit in https://github.com/ably-labs/ably-chat-swift/issues/32. Also the ARTErrorInfoStatusCode variable in ably-cocoa is not public.
211-
userInfo["ARTErrorInfoStatusCode"] = chatError.code.statusCode
293+
userInfo["ARTErrorInfoStatusCode"] = chatError.codeAndStatusCode.statusCode
212294
userInfo[NSLocalizedDescriptionKey] = chatError.localizedDescription
213295

214296
// TODO: This is kind of an implementation detail (that NSUnderlyingErrorKey is what populates `cause`); consider documenting in ably-cocoa as part of https://github.com/ably-labs/ably-chat-swift/issues/32.
@@ -218,7 +300,7 @@ internal extension ARTErrorInfo {
218300

219301
self.init(
220302
domain: errorDomain,
221-
code: chatError.code.rawValue,
303+
code: chatError.codeAndStatusCode.code.rawValue,
222304
userInfo: userInfo
223305
)
224306
}

Sources/AblyChat/RoomFeature.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,11 @@ internal protocol FeatureChannel: Sendable, EmitsDiscontinuities {
4141

4242
/// Waits until we can perform presence operations on the contributors of this room without triggering an implicit attach.
4343
///
44-
/// Implements the checks described by CHA-PR3d, CHA-PR3e, CHA-PR3f, and CHA-PR3g (and similar ones described by other functionality that performs contributor presence operations). Namely:
44+
/// Implements the checks described by CHA-PR3d, CHA-PR3e, and CHA-PR3h (and similar ones described by other functionality that performs contributor presence operations). Namely:
4545
///
46-
/// - CHA-RL9, which is invoked by CHA-PR3d, CHA-PR10d, CHA-PR6c, CHA-T2c: If the room is in the ATTACHING status, it waits for the next room status change. If the new status is ATTACHED, it returns. Else, it throws an `ARTErrorInfo` derived from ``ChatError.roomInInvalidState(cause:)``.
47-
/// - CHA-PR3e, CHA-PR11e, CHA-PR6d, CHA-T2d: If the room is in the ATTACHED status, it returns immediately.
48-
/// - CHA-PR3f, CHA-PR11f, CHA-PR6e, CHA-T2e: If the room is in the DETACHED status, it throws an `ARTErrorInfo` derived from ``ChatError.presenceOperationRequiresRoomAttach(feature:)``.
49-
/// - // CHA-PR3g, CHA-PR11g, CHA-PR6f, CHA-T2f: If the room is in any other status, it throws an `ARTErrorInfo` derived from ``ChatError.presenceOperationDisallowedForCurrentRoomStatus(feature:)``.
46+
/// - CHA-RL9, which is invoked by CHA-PR3d, CHA-PR10d, CHA-PR6c, CHA-T2c: If the room is in the ATTACHING status, it waits for the next room status change. If the new status is ATTACHED, it returns. Else, it throws an `ARTErrorInfo` derived from ``ChatError.roomTransitionedToInvalidStateForPresenceOperation(cause:)``.
47+
/// - CHA-PR3e, CHA-PR10e, CHA-PR6d, CHA-T2d: If the room is in the ATTACHED status, it returns immediately.
48+
/// - CHA-PR3h, CHA-PR10h, CHA-PR6h, CHA-T2g: If the room is in any other status, it throws an `ARTErrorInfo` derived from ``ChatError.presenceOperationRequiresRoomAttach(feature:)``.
5049
///
5150
/// - Parameters:
5251
/// - requester: The room feature that wishes to perform a presence operation. This is only used for customising the message of the thrown error.

Sources/AblyChat/RoomLifecycleManager.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,17 +1225,14 @@ internal actor DefaultRoomLifecycleManager<Contributor: RoomLifecycleContributor
12251225
// TODO: decide what to do if nextRoomStatusChange is nil; I believe that this will happen if the current Task is cancelled. For now, will just treat it as an invalid status change. Handle it properly in https://github.com/ably-labs/ably-chat-swift/issues/29
12261226
if nextRoomStatusChange?.current != .attached {
12271227
// CHA-RL9c
1228-
throw .init(chatError: .roomInInvalidState(cause: nextRoomStatusChange?.current.error))
1228+
throw .init(chatError: .roomTransitionedToInvalidStateForPresenceOperation(cause: nextRoomStatusChange?.current.error))
12291229
}
12301230
case .attached:
1231-
// CHA-PR3e, CHA-PR11e, CHA-PR6d, CHA-T2d
1231+
// CHA-PR3e, CHA-PR10e, CHA-PR6d, CHA-T2d
12321232
break
1233-
case .detached:
1234-
// CHA-PR3f, CHA-PR11f, CHA-PR6e, CHA-T2e
1235-
throw .init(chatError: .presenceOperationRequiresRoomAttach(feature: requester))
12361233
default:
1237-
// CHA-PR3g, CHA-PR11g, CHA-PR6f, CHA-T2f
1238-
throw .init(chatError: .presenceOperationDisallowedForCurrentRoomStatus(feature: requester))
1234+
// CHA-PR3h, CHA-PR10h, CHA-PR6h, CHA-T2g
1235+
throw .init(chatError: .presenceOperationRequiresRoomAttach(feature: requester))
12391236
}
12401237
}
12411238

0 commit comments

Comments
 (0)