mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
EC Timeout if it doesn't respond after 30 seconds (#4237)
* basic implementation * using a decodable struct to interpret the widget message * small code refactor/improvement
This commit is contained in:
@@ -6357,6 +6357,7 @@ class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol, @unchecked S
|
||||
}
|
||||
var handleMessageClosure: ((String) async -> Result<Bool, ElementCallWidgetDriverError>)?
|
||||
|
||||
@discardableResult
|
||||
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
||||
handleMessageCallsCount += 1
|
||||
handleMessageReceivedMessage = message
|
||||
|
||||
@@ -94,3 +94,23 @@ enum CallScreenJavaScriptMessageName: String, CaseIterable {
|
||||
allCases.map(\.postMessageScript).joined(separator: "\n")
|
||||
}
|
||||
}
|
||||
|
||||
struct DecodedWidgetMessage: Decodable {
|
||||
private static let decoder = JSONDecoder()
|
||||
private static let joinAction = "io.element.join"
|
||||
private static let fromWidget = "fromWidget"
|
||||
|
||||
let action: String?
|
||||
let api: String?
|
||||
|
||||
static func decode(message: String) throws -> DecodedWidgetMessage? {
|
||||
guard let data = message.data(using: .utf8) else {
|
||||
return nil
|
||||
}
|
||||
return try decoder.decode(DecodedWidgetMessage.self, from: data)
|
||||
}
|
||||
|
||||
var hasJoined: Bool {
|
||||
action == Self.joinAction && api == Self.fromWidget
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
@CancellableTask
|
||||
private var timeoutTask: Task<Void, Never>?
|
||||
|
||||
/// Designated initialiser
|
||||
/// - Parameters:
|
||||
/// - elementCallService: service responsible for setting up CallKit
|
||||
@@ -109,6 +112,17 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
.store(in: &cancellables)
|
||||
|
||||
setupCall()
|
||||
|
||||
timeoutTask = Task { [weak self] in
|
||||
try? await Task.sleep(for: .seconds(30))
|
||||
guard !Task.isCancelled, let self else { return }
|
||||
MXLog.error("Failed to join Element Call: Timeout")
|
||||
state.bindings.alertInfo = .init(id: UUID(),
|
||||
title: L10n.commonError,
|
||||
message: L10n.errorUnknown,
|
||||
primaryButton: .init(title: L10n.actionDismiss) { [weak self] in self?.actionsSubject.send(.dismiss) })
|
||||
timeoutTask = nil
|
||||
}
|
||||
}
|
||||
|
||||
override func process(viewAction: CallScreenViewAction) {
|
||||
@@ -129,7 +143,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
case .outputDeviceSelected(deviceID: let deviceID):
|
||||
handleOutputDeviceSelected(deviceID: deviceID)
|
||||
case .widgetAction(let message):
|
||||
Task { await widgetDriver.handleMessage(message) }
|
||||
Task { await handleWidgetAction(message: message) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +157,16 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func handleWidgetAction(message: String) async {
|
||||
if timeoutTask != nil,
|
||||
let decodedMessage = try? DecodedWidgetMessage.decode(message: message),
|
||||
decodedMessage.hasJoined {
|
||||
// This means that the call room was joined succesfully, we can stop the timeout task
|
||||
timeoutTask = nil
|
||||
}
|
||||
await widgetDriver.handleMessage(message)
|
||||
}
|
||||
|
||||
private func setupCall() {
|
||||
switch configuration.kind {
|
||||
|
||||
@@ -163,6 +163,7 @@ class ElementCallWidgetDriver: WidgetCapabilitiesProvider, ElementCallWidgetDriv
|
||||
return .success(url)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
||||
guard let widgetDriver else {
|
||||
return .failure(.driverNotSetup)
|
||||
|
||||
@@ -36,6 +36,7 @@ protocol ElementCallWidgetDriverProtocol {
|
||||
analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result<URL, ElementCallWidgetDriverError>
|
||||
|
||||
/// Passes a message from the Widget to the SDK to handle, returning a Bool that represents whether or not the widget driver is still running.
|
||||
@discardableResult
|
||||
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user