Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ECO-5015] Rename public API for {room, connection} lifecycle and status #77

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Sources/AblyChat/Connection.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import Ably

public protocol Connection: AnyObject, Sendable {
var status: any ConnectionStatus { get }
var lifecycle: any ConnectionLifecycle { get }
}

public protocol ConnectionStatus: AnyObject, Sendable {
var current: ConnectionLifecycle { get }
public protocol ConnectionLifecycle: AnyObject, Sendable {
var status: ConnectionStatus { get }
// TODO: (https://github.com/ably-labs/ably-chat-swift/issues/12): consider how to avoid the need for an unwrap
var error: ARTErrorInfo? { get }
func onChange(bufferingPolicy: BufferingPolicy) -> Subscription<ConnectionStatusChange>
}

public enum ConnectionLifecycle: Sendable {
public enum ConnectionStatus: Sendable {
case initialized
case connecting
case connected
Expand All @@ -21,13 +21,13 @@ public enum ConnectionLifecycle: Sendable {
}

public struct ConnectionStatusChange: Sendable {
public var current: ConnectionLifecycle
public var previous: ConnectionLifecycle
public var current: ConnectionStatus
public var previous: ConnectionStatus
// TODO: (https://github.com/ably-labs/ably-chat-swift/issues/12): consider how to avoid the need for an unwrap
public var error: ARTErrorInfo?
public var retryIn: TimeInterval

public init(current: ConnectionLifecycle, previous: ConnectionLifecycle, error: ARTErrorInfo? = nil, retryIn: TimeInterval) {
public init(current: ConnectionStatus, previous: ConnectionStatus, error: ARTErrorInfo? = nil, retryIn: TimeInterval) {
self.current = current
self.previous = previous
self.error = error
Expand Down
14 changes: 7 additions & 7 deletions Sources/AblyChat/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public protocol Room: AnyObject, Sendable {
var typing: any Typing { get }
// To access this property if occupancy is not enabled for the room is a programmer error, and will lead to `fatalError` being called.
var occupancy: any Occupancy { get }
var status: any RoomStatus { get }
var lifecycle: any RoomLifecycle { get }
lawrence-forooghian marked this conversation as resolved.
Show resolved Hide resolved
func attach() async throws
func detach() async throws
var options: RoomOptions { get }
Expand All @@ -30,15 +30,15 @@ internal actor DefaultRoom: Room {
}
#endif

private let _status: DefaultRoomStatus
private let _lifecycle: DefaultRoomLifecycle
private let logger: InternalLogger

internal init(realtime: RealtimeClient, roomID: String, options: RoomOptions, logger: InternalLogger) {
self.realtime = realtime
self.roomID = roomID
self.options = options
self.logger = logger
_status = .init(logger: logger)
_lifecycle = .init(logger: logger)
}

public nonisolated var messages: any Messages {
Expand All @@ -61,8 +61,8 @@ internal actor DefaultRoom: Room {
fatalError("Not yet implemented")
}

internal nonisolated var status: any RoomStatus {
_status
internal nonisolated var lifecycle: any RoomLifecycle {
_lifecycle
}

/// Fetches the channels that contribute to this room.
Expand All @@ -85,7 +85,7 @@ internal actor DefaultRoom: Room {
throw error
}
}
await _status.transition(to: .attached)
await _lifecycle.transition(to: .attached)
lawrence-forooghian marked this conversation as resolved.
Show resolved Hide resolved
}

public func detach() async throws {
Expand All @@ -97,6 +97,6 @@ internal actor DefaultRoom: Room {
throw error
}
}
await _status.transition(to: .detached)
await _lifecycle.transition(to: .detached)
lawrence-forooghian marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Ably

public protocol RoomStatus: AnyObject, Sendable {
var current: RoomLifecycle { get async }
public protocol RoomLifecycle: AnyObject, Sendable {
var status: RoomStatus { get async }
// TODO: (https://github.com/ably-labs/ably-chat-swift/issues/12): consider how to avoid the need for an unwrap
var error: ARTErrorInfo? { get async }
func onChange(bufferingPolicy: BufferingPolicy) async -> Subscription<RoomStatusChange>
}

public enum RoomLifecycle: Sendable {
public enum RoomStatus: Sendable {
case initialized
case attaching
case attached
Expand All @@ -20,20 +20,20 @@ public enum RoomLifecycle: Sendable {
}

public struct RoomStatusChange: Sendable {
public var current: RoomLifecycle
public var previous: RoomLifecycle
public var current: RoomStatus
public var previous: RoomStatus
// TODO: (https://github.com/ably-labs/ably-chat-swift/issues/12): consider how to avoid the need for an unwrap
public var error: ARTErrorInfo?

public init(current: RoomLifecycle, previous: RoomLifecycle, error: ARTErrorInfo? = nil) {
public init(current: RoomStatus, previous: RoomStatus, error: ARTErrorInfo? = nil) {
self.current = current
self.previous = previous
self.error = error
}
}

internal actor DefaultRoomStatus: RoomStatus {
internal private(set) var current: RoomLifecycle = .initialized
internal actor DefaultRoomLifecycle: RoomLifecycle {
internal private(set) var status: RoomStatus = .initialized
// TODO: populate this (https://github.com/ably-labs/ably-chat-swift/issues/28)
internal private(set) var error: ARTErrorInfo?

Expand All @@ -52,11 +52,11 @@ internal actor DefaultRoomStatus: RoomStatus {
return subscription
}

/// Sets ``current`` to the given state, and emits a status change to all subscribers added via ``onChange(bufferingPolicy:)``.
internal func transition(to newState: RoomLifecycle) {
logger.log(message: "Transitioning to \(newState)", level: .debug)
let statusChange = RoomStatusChange(current: newState, previous: current)
current = newState
/// Sets ``status`` to the given status, and emits a status change to all subscribers added via ``onChange(bufferingPolicy:)``.
internal func transition(to newStatus: RoomStatus) {
logger.log(message: "Transitioning to \(newStatus)", level: .debug)
let statusChange = RoomStatusChange(current: newStatus, previous: status)
status = newStatus
for subscription in subscriptions {
subscription.emit(statusChange)
}
Expand Down
32 changes: 16 additions & 16 deletions Sources/AblyChat/RoomLifecycleManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {
internal var channel: Channel
}

internal private(set) var current: RoomLifecycle
internal private(set) var status: RoomStatus
internal private(set) var error: ARTErrorInfo?

private let logger: InternalLogger
Expand All @@ -35,7 +35,7 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {
clock: SimpleClock
) {
self.init(
current: nil,
status: nil,
contributors: contributors,
logger: logger,
clock: clock
Expand All @@ -44,13 +44,13 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {

#if DEBUG
internal init(
testsOnly_current current: RoomLifecycle? = nil,
testsOnly_status status: RoomStatus? = nil,
contributors: [Contributor],
logger: InternalLogger,
clock: SimpleClock
) {
self.init(
current: current,
status: status,
contributors: contributors,
logger: logger,
clock: clock
Expand All @@ -59,12 +59,12 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {
#endif

private init(
current: RoomLifecycle?,
status: RoomStatus?,
contributors: [Contributor],
logger: InternalLogger,
clock: SimpleClock
) {
self.current = current ?? .initialized
self.status = status ?? .initialized
self.contributors = contributors
self.logger = logger
self.clock = clock
Expand All @@ -79,13 +79,13 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {
return subscription
}

/// Updates ``current`` and ``error`` and emits a status change event.
private func changeStatus(to new: RoomLifecycle, error: ARTErrorInfo? = nil) {
logger.log(message: "Transitioning from \(current) to \(new), error \(String(describing: error))", level: .info)
let previous = current
current = new
/// Updates ``status`` and ``error`` and emits a status change event.
private func changeStatus(to new: RoomStatus, error: ARTErrorInfo? = nil) {
logger.log(message: "Transitioning from \(status) to \(new), error \(String(describing: error))", level: .info)
let previous = status
status = new
self.error = error
let statusChange = RoomStatusChange(current: current, previous: previous, error: error)
let statusChange = RoomStatusChange(current: status, previous: previous, error: error)
emitStatusChange(statusChange)
}

Expand All @@ -97,7 +97,7 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {

/// Implements CHA-RL1’s `ATTACH` operation.
internal func performAttachOperation() async throws {
switch current {
switch status {
case .attached:
// CHA-RL1a
return
Expand Down Expand Up @@ -171,7 +171,7 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {

/// Implements CHA-RL2’s DETACH operation.
internal func performDetachOperation() async throws {
switch current {
switch status {
case .detached:
// CHA-RL2a
return
Expand Down Expand Up @@ -217,7 +217,7 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {
}

// This check is CHA-RL2h2
if current != .failed {
if status != .failed {
changeStatus(to: .failed, error: error)
}
default:
Expand Down Expand Up @@ -250,7 +250,7 @@ internal actor RoomLifecycleManager<Channel: RoomLifecycleContributorChannel> {

/// Implementes CHA-RL3’s RELEASE operation.
internal func performReleaseOperation() async {
switch current {
switch status {
case .released:
// CHA-RL3a
return
Expand Down
41 changes: 41 additions & 0 deletions Tests/AblyChatTests/DefaultRoomLifecycleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@testable import AblyChat
import Testing

struct DefaultRoomLifecycleTests {
@Test
func status_startsAsInitialized() async {
let lifecycle = DefaultRoomLifecycle(logger: TestLogger())
#expect(await lifecycle.status == .initialized)
}

@Test()
func error_startsAsNil() async {
let lifecycle = DefaultRoomLifecycle(logger: TestLogger())
#expect(await lifecycle.error == nil)
}

@Test
func transition() async throws {
// Given: A DefaultRoomLifecycle
let lifecycle = DefaultRoomLifecycle(logger: TestLogger())
let originalStatus = await lifecycle.status
let newStatus = RoomStatus.attached // arbitrary

let subscription1 = await lifecycle.onChange(bufferingPolicy: .unbounded)
let subscription2 = await lifecycle.onChange(bufferingPolicy: .unbounded)

async let statusChange1 = subscription1.first { $0.current == newStatus }
async let statusChange2 = subscription2.first { $0.current == newStatus }

// When: transition(to:) is called
await lifecycle.transition(to: newStatus)

// Then: It emits a status change to all subscribers added via onChange(bufferingPolicy:), and updates its `status` property to the new status
for statusChange in try await [#require(statusChange1), #require(statusChange2)] {
#expect(statusChange.previous == originalStatus)
#expect(statusChange.current == newStatus)
}

#expect(await lifecycle.status == .attached)
}
}
41 changes: 0 additions & 41 deletions Tests/AblyChatTests/DefaultRoomStatusTests.swift

This file was deleted.

8 changes: 4 additions & 4 deletions Tests/AblyChatTests/DefaultRoomTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct DefaultRoomTests {
let realtime = MockRealtime.create(channels: channels)
let room = DefaultRoom(realtime: realtime, roomID: "basketball", options: .init(), logger: TestLogger())

let subscription = await room.status.onChange(bufferingPolicy: .unbounded)
let subscription = await room.lifecycle.onChange(bufferingPolicy: .unbounded)
async let attachedStatusChange = subscription.first { $0.current == .attached }

// When: `attach` is called on the room
Expand All @@ -30,7 +30,7 @@ struct DefaultRoomTests {
#expect(channel.attachCallCounter.isNonZero)
}

#expect(await room.status.current == .attached)
#expect(await room.lifecycle.status == .attached)
#expect(try #require(await attachedStatusChange).current == .attached)
}

Expand Down Expand Up @@ -81,7 +81,7 @@ struct DefaultRoomTests {
let realtime = MockRealtime.create(channels: channels)
let room = DefaultRoom(realtime: realtime, roomID: "basketball", options: .init(), logger: TestLogger())

let subscription = await room.status.onChange(bufferingPolicy: .unbounded)
let subscription = await room.lifecycle.onChange(bufferingPolicy: .unbounded)
async let detachedStatusChange = subscription.first { $0.current == .detached }

// When: `detach` is called on the room
Expand All @@ -92,7 +92,7 @@ struct DefaultRoomTests {
#expect(channel.detachCallCounter.isNonZero)
}

#expect(await room.status.current == .detached)
#expect(await room.lifecycle.status == .detached)
#expect(try #require(await detachedStatusChange).current == .detached)
}

Expand Down
Loading