mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +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>)?
|
var handleMessageClosure: ((String) async -> Result<Bool, ElementCallWidgetDriverError>)?
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
||||||
handleMessageCallsCount += 1
|
handleMessageCallsCount += 1
|
||||||
handleMessageReceivedMessage = message
|
handleMessageReceivedMessage = message
|
||||||
|
|||||||
@@ -94,3 +94,23 @@ enum CallScreenJavaScriptMessageName: String, CaseIterable {
|
|||||||
allCases.map(\.postMessageScript).joined(separator: "\n")
|
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()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CancellableTask
|
||||||
|
private var timeoutTask: Task<Void, Never>?
|
||||||
|
|
||||||
/// Designated initialiser
|
/// Designated initialiser
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - elementCallService: service responsible for setting up CallKit
|
/// - elementCallService: service responsible for setting up CallKit
|
||||||
@@ -109,6 +112,17 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
setupCall()
|
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) {
|
override func process(viewAction: CallScreenViewAction) {
|
||||||
@@ -129,7 +143,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
|||||||
case .outputDeviceSelected(deviceID: let deviceID):
|
case .outputDeviceSelected(deviceID: let deviceID):
|
||||||
handleOutputDeviceSelected(deviceID: deviceID)
|
handleOutputDeviceSelected(deviceID: deviceID)
|
||||||
case .widgetAction(let message):
|
case .widgetAction(let message):
|
||||||
Task { await widgetDriver.handleMessage(message) }
|
Task { await handleWidgetAction(message: message) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +158,16 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
|||||||
|
|
||||||
// MARK: - Private
|
// 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() {
|
private func setupCall() {
|
||||||
switch configuration.kind {
|
switch configuration.kind {
|
||||||
case .genericCallLink(let url):
|
case .genericCallLink(let url):
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ class ElementCallWidgetDriver: WidgetCapabilitiesProvider, ElementCallWidgetDriv
|
|||||||
return .success(url)
|
return .success(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
||||||
guard let widgetDriver else {
|
guard let widgetDriver else {
|
||||||
return .failure(.driverNotSetup)
|
return .failure(.driverNotSetup)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ protocol ElementCallWidgetDriverProtocol {
|
|||||||
analyticsConfiguration: ElementCallAnalyticsConfiguration?) async -> Result<URL, ElementCallWidgetDriverError>
|
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.
|
/// 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>
|
func handleMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user