Cleanup proxy errors

- proxy errors have been getting repetitive and not particularly useful
- differentiate between sdk and client errors and keep what provides value
- add error logs everywhere a failure occurs
This commit is contained in:
Stefan Ceriu
2024-04-04 10:17:55 +03:00
committed by Stefan Ceriu
parent 7aba0216bc
commit 77e28df1a8
16 changed files with 189 additions and 211 deletions

View File

@@ -24,6 +24,10 @@ struct ClientProxyMockConfiguration {
var roomDirectorySearchProxy: RoomDirectorySearchProxyProtocol?
}
enum ClientProxyMockError: Error {
case generic
}
extension ClientProxyMock {
convenience init(_ configuration: ClientProxyMockConfiguration) {
self.init()
@@ -53,25 +57,25 @@ extension ClientProxyMock {
isOnlyDeviceLeftReturnValue = .success(false)
accountURLActionReturnValue = "https://matrix.org/account"
directRoomForUserIDReturnValue = .failure(.failedRetrievingDirectRoom)
createDirectRoomWithExpectedRoomNameReturnValue = .failure(.failedCreatingRoom)
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue = .failure(.failedCreatingRoom)
uploadMediaReturnValue = .failure(.failedUploadingMedia(.unknown))
loadUserDisplayNameReturnValue = .failure(.failedRetrievingUserDisplayName)
setUserDisplayNameReturnValue = .failure(.failedSettingUserDisplayName)
loadUserAvatarURLReturnValue = .failure(.failedRetrievingUserAvatarURL)
setUserAvatarMediaReturnValue = .failure(.failedSettingUserAvatar)
removeUserAvatarReturnValue = .failure(.failedSettingUserAvatar)
directRoomForUserIDReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
createDirectRoomWithExpectedRoomNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
uploadMediaReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
loadUserDisplayNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
setUserDisplayNameReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
loadUserAvatarURLReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
setUserAvatarMediaReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
removeUserAvatarReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
logoutReturnValue = nil
searchUsersSearchTermLimitReturnValue = .success(.init(results: [], limited: false))
profileForReturnValue = .success(.init(userID: "@a:b.com", displayName: "Some user"))
sessionVerificationControllerProxyReturnValue = .failure(.failedRetrievingSessionVerificationController)
sessionVerificationControllerProxyReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
ignoreUserReturnValue = .success(())
unignoreUserReturnValue = .success(())
loadMediaContentForSourceThrowableError = ClientProxyError.failedLoadingMedia
loadMediaThumbnailForSourceWidthHeightThrowableError = ClientProxyError.failedLoadingMedia
loadMediaFileForSourceBodyThrowableError = ClientProxyError.failedLoadingMedia
loadMediaContentForSourceThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
loadMediaThumbnailForSourceWidthHeightThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
loadMediaFileForSourceBodyThrowableError = ClientProxyError.sdkError(ClientProxyMockError.generic)
secureBackupController = {
let secureBackupController = SecureBackupControllerMock()

View File

@@ -49,6 +49,10 @@ struct RoomProxyMockConfiguration {
var canUserJoinCall = true
}
enum RoomProxyMockError: Error {
case generic
}
extension RoomProxyMock {
@MainActor
convenience init(with configuration: RoomProxyMockConfiguration) {
@@ -83,7 +87,7 @@ extension RoomProxyMock {
setTopicClosure = { _ in .success(()) }
getMemberUserIDClosure = { [weak self] userID in
guard let member = self?.membersPublisher.value.first(where: { $0.userID == userID }) else {
return .failure(.failedRetrievingMember)
return .failure(.sdkError(RoomProxyMockError.generic))
}
return .success(member)
}
@@ -98,7 +102,7 @@ extension RoomProxyMock {
resetPowerLevelsReturnValue = .success(.mock)
suggestedRoleForClosure = { [weak self] userID in
guard case .success(let member) = await self?.getMember(userID: userID) else {
return .failure(.failedCheckingPermission)
return .failure(.sdkError(RoomProxyMockError.generic))
}
return .success(member.role)
}

View File

@@ -110,33 +110,6 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
.store(in: &cancellables)
}
private func displayError(_ type: ClientProxyError) {
switch type {
case .failedCreatingRoom:
state.bindings.alertInfo = AlertInfo(id: .failedCreatingRoom,
title: L10n.commonError,
message: L10n.screenStartChatErrorStartingChat)
case .failedSearchingUsers:
state.bindings.alertInfo = AlertInfo(id: .unknown)
case .failedUploadingMedia(let matrixError):
switch matrixError {
case .fileTooLarge:
// waiting for proper copy
state.bindings.alertInfo = AlertInfo(id: .fileTooLarge)
default:
state.bindings.alertInfo = AlertInfo(id: .failedUploadingMedia)
}
case .mediaFileError:
state.bindings.alertInfo = AlertInfo(id: .mediaFileError)
default:
break
}
}
private var clientProxy: ClientProxyProtocol {
userSession.clientProxy
}
private func createRoom() async {
defer {
hideLoadingIndicator()
@@ -145,27 +118,42 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
let avatarURL: URL?
if let media = createRoomParameters.avatarImageMedia {
switch await clientProxy.uploadMedia(media) {
switch await userSession.clientProxy.uploadMedia(media) {
case .success(let url):
avatarURL = URL(string: url)
case .failure(let error):
displayError(error)
switch error {
case .failedUploadingMedia(_, let errorCode):
switch errorCode {
case .fileTooLarge:
state.bindings.alertInfo = AlertInfo(id: .fileTooLarge)
default:
state.bindings.alertInfo = AlertInfo(id: .failedUploadingMedia)
}
case .invalidMedia:
state.bindings.alertInfo = AlertInfo(id: .mediaFileError)
default:
state.bindings.alertInfo = AlertInfo(id: .unknown)
}
return
}
} else {
avatarURL = nil
}
switch await clientProxy.createRoom(name: createRoomParameters.name,
topic: createRoomParameters.topic,
isRoomPrivate: createRoomParameters.isRoomPrivate,
userIDs: state.selectedUsers.map(\.userID),
avatarURL: avatarURL) {
switch await userSession.clientProxy.createRoom(name: createRoomParameters.name,
topic: createRoomParameters.topic,
isRoomPrivate: createRoomParameters.isRoomPrivate,
userIDs: state.selectedUsers.map(\.userID),
avatarURL: avatarURL) {
case .success(let roomId):
analytics.trackCreatedRoom(isDM: false)
actionsSubject.send(.openRoom(withIdentifier: roomId))
case .failure(let failure):
displayError(failure)
case .failure:
state.bindings.alertInfo = AlertInfo(id: .failedCreatingRoom,
title: L10n.commonError,
message: L10n.screenStartChatErrorStartingChat)
}
}

View File

@@ -119,7 +119,7 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true))
guard let roomProxy = await clientProxy.roomForIdentifier(roomID) else {
displayError(.failedAcceptingInvite)
displayError()
return
}
@@ -127,8 +127,8 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
case .success:
actionsSubject.send(.openRoom(withIdentifier: roomID))
analytics.trackJoinedRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace, activeMemberCount: UInt(roomProxy.activeMembersCount))
case .failure(let error):
displayError(error)
case .failure:
displayError()
}
}
}
@@ -143,20 +143,19 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true))
guard let roomProxy = await clientProxy.roomForIdentifier(roomID) else {
displayError(.failedRejectingInvite)
displayError()
return
}
let result = await roomProxy.rejectInvitation()
if case .failure(let error) = result {
displayError(error)
if case .failure = result {
displayError()
}
}
}
private func displayError(_ error: RoomProxyError) {
MXLog.error("Failed to accept/decline invite: \(error)")
private func displayError() {
state.bindings.alertInfo = .init(id: true,
title: L10n.commonError,
message: L10n.errorUnknown)

View File

@@ -48,9 +48,9 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe
Task {
// Can't use async let because the mocks aren't thread safe when calling the same method 🤦
state.canEditAvatar = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomAvatar) == .success(true)
state.canEditName = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomName) == .success(true)
state.canEditTopic = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomTopic) == .success(true)
state.canEditAvatar = await (try? roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomAvatar).get()) == .some(true)
state.canEditName = await (try? roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomName).get()) == .some(true)
state.canEditTopic = await (try? roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomTopic).get()) == .some(true)
}
}

View File

@@ -178,15 +178,15 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
}
private func updatePowerLevelPermissions() async {
async let canInviteUsers = roomProxy.canUserInvite(userID: roomProxy.ownUserID) == .success(true)
// Can't use async let because the mocks aren't thread safe when calling the same method 🤦
state.canEditRoomName = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomName) == .success(true)
state.canEditRoomTopic = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomTopic) == .success(true)
state.canEditRoomAvatar = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomAvatar) == .success(true)
state.canEditRoomName = await (try? roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomName).get()) == true
state.canEditRoomTopic = await (try? roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomTopic).get()) == true
state.canEditRoomAvatar = await (try? roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomAvatar).get()) == true
if appSettings.roomModerationEnabled {
state.canEditRolesOrPermissions = await roomProxy.suggestedRole(for: roomProxy.ownUserID) == .success(.administrator)
state.canEditRolesOrPermissions = await (try? roomProxy.suggestedRole(for: roomProxy.ownUserID).get()) == .administrator
}
state.canInviteUsers = await canInviteUsers
state.canInviteUsers = await (try? roomProxy.canUserInvite(userID: roomProxy.ownUserID).get()) == true
}
private func setupNotificationSettingsSubscription() {

View File

@@ -110,12 +110,9 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
bannedMembers: roomMembersDetails.bannedMembers,
bindings: state.bindings)
async let canInviteUsers = roomProxy.canUserInvite(userID: roomProxy.ownUserID)
async let canKickUsers = roomProxy.canUserKick(userID: roomProxy.ownUserID)
async let canBanUsers = roomProxy.canUserBan(userID: roomProxy.ownUserID)
self.state.canInviteUsers = await canInviteUsers == .success(true)
self.state.canKickUsers = await canKickUsers == .success(true)
self.state.canBanUsers = await canBanUsers == .success(true)
self.state.canInviteUsers = await (try? roomProxy.canUserInvite(userID: roomProxy.ownUserID).get()) == true
self.state.canKickUsers = await (try? roomProxy.canUserKick(userID: roomProxy.ownUserID).get()) == true
self.state.canBanUsers = await (try? roomProxy.canUserBan(userID: roomProxy.ownUserID).get()) == true
hideLoader()
}

View File

@@ -56,16 +56,16 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie
case .selectUser(let user):
showLoadingIndicator()
Task {
let currentDirectRoom = await clientProxy.directRoomForUserID(user.userID)
let currentDirectRoom = await userSession.clientProxy.directRoomForUserID(user.userID)
switch currentDirectRoom {
case .success(.some(let roomId)):
self.hideLoadingIndicator()
self.actionsSubject.send(.openRoom(withIdentifier: roomId))
case .success(nil):
case .success:
await self.createDirectRoom(with: user)
case .failure(let failure):
case .failure:
self.hideLoadingIndicator()
self.displayError(failure)
self.displayError()
}
}
}
@@ -73,19 +73,6 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie
// MARK: - Private
private func displayError(_ type: ClientProxyError) {
switch type {
case .failedCreatingRoom, .failedRetrievingDirectRoom:
state.bindings.alertInfo = AlertInfo(id: .failedCreatingRoom,
title: L10n.commonError,
message: L10n.screenStartChatErrorStartingChat)
case .failedSearchingUsers:
state.bindings.alertInfo = AlertInfo(id: .unknown)
default:
break
}
}
private func setupBindings() {
context.$viewState
.map(\.bindings.searchQuery)
@@ -101,12 +88,12 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie
private var fetchUsersTask: Task<Void, Never>?
private func fetchUsers() {
guard searchQuery.count >= 3 else {
guard context.searchQuery.count >= 3 else {
state.usersSection = .init(type: .suggestions, users: [])
return
}
fetchUsersTask = Task {
let result = await userDiscoveryService.searchProfiles(with: searchQuery)
let result = await userDiscoveryService.searchProfiles(with: context.searchQuery)
guard !Task.isCancelled else { return }
handleResult(for: .searchResult, result: result)
}
@@ -117,7 +104,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie
case .success(let users):
state.usersSection = .init(type: sectionType, users: users)
case .failure:
break
state.bindings.alertInfo = AlertInfo(id: .unknown)
}
}
@@ -126,23 +113,21 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie
hideLoadingIndicator()
}
showLoadingIndicator()
switch await clientProxy.createDirectRoom(with: user.userID, expectedRoomName: user.displayName) {
switch await userSession.clientProxy.createDirectRoom(with: user.userID, expectedRoomName: user.displayName) {
case .success(let roomId):
analytics.trackCreatedRoom(isDM: true)
actionsSubject.send(.openRoom(withIdentifier: roomId))
case .failure(let failure):
displayError(failure)
case .failure:
displayError()
}
}
private var clientProxy: ClientProxyProtocol {
userSession.clientProxy
private func displayError() {
state.bindings.alertInfo = AlertInfo(id: .failedCreatingRoom,
title: L10n.commonError,
message: L10n.screenStartChatErrorStartingChat)
}
private var searchQuery: String {
context.searchQuery
}
// MARK: Loading indicator
private static let loadingIndicatorIdentifier = "\(StartChatScreenViewModel.self)-Loading"

View File

@@ -216,7 +216,7 @@ class ClientProxy: ClientProxyProtocol {
return .success(result)
} catch {
MXLog.error("Failed checking isLastDevice with error: \(error)")
return .failure(.failedCheckingIsLastDevice(error))
return .failure(.sdkError(error))
}
}
@@ -293,7 +293,8 @@ class ClientProxy: ClientProxyProtocol {
let roomID = try self.client.getDmRoom(userId: userID)?.id()
return .success(roomID)
} catch {
return .failure(.failedRetrievingDirectRoom)
MXLog.error("Failed retrieving direct room for userID: \(userID) with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -313,7 +314,8 @@ class ClientProxy: ClientProxyProtocol {
let result = try self.client.createRoom(request: parameters)
return .success(result)
} catch {
return .failure(.failedCreatingRoom)
MXLog.error("Failed creating direct room for userID: \(userID) with error: \(error)")
return .failure(.sdkError(error))
}
}
@@ -335,7 +337,8 @@ class ClientProxy: ClientProxyProtocol {
let roomID = try self.client.createRoom(request: parameters)
return .success(roomID)
} catch {
return .failure(.failedCreatingRoom)
MXLog.error("Failed creating room with error: \(error)")
return .failure(.sdkError(error))
}
}
@@ -351,20 +354,27 @@ class ClientProxy: ClientProxyProtocol {
return .success(())
} catch {
return .failure(.failedJoiningRoom)
MXLog.error("Failed joining roomID: \(roomID) with error: \(error)")
return .failure(.sdkError(error))
}
}
func uploadMedia(_ media: MediaInfo) async -> Result<String, ClientProxyError> {
guard let mimeType = media.mimeType else { return .failure(ClientProxyError.mediaFileError) }
guard let mimeType = media.mimeType else {
MXLog.error("Failed uploading media, invalid mime type: \(media)")
return .failure(ClientProxyError.invalidMedia)
}
do {
let data = try Data(contentsOf: media.url)
let matrixUrl = try await client.uploadMedia(mimeType: mimeType, data: data, progressWatcher: nil)
return .success(matrixUrl)
} catch let error as ClientError {
return .failure(ClientProxyError.failedUploadingMedia(error.code))
MXLog.error("Failed uploading media with error: \(error)")
return .failure(ClientProxyError.failedUploadingMedia(error, error.code))
} catch {
return .failure(ClientProxyError.mediaFileError)
MXLog.error("Failed uploading media with error: \(error)")
return .failure(ClientProxyError.sdkError(error))
}
}
@@ -435,7 +445,8 @@ class ClientProxy: ClientProxyProtocol {
self.userDisplayNameSubject.send(displayName)
return .success(())
} catch {
return .failure(.failedRetrievingUserDisplayName)
MXLog.error("Failed loading user display name with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -449,7 +460,8 @@ class ClientProxy: ClientProxyProtocol {
}
return .success(())
} catch {
return .failure(.failedSettingUserDisplayName)
MXLog.error("Failed setting user display name with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -462,7 +474,8 @@ class ClientProxy: ClientProxyProtocol {
self.userAvatarURLSubject.send(urlString.flatMap(URL.init))
return .success(())
} catch {
return .failure(.failedRetrievingUserAvatarURL)
MXLog.error("Failed loading user avatar URL with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -470,7 +483,8 @@ class ClientProxy: ClientProxyProtocol {
func setUserAvatar(media: MediaInfo) async -> Result<Void, ClientProxyError> {
await Task.dispatch(on: .global()) {
guard case let .image(imageURL, _, _) = media, let mimeType = media.mimeType else {
return .failure(.failedSettingUserAvatar)
MXLog.error("Failed uploading, invalid media: \(media)")
return .failure(.invalidMedia)
}
do {
@@ -481,7 +495,8 @@ class ClientProxy: ClientProxyProtocol {
}
return .success(())
} catch {
return .failure(.failedSettingUserAvatar)
MXLog.error("Failed setting user avatar with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -495,7 +510,8 @@ class ClientProxy: ClientProxyProtocol {
}
return .success(())
} catch {
return .failure(.failedSettingUserAvatar)
MXLog.error("Failed removing user avatar with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -506,7 +522,8 @@ class ClientProxy: ClientProxyProtocol {
let sessionVerificationController = try self.client.getSessionVerificationController()
return .success(SessionVerificationControllerProxy(sessionVerificationController: sessionVerificationController))
} catch {
return .failure(.failedRetrievingSessionVerificationController)
MXLog.error("Failed retrieving session verification controller proxy with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -536,7 +553,8 @@ class ClientProxy: ClientProxyProtocol {
do {
return try .success(.init(sdkResults: self.client.searchUsers(searchTerm: searchTerm, limit: UInt64(limit))))
} catch {
return .failure(.failedSearchingUsers)
MXLog.error("Failed searching users with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -546,7 +564,8 @@ class ClientProxy: ClientProxyProtocol {
do {
return try .success(.init(sdkUserProfile: self.client.getProfile(userId: userID)))
} catch {
return .failure(.failedGettingUserProfile)
MXLog.error("Failed retrieving profile for userID: \(userID) with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -563,7 +582,7 @@ class ClientProxy: ClientProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed ignoring user with error: \(error)")
return .failure(.failedIgnoringUser)
return .failure(.sdkError(error))
}
}
@@ -573,7 +592,7 @@ class ClientProxy: ClientProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed unignoring user with error: \(error)")
return .failure(.failedUnignoringUser)
return .failure(.sdkError(error))
}
}

View File

@@ -38,22 +38,9 @@ enum ClientProxyLoadingState {
}
enum ClientProxyError: Error {
case failedCreatingRoom
case failedRetrievingDirectRoom
case failedRetrievingUserDisplayName
case failedRetrievingUserAvatarURL
case failedSettingUserDisplayName
case failedRetrievingSessionVerificationController
case failedLoadingMedia
case mediaFileError
case failedUploadingMedia(MatrixErrorCode)
case failedSearchingUsers
case failedGettingUserProfile
case failedSettingUserAvatar
case failedCheckingIsLastDevice(Error?)
case failedIgnoringUser
case failedUnignoringUser
case failedJoiningRoom
case sdkError(Error)
case invalidMedia
case failedUploadingMedia(Error, MatrixErrorCode)
}
enum SlidingSyncConstants {

View File

@@ -168,7 +168,8 @@ class RoomProxy: RoomProxyProtocol {
try self.room.redact(eventId: eventID, reason: nil)
return .success(())
} catch {
return .failure(.failedRedactingEvent)
MXLog.error("Failed redacting eventID: \(eventID) with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -184,7 +185,8 @@ class RoomProxy: RoomProxyProtocol {
try self.room.reportContent(eventId: eventID, score: nil, reason: reason)
return .success(())
} catch {
return .failure(.failedReportingContent)
MXLog.error("Failed reporting eventID: \(eventID) with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -198,7 +200,7 @@ class RoomProxy: RoomProxyProtocol {
membersSubject.value = members.map(RoomMemberProxy.init)
}
} catch {
MXLog.error("[RoomProxy] Failed to update members using no sync API: \(error)")
MXLog.error("[RoomProxy] Failed updating members using no sync API: \(error)")
}
do {
@@ -208,7 +210,7 @@ class RoomProxy: RoomProxyProtocol {
membersSubject.value = members.map(RoomMemberProxy.init)
}
} catch {
MXLog.error("[RoomProxy] Failed to update members using sync API: \(error)")
MXLog.error("[RoomProxy] Failed updating members using sync API: \(error)")
}
}
@@ -226,7 +228,8 @@ class RoomProxy: RoomProxyProtocol {
let member = try await room.member(userId: userID)
return .success(RoomMemberProxy(member: member))
} catch {
return .failure(.failedRetrievingMember)
MXLog.error("Failed retrieving member \(userID) with error: \(error)")
return .failure(.sdkError(error))
}
}
@@ -241,8 +244,8 @@ class RoomProxy: RoomProxyProtocol {
try self.room.leave()
return .success(())
} catch {
MXLog.error("Failed to leave the room: \(error)")
return .failure(.failedLeavingRoom)
MXLog.error("Failed leaving room with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -252,7 +255,8 @@ class RoomProxy: RoomProxyProtocol {
do {
return try .success(self.room.leave())
} catch {
return .failure(.failedRejectingInvite)
MXLog.error("Failed rejecting invitiation with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -263,7 +267,8 @@ class RoomProxy: RoomProxyProtocol {
try self.room.join()
return .success(())
} catch {
return .failure(.failedAcceptingInvite)
MXLog.error("Failed accepting invitation with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -275,7 +280,7 @@ class RoomProxy: RoomProxyProtocol {
return try .success(self.room.inviteUserById(userId: userID))
} catch {
MXLog.error("Failed inviting user \(userID) with error: \(error)")
return .failure(.failedInvitingUser)
return .failure(.sdkError(error))
}
}
}
@@ -285,7 +290,8 @@ class RoomProxy: RoomProxyProtocol {
do {
return try .success(self.room.setName(name: name))
} catch {
return .failure(.failedSettingRoomName)
MXLog.error("Failed setting name with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -295,7 +301,8 @@ class RoomProxy: RoomProxyProtocol {
do {
return try .success(self.room.setTopic(topic: topic))
} catch {
return .failure(.failedSettingRoomTopic)
MXLog.error("Failed setting topic with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -305,7 +312,8 @@ class RoomProxy: RoomProxyProtocol {
do {
return try .success(self.room.removeAvatar())
} catch {
return .failure(.failedRemovingAvatar)
MXLog.error("Failed removing avatar with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -313,14 +321,16 @@ class RoomProxy: RoomProxyProtocol {
func uploadAvatar(media: MediaInfo) async -> Result<Void, RoomProxyError> {
await Task.dispatch(on: .global()) {
guard case let .image(imageURL, _, _) = media, let mimeType = media.mimeType else {
return .failure(.failedUploadingAvatar)
MXLog.error("Failed uploading avatar, invalid media: \(media)")
return .failure(.invalidMedia)
}
do {
let data = try Data(contentsOf: imageURL)
return try .success(self.room.uploadAvatar(mimeType: mimeType, data: data, mediaInfo: nil))
} catch {
return .failure(.failedUploadingAvatar)
MXLog.error("Failed uploading avatar with error: \(error)")
return .failure(.sdkError(error))
}
}
}
@@ -331,7 +341,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed marking room \(id) as read with error: \(error)")
return .failure(.failedMarkingAsRead)
return .failure(.sdkError(error))
}
}
@@ -343,7 +353,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed sending typing notice with error: \(error)")
return .failure(.failedSendingTypingNotice)
return .failure(.sdkError(error))
}
}
@@ -357,7 +367,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed marking room \(id) as unread: \(isUnread) with error: \(error)")
return .failure(.failedFlaggingAsUnread)
return .failure(.sdkError(error))
}
}
@@ -367,7 +377,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed flagging room \(id) as favourite with error: \(error)")
return .failure(.failedFlaggingAsFavourite)
return .failure(.sdkError(error))
}
}
@@ -378,7 +388,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.getPowerLevels())
} catch {
MXLog.error("Failed building the current power level settings: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -387,7 +397,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.applyPowerLevelChanges(changes: changes))
} catch {
MXLog.error("Failed applying the power level changes: \(error)")
return .failure(.failedSettingPermission)
return .failure(.sdkError(error))
}
}
@@ -396,7 +406,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.resetPowerLevels())
} catch {
MXLog.error("Failed resetting the power levels: \(error)")
return .failure(.failedSettingPermission)
return .failure(.sdkError(error))
}
}
@@ -405,7 +415,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.suggestedRoleForUser(userId: userID))
} catch {
MXLog.error("Failed getting a user's role: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -415,7 +425,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.updatePowerLevelsForUsers(updates: updates))
} catch {
MXLog.error("Failed updating user power levels changes: \(error)")
return .failure(.failedSettingPermission)
return .failure(.sdkError(error))
}
}
@@ -424,7 +434,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserSendState(userId: userID, stateEvent: event))
} catch {
MXLog.error("Failed checking if the user can send \(event) with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -433,7 +443,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserInvite(userId: userID))
} catch {
MXLog.error("Failed checking if the user can invite with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -442,7 +452,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserRedactOther(userId: userID))
} catch {
MXLog.error("Failed checking if the user can redact others with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -451,7 +461,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserRedactOwn(userId: userID))
} catch {
MXLog.error("Failed checking if the user can redact self with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -460,7 +470,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserKick(userId: userID))
} catch {
MXLog.error("Failed checking if the user can kick with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -469,7 +479,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserBan(userId: userID))
} catch {
MXLog.error("Failed checking if the user can ban with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -478,7 +488,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserTriggerRoomNotification(userId: userID))
} catch {
MXLog.error("Failed checking if the user can trigger room notification with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -490,7 +500,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed kicking \(userID) with error: \(error)")
return .failure(.failedModeration)
return .failure(.sdkError(error))
}
}
@@ -500,7 +510,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed banning \(userID) with error: \(error)")
return .failure(.failedModeration)
return .failure(.sdkError(error))
}
}
@@ -510,7 +520,7 @@ class RoomProxy: RoomProxyProtocol {
return .success(())
} catch {
MXLog.error("Failed unbanning \(userID) with error: \(error)")
return .failure(.failedModeration)
return .failure(.sdkError(error))
}
}
@@ -521,7 +531,7 @@ class RoomProxy: RoomProxyProtocol {
return try await .success(room.canUserSendState(userId: userID, stateEvent: .callMember))
} catch {
MXLog.error("Failed checking if the user can trigger room notification with error: \(error)")
return .failure(.failedCheckingPermission)
return .failure(.sdkError(error))
}
}
@@ -536,14 +546,14 @@ class RoomProxy: RoomProxyProtocol {
let urlString = try await room.matrixToPermalink()
guard let url = URL(string: urlString) else {
MXLog.error("Invalid permalink URL string: \(urlString)")
return .failure(.generic("Invalid permalink URL string: \(urlString)"))
MXLog.error("Failed creating permalink for roomID: \(id), invalid permalink URL string: \(urlString)")
return .failure(.invalidURL)
}
return .success(url)
} catch {
MXLog.error("Failed creating permalink for roomID: \(id) with error: \(error)")
return .failure(.generic(error.localizedDescription))
return .failure(.sdkError(error))
}
}
@@ -552,14 +562,14 @@ class RoomProxy: RoomProxyProtocol {
let urlString = try await room.matrixToEventPermalink(eventId: eventID)
guard let url = URL(string: urlString) else {
MXLog.error("Invalid permalink URL string: \(urlString)")
return .failure(.generic("Invalid permalink URL string: \(urlString)"))
MXLog.error("Failed creating permalink for eventID: \(eventID), invalid permalink URL string: \(urlString)")
return .failure(.invalidURL)
}
return .success(url)
} catch {
MXLog.error("Failed creating permalink for eventID: \(eventID) with error: \(error)")
return .failure(.generic(error.localizedDescription))
return .failure(.sdkError(error))
}
}

View File

@@ -18,26 +18,11 @@ import Combine
import Foundation
import MatrixRustSDK
enum RoomProxyError: Error, Equatable {
case generic(String?)
case failedRedactingEvent
case failedReportingContent
case failedRetrievingMember
case failedLeavingRoom
case failedAcceptingInvite
case failedRejectingInvite
case failedInvitingUser
case failedSettingRoomName
case failedSettingRoomTopic
case failedRemovingAvatar
case failedUploadingAvatar
case failedCheckingPermission
case failedSettingPermission
case failedFlaggingAsUnread
case failedMarkingAsRead
case failedSendingTypingNotice
case failedFlaggingAsFavourite
case failedModeration
enum RoomProxyError: Error {
case sdkError(Error)
case invalidURL
case invalidMedia
}
enum RoomProxyAction {

View File

@@ -105,7 +105,7 @@ class HomeScreenViewModelTests: XCTestCase {
func testLeaveRoomError() async throws {
let mockRoomId = "1"
let room: RoomProxyMock = .init(with: .init(id: mockRoomId, name: "Some room"))
room.leaveRoomClosure = { .failure(.failedLeavingRoom) }
room.leaveRoomClosure = { .failure(.sdkError(ClientProxyMockError.generic)) }
clientProxy.roomForIdentifierClosure = { _ in room }

View File

@@ -138,7 +138,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
defer {
expectation.fulfill()
}
return .failure(.failedLeavingRoom)
return .failure(.sdkError(ClientProxyMockError.generic))
}
context.send(viewAction: .confirmLeave)
await fulfillment(of: [expectation])
@@ -207,7 +207,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
let recipient = RoomMemberProxyMock.mockDan
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
let clientProxy = ClientProxyMock(.init())
clientProxy.ignoreUserReturnValue = .failure(.failedIgnoringUser)
clientProxy.ignoreUserReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
roomProxyMock = RoomProxyMock(with: .init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
clientProxy: clientProxy,
@@ -276,7 +276,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
let recipient = RoomMemberProxyMock.mockIgnored
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
let clientProxy = ClientProxyMock(.init())
clientProxy.unignoreUserReturnValue = .failure(.failedUnignoringUser)
clientProxy.unignoreUserReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
roomProxyMock = RoomProxyMock(with: .init(name: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock,
clientProxy: clientProxy,

View File

@@ -87,7 +87,7 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testIgnoreFailure() async throws {
roomMemberProxyMock = RoomMemberProxyMock.mockAlice
let clientProxy = ClientProxyMock(.init())
clientProxy.ignoreUserReturnValue = .failure(.failedIgnoringUser)
clientProxy.ignoreUserReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
viewModel = RoomMemberDetailsScreenViewModel(userID: roomMemberProxyMock.userID,
roomProxy: roomProxyMock,
clientProxy: clientProxy,
@@ -158,7 +158,7 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testUnignoreFailure() async throws {
roomMemberProxyMock = RoomMemberProxyMock.mockIgnored
let clientProxy = ClientProxyMock(.init())
clientProxy.unignoreUserReturnValue = .failure(.failedUnignoringUser)
clientProxy.unignoreUserReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
viewModel = RoomMemberDetailsScreenViewModel(userID: roomMemberProxyMock.userID,
roomProxy: roomProxyMock,
clientProxy: clientProxy,

View File

@@ -71,7 +71,7 @@ class UserDiscoveryServiceTest: XCTestCase {
}
func testLocalResultShowsOnSearchError() async {
clientProxy.searchUsersSearchTermLimitReturnValue = .failure(.failedSearchingUsers)
clientProxy.searchUsersSearchTermLimitReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
clientProxy.profileForReturnValue = .success(.init(userID: "@some:matrix.org"))
let results = await (try? search(query: "@a:b.com").get()) ?? []
@@ -81,7 +81,7 @@ class UserDiscoveryServiceTest: XCTestCase {
}
func testSearchErrorTriggers() async {
clientProxy.searchUsersSearchTermLimitReturnValue = .failure(.failedSearchingUsers)
clientProxy.searchUsersSearchTermLimitReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
clientProxy.profileForReturnValue = .success(.init(userID: "@some:matrix.org"))
switch await search(query: "some query") {
@@ -108,7 +108,7 @@ class UserDiscoveryServiceTest: XCTestCase {
func testSearchResultsShowWhenGetProfileFails() async {
clientProxy.searchUsersSearchTermLimitReturnValue = .success(.init(results: searchResults, limited: true))
clientProxy.profileForReturnValue = .failure(.failedGettingUserProfile)
clientProxy.profileForReturnValue = .failure(.sdkError(ClientProxyMockError.generic))
let results = await (try? search(query: "@a:b.com").get()) ?? []