Skip to content

Commit 38fafd4

Browse files
committed
Change non spec errors:
- failedToResolveSubscriptionPointBecauseChannelSerialNotDefined: renamed since `channelSerial` checked first. Introduced error code used in JS - 102_110; - failedToResolveSubscriptionPointBecauseChannelFailedToAttach: changed error code to 102_112 (roomInInvalidState), JS doesn't throw anything and just waits for channel attach event. Proposed spec for throwing an error with 102_112 code; - noItemInResponse: changed error code to 404 and proposed spec for that; - failedToGetPaginatedResult: renamed and added full error info taken from realtime, JS also throws error with values from realtime. Am not sure what to do with `badRequest` here, probably it's fine to leave it (or `internalServerError` maybe?); - headersValueJSONDecodingError and jsonValueDecodingError are JSON parser errors and probably should stay with `badRequest`. Removed unused `MessagesError` enum. Proposed specs: ably/specification#401
1 parent ff4b8b4 commit 38fafd4

File tree

5 files changed

+58
-31
lines changed

5 files changed

+58
-31
lines changed

Sources/AblyChat/AblyCocoaExtensions/InternalAblyCocoaTypes.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,14 @@ internal protocol InternalHTTPPaginatedResponseProtocol: AnyObject, Sendable {
109109
var items: [JSONValue] { get }
110110
var hasNext: Bool { get }
111111
var isLast: Bool { get }
112-
var statusCode: Int { get }
113112

114113
func next() async throws(ErrorInfo) -> Self?
115114
func first() async throws(ErrorInfo) -> Self
115+
116+
var success: Bool { get }
117+
var statusCode: Int { get }
118+
var errorCode: Int { get }
119+
var errorMessage: String? { get }
116120
}
117121

118122
/// Converts a `@MainActor` callback into one that can be passed as a callback to ably-cocoa.
@@ -202,10 +206,22 @@ internal final class InternalHTTPPaginatedResponseAdapter: InternalHTTPPaginated
202206
underlying.isLast
203207
}
204208

209+
internal var success: Bool {
210+
underlying.success
211+
}
212+
205213
internal var statusCode: Int {
206214
underlying.statusCode
207215
}
208216

217+
internal var errorCode: Int {
218+
underlying.errorCode
219+
}
220+
221+
internal var errorMessage: String? {
222+
underlying.errorMessage
223+
}
224+
209225
internal func next() async throws(ErrorInfo) -> InternalHTTPPaginatedResponseAdapter? {
210226
do {
211227
return try await withCheckedContinuation { (continuation: CheckedContinuation<Result<InternalHTTPPaginatedResponseAdapter?, ARTErrorInfo>, _>) in

Sources/AblyChat/DefaultMessages.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ internal final class DefaultMessages<Realtime: InternalRealtimeClientProtocol>:
159159
continuation.resume(returning: .success(subscriptionPoint))
160160
} else {
161161
logger.log(message: "Channel is attached, but attachSerial is not defined", level: .error)
162-
continuation.resume(returning: .failure(InternalError.failedToResolveSubscriptionPointBecauseAttachSerialNotDefined.toErrorInfo()))
162+
continuation.resume(returning: .failure(InternalError.failedToResolveSubscriptionPointBecauseChannelSerialNotDefined.toErrorInfo()))
163163
}
164164
case .failed, .suspended:
165165
let error = InternalError.failedToResolveSubscriptionPointBecauseChannelFailedToAttach(cause: stateChange.reason)
@@ -171,8 +171,4 @@ internal final class DefaultMessages<Realtime: InternalRealtimeClientProtocol>:
171171
}
172172
}.get()
173173
}
174-
175-
internal enum MessagesError: Error {
176-
case noReferenceToSelf
177-
}
178174
}

Sources/AblyChat/InternalError.swift

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,25 +87,19 @@ internal enum InternalError {
8787
/// Error code is `badRequest` (this is our own error, which is not specified by the spec).
8888
case failedToResolveSubscriptionPointBecauseMessagesInstanceGone
8989

90-
/// Unable to fetch `historyBeforeSubscribe` because a channel in the `ATTACHED` state has violated our expectations by its `attachSerial` not being populated, so we cannot resolve its "subscription point" per CHA-M5b.
91-
///
92-
/// Error code is `badRequest` (this is not specified by the spec, which does not make it explicit that the SDK should throw an error in this scenario).
93-
case failedToResolveSubscriptionPointBecauseAttachSerialNotDefined
90+
/// Unable to fetch `historyBeforeSubscribe` because a channel in the `ATTACHED` state has violated our expectations by its `channelSerial` or `attachSerial` not being populated, so we cannot resolve its "subscription point" per CHA-M5b.
91+
case failedToResolveSubscriptionPointBecauseChannelSerialNotDefined
9492

9593
/// Unable to fetch `historyBeforeSubscribe` because whilst waiting for a channel to become attached per CHA-M5b in order to resolve its "subscription point".
96-
///
97-
/// Error code is `badRequest` (this is not specified by the spec, which does not make it explicit that the SDK should throw an error in this scenario).
9894
case failedToResolveSubscriptionPointBecauseChannelFailedToAttach(cause: ErrorInfo?)
9995

10096
/// Attempted to load a resource from the given `path`, expecting to get a single item back, but the returned `PaginatedResult` is empty.
101-
///
102-
/// Error code is `badRequest` (this is not specified by the spec, which does not make it explicit that the SDK should throw an error in this scenario).
10397
case noItemInResponse(path: String)
10498

10599
/// An ably-cocoa `ARTHTTPPaginatedResponse` was received with the given non-200 status code.
106100
///
107101
/// Error code is `badRequest` (this is not specified by the spec, which does not make it explicit that the SDK should throw an error in this scenario).
108-
case paginatedResultStatusCode(Int)
102+
case failedToGetPaginatedResult(cause: ErrorInfo?)
109103

110104
// Failed to decode a `HeadersValue` from a `JSONValue`.
111105
///
@@ -130,9 +124,11 @@ internal enum InternalError {
130124
internal enum ErrorCode: Int {
131125
case badRequest = 40000
132126
case invalidArgument = 40003
127+
case notFound = 40400
133128
case roomDiscontinuity = 102_100
134129
case roomReleasedBeforeOperationCompleted = 102_106
135130
case roomExistsWithDifferentOptions = 102_107
131+
case channelSerialNotDefined = 102_110
136132
case roomInInvalidState = 102_112
137133

138134
/// The ``ErrorInfo/statusCode`` that should be returned for this error.
@@ -145,7 +141,10 @@ internal enum InternalError {
145141
.roomInInvalidState,
146142
.roomExistsWithDifferentOptions:
147143
400
148-
case .roomDiscontinuity:
144+
case .notFound:
145+
404
146+
case .roomDiscontinuity,
147+
.channelSerialNotDefined:
149148
500
150149
}
151150
}
@@ -183,13 +182,13 @@ internal enum InternalError {
183182
.invalidArgument
184183
case .cannotApplyCreatedMessageEvent:
185184
.invalidArgument
186-
case .failedToResolveSubscriptionPointBecauseAttachSerialNotDefined:
187-
.badRequest
185+
case .failedToResolveSubscriptionPointBecauseChannelSerialNotDefined:
186+
.channelSerialNotDefined
188187
case .failedToResolveSubscriptionPointBecauseChannelFailedToAttach:
189-
.badRequest
188+
.roomInInvalidState
190189
case .noItemInResponse:
191-
.badRequest
192-
case .paginatedResultStatusCode:
190+
.notFound
191+
case .failedToGetPaginatedResult:
193192
.badRequest
194193
case .failedToResolveSubscriptionPointBecauseMessagesInstanceGone:
195194
.badRequest
@@ -286,9 +285,9 @@ internal enum InternalError {
286285
case .failedToResolveSubscriptionPointBecauseMessagesInstanceGone:
287286
op = "fetch message history from before subscription"
288287
reason = "Messages instance has been deallocated"
289-
case .failedToResolveSubscriptionPointBecauseAttachSerialNotDefined:
288+
case .failedToResolveSubscriptionPointBecauseChannelSerialNotDefined:
290289
op = "fetch message history from before subscription"
291-
reason = "channel is attached but attachSerial is not defined"
290+
reason = "channel is attached but channelSerial is not defined"
292291
case let .failedToResolveSubscriptionPointBecauseChannelFailedToAttach(cause):
293292
op = "fetch message history from before subscription"
294293
reason = "channel failed to attach: \(cause, default: "(nil cause)")"
@@ -301,9 +300,9 @@ internal enum InternalError {
301300
case let .noItemInResponse(path):
302301
op = "load resource"
303302
reason = "paginated result from path \(path) is empty"
304-
case let .paginatedResultStatusCode(statusCode):
303+
case let .failedToGetPaginatedResult(cause):
305304
op = "load resource"
306-
reason = "received status code \(statusCode)"
305+
reason = "reason: \(cause, default: "<no reason>")"
307306
case let .headersValueJSONDecodingError(error):
308307
op = "decode headers"
309308
switch error {
@@ -336,6 +335,8 @@ internal enum InternalError {
336335
cause
337336
case let .failedToResolveSubscriptionPointBecauseChannelFailedToAttach(cause):
338337
cause
338+
case let .failedToGetPaginatedResult(cause):
339+
cause
339340
case .jsonValueDecodingError,
340341
.headersValueJSONDecodingError,
341342
.roomExistsWithDifferentOptions,
@@ -344,15 +345,14 @@ internal enum InternalError {
344345
.presenceOperationRequiresRoomAttach,
345346
.cannotApplyCreatedMessageEvent,
346347
.unableDeleteReactionWithoutName,
347-
.failedToResolveSubscriptionPointBecauseAttachSerialNotDefined,
348+
.failedToResolveSubscriptionPointBecauseChannelSerialNotDefined,
348349
.roomInInvalidStateForAttach,
349350
.roomInInvalidStateForDetach,
350351
.cannotApplyMessageEventForDifferentMessage,
351352
.cannotApplyReactionSummaryEventForDifferentMessage,
352353
.sendMessageReactionEmptyMessageSerial,
353354
.deleteMessageReactionEmptyMessageSerial,
354355
.noItemInResponse,
355-
.paginatedResultStatusCode,
356356
.failedToResolveSubscriptionPointBecauseMessagesInstanceGone:
357357
nil
358358
}

Sources/AblyChat/PaginatedResult.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,14 @@ internal final class DefaultPaginatedResult<Underlying: InternalHTTPPaginatedRes
4141

4242
/// Convenience initializer that checks status code and decodes items from the response.
4343
internal convenience init(response: Underlying) throws(ErrorInfo) {
44-
// TODO: We've had this check since the start of the codebase, but it's not specified anywhere; rectify this in https://github.com/ably/ably-chat-swift/issues/453
45-
guard response.statusCode == 200 else {
46-
throw InternalError.paginatedResultStatusCode(response.statusCode).toErrorInfo()
44+
// (CHA-M6b) If the REST API returns an error, then the method must throw its `ErrorInfo` representation.
45+
guard response.success else {
46+
throw InternalError.failedToGetPaginatedResult(cause:
47+
.init(
48+
code: response.errorCode,
49+
message: response.errorMessage ?? "<no error message in response>",
50+
statusCode: response.statusCode,
51+
)).toErrorInfo()
4752
}
4853

4954
let items = try response.items.map { jsonValue throws(ErrorInfo) in

Tests/AblyChatTests/Mocks/MockHTTPPaginatedResponse.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,28 @@ import Ably
33

44
final class MockHTTPPaginatedResponse: InternalHTTPPaginatedResponseProtocol {
55
let items: [JSONValue]
6-
let statusCode: Int
76
let headers: [String: String]
87
let hasNext: Bool
98

9+
var success: Bool
10+
let statusCode: Int
11+
var errorCode: Int
12+
var errorMessage: String?
13+
1014
init(
1115
items: [[String: JSONValue]],
16+
success: Bool = true,
1217
statusCode: Int = 200,
18+
errorCode: Int = 0,
19+
errorMessage: String? = nil,
1320
headers: [String: String] = [:],
1421
hasNext: Bool = false,
1522
) {
1623
self.items = items.map { .object($0) }
24+
self.success = success
1725
self.statusCode = statusCode
26+
self.errorCode = errorCode
27+
self.errorMessage = errorMessage
1828
self.headers = headers
1929
self.hasNext = hasNext
2030
}

0 commit comments

Comments
 (0)