Skip to content

Commit

Permalink
[WIP] Implement room lifecycle spec
Browse files Browse the repository at this point in the history
This is based on [1] at aa7455d. It’s generated some questions, which
I’ve asked on that PR.

I started implementing this as part of #19, before realising that
implementing the spec is not the aim of that task. So, putting this work
on hold until we pick it up again in #28.

So far, only the ATTACH operation is implemented.

[1] ably/specification#200

I have since updated with error names @ bcb7390

other stuff done since first version of this commit:

- start implementing the low-hanging fruit of DETACH

all the infrastructure in place for feature-specific errors

used generic type for contributor so that i can access the mock-specific
properties of the contributor's channel in the tests without having to
create channels and then create contributors from those

wip detachment errors

further with detachment errors

wip trying to see if there aren't 2 status updates

Revert "wip trying to see if there aren't 2 status updates"

This reverts commit 63dd9b9.

Doesn’t work.

implement CHA-RL2h2

wip channel detach retry

a few updates to older bits

implement more of RELEASE

comment

wip

done RELEASE
  • Loading branch information
lawrence-forooghian committed Sep 17, 2024
1 parent 9014b0c commit 280fd4a
Show file tree
Hide file tree
Showing 10 changed files with 1,175 additions and 4 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ To check formatting and code quality, run `swift run BuildTool lint`. Run with `
- We should aim to make it easy for consumers of the SDK to be able to mock out the SDK in the tests for their own code. A couple of things that will aid with this:
- Describe the SDK’s functionality via protocols (when doing so would still be sufficiently idiomatic to Swift).
- When defining a `struct` that is emitted by the public API of the library, make sure to define a public memberwise initializer so that users can create one to be emitted by their mocks. (There is no way to make Swift’s autogenerated memberwise initializer public, so you will need to write one yourself. In Xcode, you can do this by clicking at the start of the type declaration and doing Editor → Refactor → Generate Memberwise Initializer.)
- TODO something about adding spec points in code and tests

## Building for Swift 6

Expand Down
95 changes: 93 additions & 2 deletions Sources/AblyChat/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,25 @@ public enum ErrorCode: Int {
/// TODO this code is a guess, revisit in https://github.com/ably-labs/ably-chat-swift/issues/32
case inconsistentRoomOptions = 1

// TODO: describe, and code is a guess
case channelAttachResultedInSuspended = 2
case channelAttachResultedInFailed = 3

case roomInFailedState = 102_101 // CHA-RL2d
case roomIsReleasing = 102_102 // CHA-RL1b, CHA-RL2b
case roomIsReleased = 102_103 // CHA-RL1c, CHA-RL2c

case messagesDetachmentFailed = 102_050
case presenceDetachmentFailed = 102_051
case reactionsDetachmentFailed = 102_052
case occupancyDetachmentFailed = 102_053
case typingDetachmentFailed = 102_054

/// The ``ARTErrorInfo.statusCode`` that should be returned for this error.
internal var statusCode: Int {
// TODO: These are currently a guess, revisit in https://github.com/ably-labs/ably-chat-swift/issues/32
switch self {
case .inconsistentRoomOptions:
case .inconsistentRoomOptions, .channelAttachResultedInSuspended, .channelAttachResultedInFailed, .roomInFailedState, .roomIsReleasing, .roomIsReleased, .messagesDetachmentFailed, .presenceDetachmentFailed, .reactionsDetachmentFailed, .occupancyDetachmentFailed, .typingDetachmentFailed:
400
}
}
Expand All @@ -29,16 +43,45 @@ public enum ErrorCode: Int {
/**
The errors thrown by the Chat SDK.

This type exists in addition to ``ErrorCode`` to allow us to attach metadata which can be incorporated into the error’s `localizedDescription`.
This type exists in addition to ``ErrorCode`` to allow us to attach metadata which can be incorporated into the error’s `localizedDescription` and `cause`.
*/
internal enum ChatError {
case inconsistentRoomOptions(requested: RoomOptions, existing: RoomOptions)
case channelAttachResultedInSuspended(underlyingError: ARTErrorInfo)
case channelAttachResultedInFailed(underlyingError: ARTErrorInfo)
case roomInFailedState
case roomIsReleasing
case roomIsReleased
case detachmentFailed(feature: RoomFeature, underlyingError: ARTErrorInfo)

/// The ``ARTErrorInfo.code`` that should be returned for this error.
internal var code: ErrorCode {
switch self {
case .inconsistentRoomOptions:
.inconsistentRoomOptions
case .channelAttachResultedInSuspended:
.channelAttachResultedInSuspended
case .channelAttachResultedInFailed:
.channelAttachResultedInFailed
case .roomInFailedState:
.roomInFailedState
case .roomIsReleasing:
.roomIsReleasing
case .roomIsReleased:
.roomIsReleased
case let .detachmentFailed(feature, _):
switch feature {
case .messages:
.messagesDetachmentFailed
case .occupancy:
.occupancyDetachmentFailed
case .presence:
.presenceDetachmentFailed
case .reactions:
.reactionsDetachmentFailed
case .typing:
.typingDetachmentFailed
}
}
}

Expand All @@ -47,6 +90,49 @@ internal enum ChatError {
switch self {
case let .inconsistentRoomOptions(requested, existing):
"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:). Requested options: \(requested), existing options: \(existing)"
case .channelAttachResultedInSuspended:
"TODO"
case .channelAttachResultedInFailed:
"TODO"
case .roomInFailedState:
"Cannot perform operation because the room is in a failed state."
case .roomIsReleasing:
"Cannot perform operation because the room is in a releasing state."
case .roomIsReleased:
"Cannot perform operation because the room is in a released state."
case let .detachmentFailed(feature, _):
{
let description = switch feature {
case .messages:
"messages"
case .occupancy:
"occupancy"
case .presence:
"presence"
case .reactions:
"reactions"
case .typing:
"typing"
}
return "The \(description) feature failed to detach."
}()
}
}

/// The ``ARTErrorInfo.cause`` that should be returned for this error.
internal var cause: ARTErrorInfo? {
switch self {
case let .channelAttachResultedInSuspended(underlyingError):
underlyingError
case let .channelAttachResultedInFailed(underlyingError):
underlyingError
case let .detachmentFailed(_, underlyingError):
underlyingError
case .inconsistentRoomOptions,
.roomInFailedState,
.roomIsReleasing,
.roomIsReleased:
nil
}
}
}
Expand All @@ -58,6 +144,11 @@ internal extension ARTErrorInfo {
userInfo["ARTErrorInfoStatusCode"] = chatError.code.statusCode
userInfo[NSLocalizedDescriptionKey] = chatError.localizedDescription

// 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.
if let cause = chatError.cause {
userInfo[NSUnderlyingErrorKey] = cause
}

self.init(
domain: errorDomain,
code: chatError.code.rawValue,
Expand Down
8 changes: 8 additions & 0 deletions Sources/AblyChat/RoomFeature.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// The features offered by a chat room.
internal enum RoomFeature {
case messages
case presence
case reactions
case occupancy
case typing
}
Loading

0 comments on commit 280fd4a

Please sign in to comment.