Skip to content

Commit

Permalink
Simplify error type (livekit#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
hiroshihorie committed Dec 17, 2023
1 parent 5bd432c commit 66bd743
Show file tree
Hide file tree
Showing 27 changed files with 243 additions and 391 deletions.
4 changes: 2 additions & 2 deletions Sources/LiveKit/Core/DataChannelPairActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ actor DataChannelPairActor: NSObject, Loggable {

public func send(userPacket: Livekit_UserPacket, reliability: Reliability) throws {
guard isOpen else {
throw InternalError.state(message: "Data channel is not open")
throw LiveKitError(.invalidState, message: "Data channel is not open")
}

let packet = Livekit_DataPacket.with {
Expand All @@ -89,7 +89,7 @@ actor DataChannelPairActor: NSObject, Loggable {

let channel = (reliability == .reliable) ? _reliableChannel : _lossyChannel
guard let sendDataResult = channel?.sendData(rtcData), sendDataResult else {
throw InternalError.state(message: "sendData failed")
throw LiveKitError(.invalidState, message: "sendData failed")
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/Core/Engine+SignalClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ extension Engine: SignalClientDelegate {
// connectionState did update
if state.connectionState != oldState.connectionState,
// did disconnect
case let .disconnected(reason) = state.connectionState,
case .disconnected = state.connectionState,
// only attempt re-connect if disconnected(reason: network)
case .networkError = reason,
case .network = state.disconnectError?.type,
// engine is currently connected state
case .connected = _state.connectionState
{
Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/Core/Engine+TransportDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extension Engine: TransportDelegate {
publisherTransportConnectedCompleter.resume(returning: ())
}

if _state.connectionState.isConnected {
if _state.connectionState == .connected {
// Attempt re-connect if primary or publisher transport failed
if transport.isPrimary || (_state.hasPublished && transport.target == .publisher), [.disconnected, .failed].contains(pcState) {
log("[reconnect] starting, reason: transport disconnected or failed")
Expand All @@ -56,7 +56,7 @@ extension Engine: TransportDelegate {
// execute block when connected
execute(when: { state, _ in state.connectionState == .connected },
// always remove this block when disconnected
removeWhen: { state, _ in state.connectionState == .disconnected() })
removeWhen: { state, _ in state.connectionState == .disconnected })
{ [weak self] in
guard let self else { return }
self.notify { $0.engine(self, didAddTrack: track, rtpReceiver: rtpReceiver, streams: streams) }
Expand Down
40 changes: 22 additions & 18 deletions Sources/LiveKit/Core/Engine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class Engine: MulticastDelegate<EngineDelegate> {
// preferred reconnect mode which will be used only for next attempt
var nextPreferredReconnectMode: ReconnectMode?
var reconnectMode: ReconnectMode?
var connectionState: ConnectionState = .disconnected()
var connectionState: ConnectionState = .disconnected
var disconnectError: LiveKitError?
var connectStopwatch = Stopwatch(label: "connect")
var hasPublished: Bool = false
}
Expand Down Expand Up @@ -159,20 +160,22 @@ class Engine: MulticastDelegate<EngineDelegate> {
$0.connectionState = .connected
}

} catch is CancellationError {
// Cancelled by .user
try await cleanUp(reason: .user)
} catch {
try await cleanUp(reason: .networkError(error))
try await cleanUp(withError: error)
// Re-throw error
throw error
}
}

// cleanUp (reset) both Room & Engine's state
func cleanUp(reason: DisconnectReason? = nil, isFullReconnect: Bool = false) async throws {
func cleanUp(withError disconnectError: Error? = nil,
isFullReconnect: Bool = false) async throws
{
// This should never happen since Engine is owned by Room
let room = try requireRoom()
// Call Room's cleanUp
await room.cleanUp(reason: reason, isFullReconnect: isFullReconnect)
await room.cleanUp(withError: disconnectError,
isFullReconnect: isFullReconnect)
}

// Resets state of transports
Expand Down Expand Up @@ -362,18 +365,18 @@ extension Engine {

func startReconnect() async throws {
guard case .connected = _state.connectionState else {
log("[reconnect] must be called with connected state", .warning)
throw EngineError.state(message: "Must be called with connected state")
log("[Reconnect] Must be called with connected state", .error)
throw LiveKitError(.invalidState)
}

guard let url = _state.url, let token = _state.token else {
log("[reconnect] url or token is nil", .warning)
throw EngineError.state(message: "url or token is nil")
log("[Reconnect] Url or token is nil", .error)
throw LiveKitError(.invalidState)
}

guard subscriber != nil, publisher != nil else {
log("[reconnect] publisher or subscriber is nil", .warning)
throw EngineError.state(message: "Publisher or Subscriber is nil")
log("[Reconnect] Publisher or subscriber is nil", .error)
throw LiveKitError(.invalidState)
}

// quick connect sequence, does not update connection state
Expand Down Expand Up @@ -420,7 +423,8 @@ extension Engine {
guard let url = _state.url,
let token = _state.token
else {
throw EngineError.state(message: "url or token is nil")
log("[Reconnect] Url or token is nil")
throw LiveKitError(.invalidState)
}

try await fullConnectSequence(url, token)
Expand Down Expand Up @@ -461,12 +465,12 @@ extension Engine {
do {
try await retryingTask.value
// Re-connect sequence successful
log("[reconnect] sequence completed")
log("[reconnect] Sequence completed")
_state.mutate { $0.connectionState = .connected }
} catch {
log("[Reconnect] Sequence failed with error: \(error)")
// Finally disconnect if all attempts fail
try await cleanUp(reason: .networkError(error))
try await cleanUp(withError: error)
}
}
}
Expand Down Expand Up @@ -517,12 +521,12 @@ extension Engine {

extension Engine {
func requireRoom() throws -> Room {
guard let room = _room else { throw EngineError.state(message: "Room is nil") }
guard let room = _room else { throw LiveKitError(.invalidState, message: "Room is nil") }
return room
}

func requirePublisher() throws -> Transport {
guard let publisher else { throw EngineError.state(message: "Publisher is nil") }
guard let publisher else { throw LiveKitError(.invalidState, message: "Publisher is nil") }
return publisher
}
}
Expand Down
16 changes: 5 additions & 11 deletions Sources/LiveKit/Core/Room+EngineDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,23 @@ extension Room: EngineDelegate {
}

delegates.notify(label: { "room.didUpdate connectionState: \(state.connectionState) oldValue: \(oldState.connectionState)" }) {
// Objective-C support
$0.room?(self, didUpdate: state.connectionState.toObjCType(), oldValue: oldState.connectionState.toObjCType())
// Swift only
if let delegateSwift = $0 as? RoomDelegate {
delegateSwift.room(self, didUpdate: state.connectionState, oldValue: oldState.connectionState)
}
$0.room?(self, didUpdate: state.connectionState, oldValue: oldState.connectionState)
}

// Legacy connection delegates
if case .connected = state.connectionState {
let didReconnect = oldState.connectionState == .reconnecting
delegates.notify { $0.room?(self, didConnect: didReconnect) }
} else if case let .disconnected(reason) = state.connectionState {
} else if case .disconnected = state.connectionState {
if case .connecting = oldState.connectionState {
let error = reason?.networkError ?? NetworkError.disconnected(message: "Did fail to connect", rawError: nil)
delegates.notify { $0.room?(self, didFailToConnect: error) }
delegates.notify { $0.room?(self, didFailToConnect: oldState.disconnectError) }
} else {
delegates.notify { $0.room?(self, didDisconnect: reason?.networkError) }
delegates.notify { $0.room?(self, didDisconnect: state.disconnectError) }
}
}
}

if state.connectionState.isReconnecting, state.reconnectMode == .full, oldState.reconnectMode != .full {
if state.connectionState == .reconnecting, state.reconnectMode == .full, oldState.reconnectMode != .full {
Task {
// Started full reconnect
await cleanUpParticipants(notify: true)
Expand Down
16 changes: 2 additions & 14 deletions Sources/LiveKit/Core/Room+MulticastDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
import Foundation

extension Room: MulticastDelegateProtocol {
@objc(addDelegate:)
public func add(delegate: RoomDelegate) {
delegates.add(delegate: delegate)
}

@objc(removeDelegate:)
public func remove(delegate: RoomDelegate) {
delegates.remove(delegate: delegate)
}
Expand All @@ -29,18 +31,4 @@ extension Room: MulticastDelegateProtocol {
public func removeAllDelegates() {
delegates.removeAllDelegates()
}

/// Only for Objective-C.
@objc(addDelegate:)
@available(swift, obsoleted: 1.0)
public func addObjC(delegate: RoomDelegateObjC) {
delegates.add(delegate: delegate)
}

/// Only for Objective-C.
@objc(removeDelegate:)
@available(swift, obsoleted: 1.0)
public func removeObjC(delegate: RoomDelegateObjC) {
delegates.remove(delegate: delegate)
}
}
2 changes: 1 addition & 1 deletion Sources/LiveKit/Core/Room+SignalClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ extension Room: SignalClientDelegate {
} else {
Task {
// Server indicates it's not recoverable
await cleanUp(reason: reason.toLKType())
await cleanUp(withError: LiveKitError.from(reason: reason))
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions Sources/LiveKit/Core/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Foundation
public class Room: NSObject, ObservableObject, Loggable {
// MARK: - MulticastDelegate

public let delegates = MulticastDelegate<RoomDelegateObjC>()
public let delegates = MulticastDelegate<RoomDelegate>()

// MARK: - Public

Expand Down Expand Up @@ -76,12 +76,11 @@ public class Room: NSObject, ObservableObject, Loggable {
public var token: String? { engine._state.token }

/// Current ``ConnectionState`` of the ``Room``.
@objc
public var connectionState: ConnectionState { engine._state.connectionState }

/// Only for Objective-C.
@objc(connectionState)
@available(swift, obsoleted: 1.0)
public var connectionStateObjC: ConnectionStateObjC { engine._state.connectionState.toObjCType() }
@objc
public var disconnectError: LiveKitError? { engine._state.disconnectError }

public var connectStopwatch: Stopwatch { engine._state.connectStopwatch }

Expand Down Expand Up @@ -141,7 +140,7 @@ public class Room: NSObject, ObservableObject, Loggable {
}

@objc
public init(delegate: RoomDelegateObjC? = nil,
public init(delegate: RoomDelegate? = nil,
connectOptions: ConnectOptions? = nil,
roomOptions: RoomOptions? = nil)
{
Expand Down Expand Up @@ -252,18 +251,18 @@ public class Room: NSObject, ObservableObject, Loggable {
log("Failed to send leave with error: \(error)")
}

await cleanUp(reason: .user)
await cleanUp()
}
}

// MARK: - Internal

extension Room {
// Resets state of Room
func cleanUp(reason: DisconnectReason? = nil,
func cleanUp(withError disconnectError: Error? = nil,
isFullReconnect: Bool = false) async
{
log("Reason: \(String(describing: reason))")
log("withError: \(String(describing: disconnectError))")

// Start Engine cleanUp sequence

Expand All @@ -281,11 +280,12 @@ extension Room {
connectionState: $0.connectionState
) : Engine.State(
connectOptions: $0.connectOptions,
connectionState: .disconnected(reason: reason)
connectionState: .disconnected,
disconnectError: LiveKitError.from(error: disconnectError)
)
}

await engine.signalClient.cleanUp(reason: reason)
await engine.signalClient.cleanUp(withError: disconnectError)
await engine.cleanUpRTC()
await cleanUpParticipants()
// Reset state
Expand Down Expand Up @@ -315,7 +315,7 @@ extension Room {

func _onParticipantDidDisconnect(identity: Identity) async throws {
guard let participant = _state.mutate({ $0.remoteParticipants.removeValue(forKey: identity) }) else {
throw EngineError.state(message: "Participant not found for \(identity)")
throw LiveKitError(.invalidState, message: "Participant not found for \(identity)")
}

await participant.cleanUp(notify: true)
Expand Down
Loading

0 comments on commit 66bd743

Please sign in to comment.