SDK update (#3891)

* Bump the RustSDK to v25.03.11

* Replace oidc login prompt with nil following the changes from https://github.com/matrix-org/matrix-rust-sdk/pull/4761

```
/// * `prompt` - The desired user experience in the web UI. No value means
///   that the user wishes to login into an existing account, and a value of
///   `Create` means that the user wishes to register a new account.
```

* Fix trailing closure warnings

* Update the client proxy after making `getNotificationSettings()` and  `cachedAvatarUrl()` async (they used to be blocking on the rust side).

* Move `Room.isEncrypted` to the info publisher and manually update the encryption state when creating the room.

* Bump the SDK again to v25.03.12 - This introduces a new way to configure the tokio runtime that we can use to have extensions use less memory
- introduce a new Target struct that takes care of setting up rust services (tracing and tokio) for our various targets
- cleanup MXLog and friends

* Address PR comments

* Bump the SDK again, switch back to using `.consent` as the OIDC login prompt (which was reintroduced in matrix-org/matrix-rust-sdk/pull/4791)
This commit is contained in:
Stefan Ceriu
2025-03-13 11:17:37 +02:00
committed by GitHub
parent 2b31ac6f88
commit 07e96115ce
34 changed files with 365 additions and 327 deletions
@@ -69,7 +69,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
let appSettings = appHooks.appSettingsHook.configure(AppSettings())
MXLog.configure(currentTarget: "elementx", filePrefix: nil, logLevel: appSettings.logLevel)
Target.mainApp.configure(logLevel: appSettings.logLevel)
let appName = InfoPlistReader.main.bundleDisplayName
let appVersion = InfoPlistReader.main.bundleShortVersionString
@@ -0,0 +1,42 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import MatrixRustSDK
enum Target: String {
case mainApp = "elementx"
case nse
case shareExtension = "shareextension"
case tests
private static var isConfigured = false
func configure(logLevel: LogLevel) {
guard !Self.isConfigured else {
return
}
switch self {
case .mainApp:
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel, currentTarget: rawValue, filePrefix: nil)
initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: false)
case .nse:
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel, currentTarget: rawValue, filePrefix: rawValue)
initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: true)
case .shareExtension:
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel, currentTarget: rawValue, filePrefix: rawValue)
initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: true)
case .tests:
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel, currentTarget: rawValue, filePrefix: rawValue)
initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: false)
}
MXLog.configure(currentTarget: rawValue)
Self.isConfigured = true
}
}
@@ -29,6 +29,7 @@ extension BannedRoomProxyMock {
extension RoomInfo {
@MainActor init(_ configuration: BannedRoomProxyMockConfiguration) {
self.init(id: configuration.id,
encryptionState: .notEncrypted,
creator: nil,
displayName: configuration.name,
rawName: nil,
@@ -6212,11 +6212,6 @@ class InvitedRoomProxyMock: InvitedRoomProxyProtocol, @unchecked Sendable {
}
}
class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable {
var isEncrypted: Bool {
get { return underlyingIsEncrypted }
set(value) { underlyingIsEncrypted = value }
}
var underlyingIsEncrypted: Bool!
var infoPublisher: CurrentValuePublisher<RoomInfoProxy, Never> {
get { return underlyingInfoPublisher }
set(value) { underlyingInfoPublisher = value }
@@ -473,15 +473,15 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable {
}
}
}
open var cachedAvatarUrlClosure: (() throws -> String?)?
open var cachedAvatarUrlClosure: (() async throws -> String?)?
open override func cachedAvatarUrl() throws -> String? {
open override func cachedAvatarUrl() async throws -> String? {
if let error = cachedAvatarUrlThrowableError {
throw error
}
cachedAvatarUrlCallsCount += 1
if let cachedAvatarUrlClosure = cachedAvatarUrlClosure {
return try cachedAvatarUrlClosure()
return try await cachedAvatarUrlClosure()
} else {
return cachedAvatarUrlReturnValue
}
@@ -1404,12 +1404,12 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable {
}
}
}
open var getNotificationSettingsClosure: (() -> NotificationSettings)?
open var getNotificationSettingsClosure: (() async -> NotificationSettings)?
open override func getNotificationSettings() -> NotificationSettings {
open override func getNotificationSettings() async -> NotificationSettings {
getNotificationSettingsCallsCount += 1
if let getNotificationSettingsClosure = getNotificationSettingsClosure {
return getNotificationSettingsClosure()
return await getNotificationSettingsClosure()
} else {
return getNotificationSettingsReturnValue
}
@@ -1559,6 +1559,81 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable {
}
}
//MARK: - getRoom
open var getRoomRoomIdThrowableError: Error?
var getRoomRoomIdUnderlyingCallsCount = 0
open var getRoomRoomIdCallsCount: Int {
get {
if Thread.isMainThread {
return getRoomRoomIdUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = getRoomRoomIdUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
getRoomRoomIdUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
getRoomRoomIdUnderlyingCallsCount = newValue
}
}
}
}
open var getRoomRoomIdCalled: Bool {
return getRoomRoomIdCallsCount > 0
}
open var getRoomRoomIdReceivedRoomId: String?
open var getRoomRoomIdReceivedInvocations: [String] = []
var getRoomRoomIdUnderlyingReturnValue: Room?
open var getRoomRoomIdReturnValue: Room? {
get {
if Thread.isMainThread {
return getRoomRoomIdUnderlyingReturnValue
} else {
var returnValue: Room?? = nil
DispatchQueue.main.sync {
returnValue = getRoomRoomIdUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
getRoomRoomIdUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
getRoomRoomIdUnderlyingReturnValue = newValue
}
}
}
}
open var getRoomRoomIdClosure: ((String) throws -> Room?)?
open override func getRoom(roomId: String) throws -> Room? {
if let error = getRoomRoomIdThrowableError {
throw error
}
getRoomRoomIdCallsCount += 1
getRoomRoomIdReceivedRoomId = roomId
DispatchQueue.main.async {
self.getRoomRoomIdReceivedInvocations.append(roomId)
}
if let getRoomRoomIdClosure = getRoomRoomIdClosure {
return try getRoomRoomIdClosure(roomId)
} else {
return getRoomRoomIdReturnValue
}
}
//MARK: - getRoomPreviewFromRoomAlias
open var getRoomPreviewFromRoomAliasRoomAliasThrowableError: Error?
@@ -4111,8 +4186,8 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable {
open var urlForOidcOidcConfigurationPromptCalled: Bool {
return urlForOidcOidcConfigurationPromptCallsCount > 0
}
open var urlForOidcOidcConfigurationPromptReceivedArguments: (oidcConfiguration: OidcConfiguration, prompt: OidcPrompt)?
open var urlForOidcOidcConfigurationPromptReceivedInvocations: [(oidcConfiguration: OidcConfiguration, prompt: OidcPrompt)] = []
open var urlForOidcOidcConfigurationPromptReceivedArguments: (oidcConfiguration: OidcConfiguration, prompt: OidcPrompt?)?
open var urlForOidcOidcConfigurationPromptReceivedInvocations: [(oidcConfiguration: OidcConfiguration, prompt: OidcPrompt?)] = []
var urlForOidcOidcConfigurationPromptUnderlyingReturnValue: OidcAuthorizationData!
open var urlForOidcOidcConfigurationPromptReturnValue: OidcAuthorizationData! {
@@ -4138,9 +4213,9 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable {
}
}
}
open var urlForOidcOidcConfigurationPromptClosure: ((OidcConfiguration, OidcPrompt) async throws -> OidcAuthorizationData)?
open var urlForOidcOidcConfigurationPromptClosure: ((OidcConfiguration, OidcPrompt?) async throws -> OidcAuthorizationData)?
open override func urlForOidc(oidcConfiguration: OidcConfiguration, prompt: OidcPrompt) async throws -> OidcAuthorizationData {
open override func urlForOidc(oidcConfiguration: OidcConfiguration, prompt: OidcPrompt?) async throws -> OidcAuthorizationData {
if let error = urlForOidcOidcConfigurationPromptThrowableError {
throw error
}
@@ -11486,6 +11561,71 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable {
enableSendQueueEnableClosure?(enable)
}
//MARK: - encryptionState
var encryptionStateUnderlyingCallsCount = 0
open var encryptionStateCallsCount: Int {
get {
if Thread.isMainThread {
return encryptionStateUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = encryptionStateUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
encryptionStateUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
encryptionStateUnderlyingCallsCount = newValue
}
}
}
}
open var encryptionStateCalled: Bool {
return encryptionStateCallsCount > 0
}
var encryptionStateUnderlyingReturnValue: EncryptionState!
open var encryptionStateReturnValue: EncryptionState! {
get {
if Thread.isMainThread {
return encryptionStateUnderlyingReturnValue
} else {
var returnValue: EncryptionState? = nil
DispatchQueue.main.sync {
returnValue = encryptionStateUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
encryptionStateUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
encryptionStateUnderlyingReturnValue = newValue
}
}
}
}
open var encryptionStateClosure: (() -> EncryptionState)?
open override func encryptionState() -> EncryptionState {
encryptionStateCallsCount += 1
if let encryptionStateClosure = encryptionStateClosure {
return encryptionStateClosure()
} else {
return encryptionStateReturnValue
}
}
//MARK: - forget
open var forgetThrowableError: Error?
@@ -12062,71 +12202,6 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable {
}
}
//MARK: - inviter
var inviterUnderlyingCallsCount = 0
open var inviterCallsCount: Int {
get {
if Thread.isMainThread {
return inviterUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = inviterUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
inviterUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
inviterUnderlyingCallsCount = newValue
}
}
}
}
open var inviterCalled: Bool {
return inviterCallsCount > 0
}
var inviterUnderlyingReturnValue: RoomMember?
open var inviterReturnValue: RoomMember? {
get {
if Thread.isMainThread {
return inviterUnderlyingReturnValue
} else {
var returnValue: RoomMember?? = nil
DispatchQueue.main.sync {
returnValue = inviterUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
inviterUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
inviterUnderlyingReturnValue = newValue
}
}
}
}
open var inviterClosure: (() async -> RoomMember?)?
open override func inviter() async -> RoomMember? {
inviterCallsCount += 1
if let inviterClosure = inviterClosure {
return await inviterClosure()
} else {
return inviterReturnValue
}
}
//MARK: - isDirect
var isDirectUnderlyingCallsCount = 0
@@ -12181,86 +12256,17 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable {
}
}
}
open var isDirectClosure: (() -> Bool)?
open var isDirectClosure: (() async -> Bool)?
open override func isDirect() -> Bool {
open override func isDirect() async -> Bool {
isDirectCallsCount += 1
if let isDirectClosure = isDirectClosure {
return isDirectClosure()
return await isDirectClosure()
} else {
return isDirectReturnValue
}
}
//MARK: - isEncrypted
open var isEncryptedThrowableError: Error?
var isEncryptedUnderlyingCallsCount = 0
open var isEncryptedCallsCount: Int {
get {
if Thread.isMainThread {
return isEncryptedUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = isEncryptedUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
isEncryptedUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
isEncryptedUnderlyingCallsCount = newValue
}
}
}
}
open var isEncryptedCalled: Bool {
return isEncryptedCallsCount > 0
}
var isEncryptedUnderlyingReturnValue: Bool!
open var isEncryptedReturnValue: Bool! {
get {
if Thread.isMainThread {
return isEncryptedUnderlyingReturnValue
} else {
var returnValue: Bool? = nil
DispatchQueue.main.sync {
returnValue = isEncryptedUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
isEncryptedUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
isEncryptedUnderlyingReturnValue = newValue
}
}
}
}
open var isEncryptedClosure: (() throws -> Bool)?
open override func isEncrypted() throws -> Bool {
if let error = isEncryptedThrowableError {
throw error
}
isEncryptedCallsCount += 1
if let isEncryptedClosure = isEncryptedClosure {
return try isEncryptedClosure()
} else {
return isEncryptedReturnValue
}
}
//MARK: - isPublic
var isPublicUnderlyingCallsCount = 0
@@ -12672,6 +12678,75 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable {
try await kickUserUserIdReasonClosure?(userId, reason)
}
//MARK: - latestEncryptionState
open var latestEncryptionStateThrowableError: Error?
var latestEncryptionStateUnderlyingCallsCount = 0
open var latestEncryptionStateCallsCount: Int {
get {
if Thread.isMainThread {
return latestEncryptionStateUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = latestEncryptionStateUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
latestEncryptionStateUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
latestEncryptionStateUnderlyingCallsCount = newValue
}
}
}
}
open var latestEncryptionStateCalled: Bool {
return latestEncryptionStateCallsCount > 0
}
var latestEncryptionStateUnderlyingReturnValue: EncryptionState!
open var latestEncryptionStateReturnValue: EncryptionState! {
get {
if Thread.isMainThread {
return latestEncryptionStateUnderlyingReturnValue
} else {
var returnValue: EncryptionState? = nil
DispatchQueue.main.sync {
returnValue = latestEncryptionStateUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
latestEncryptionStateUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
latestEncryptionStateUnderlyingReturnValue = newValue
}
}
}
}
open var latestEncryptionStateClosure: (() async throws -> EncryptionState)?
open override func latestEncryptionState() async throws -> EncryptionState {
if let error = latestEncryptionStateThrowableError {
throw error
}
latestEncryptionStateCallsCount += 1
if let latestEncryptionStateClosure = latestEncryptionStateClosure {
return try await latestEncryptionStateClosure()
} else {
return latestEncryptionStateReturnValue
}
}
//MARK: - leave
open var leaveThrowableError: Error?
@@ -16880,75 +16955,6 @@ open class RoomListItemSDKMock: MatrixRustSDK.RoomListItem, @unchecked Sendable
try await initTimelineEventTypeFilterInternalIdPrefixClosure?(eventTypeFilter, internalIdPrefix)
}
//MARK: - invitedRoom
open var invitedRoomThrowableError: Error?
var invitedRoomUnderlyingCallsCount = 0
open var invitedRoomCallsCount: Int {
get {
if Thread.isMainThread {
return invitedRoomUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = invitedRoomUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
invitedRoomUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
invitedRoomUnderlyingCallsCount = newValue
}
}
}
}
open var invitedRoomCalled: Bool {
return invitedRoomCallsCount > 0
}
var invitedRoomUnderlyingReturnValue: Room!
open var invitedRoomReturnValue: Room! {
get {
if Thread.isMainThread {
return invitedRoomUnderlyingReturnValue
} else {
var returnValue: Room? = nil
DispatchQueue.main.sync {
returnValue = invitedRoomUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
invitedRoomUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
invitedRoomUnderlyingReturnValue = newValue
}
}
}
}
open var invitedRoomClosure: (() throws -> Room)?
open override func invitedRoom() throws -> Room {
if let error = invitedRoomThrowableError {
throw error
}
invitedRoomCallsCount += 1
if let invitedRoomClosure = invitedRoomClosure {
return try invitedRoomClosure()
} else {
return invitedRoomReturnValue
}
}
//MARK: - isDirect
var isDirectUnderlyingCallsCount = 0
@@ -17003,12 +17009,12 @@ open class RoomListItemSDKMock: MatrixRustSDK.RoomListItem, @unchecked Sendable
}
}
}
open var isDirectClosure: (() -> Bool)?
open var isDirectClosure: (() async -> Bool)?
open override func isDirect() -> Bool {
open override func isDirect() async -> Bool {
isDirectCallsCount += 1
if let isDirectClosure = isDirectClosure {
return isDirectClosure()
return await isDirectClosure()
} else {
return isDirectReturnValue
}
@@ -33,6 +33,7 @@ extension InvitedRoomProxyMock {
extension RoomInfo {
@MainActor init(_ configuration: InvitedRoomProxyMockConfiguration) {
self.init(id: configuration.id,
encryptionState: .notEncrypted,
creator: nil,
displayName: configuration.name,
rawName: nil,
@@ -52,8 +52,7 @@ extension JoinedRoomProxyMock {
self.init()
id = configuration.id
isEncrypted = configuration.isEncrypted
timeline = TimelineProxyMock(.init(isAutoUpdating: configuration.shouldUseAutoUpdatingTimeline,
timelineStartReached: configuration.timelineStartReached))
@@ -137,6 +136,7 @@ extension JoinedRoomProxyMock {
extension RoomInfo {
@MainActor init(_ configuration: JoinedRoomProxyMockConfiguration) {
self.init(id: configuration.id,
encryptionState: configuration.isEncrypted ? .encrypted : .notEncrypted,
creator: nil,
displayName: configuration.name,
rawName: configuration.name,
@@ -29,6 +29,7 @@ extension KnockedRoomProxyMock {
extension RoomInfo {
@MainActor init(_ configuration: KnockedRoomProxyMockConfiguration) {
self.init(id: configuration.id,
encryptionState: .notEncrypted,
creator: nil,
displayName: configuration.name,
rawName: nil,
@@ -9,8 +9,6 @@ import Foundation
import MatrixRustSDK
enum ExtensionLogger {
private static var isConfigured = false
/// Memory formatter, uses exact 2 fraction digits and no grouping
private static var numberFormatter: NumberFormatter {
let formatter = NumberFormatter()
@@ -66,15 +64,6 @@ enum ExtensionLogger {
return "\(formattedStr) MB"
}
static func configure(currentTarget: String, logLevel: LogLevel) {
guard !isConfigured else {
return
}
isConfigured = true
MXLog.configure(currentTarget: currentTarget, filePrefix: currentTarget, logLevel: logLevel)
}
static func logMemory(with tag: String) {
MXLog.info("\(tag) Memory: footprint: \(formattedMemoryFootprint) - available: \(formattedMemoryAvailable)")
}
+2 -21
View File
@@ -14,29 +14,14 @@ import MatrixRustSDK
Its purpose is to provide a common entry for customizing logging and should be used throughout the code.
*/
enum MXLog {
private enum Constants {
static let target = "elementx"
}
// Rust side crashes if invoking setupTracing multiple times
private static var didConfigureOnce = false
private static var rootSpan: Span!
private static var currentTarget: String!
static func configure(currentTarget: String,
filePrefix: String?,
logLevel: LogLevel) {
guard !didConfigureOnce else { return }
Tracing.setup(logLevel: logLevel, currentTarget: currentTarget, filePrefix: filePrefix)
static func configure(currentTarget: String) {
self.currentTarget = currentTarget
rootSpan = Span(file: #file, line: #line, level: .info, target: self.currentTarget, name: "root")
rootSpan.enter()
didConfigureOnce = true
}
static func createSpan(_ name: String,
@@ -134,10 +119,6 @@ enum MXLog {
function: String = #function,
line: Int = #line,
column: Int = #column) -> Span {
guard didConfigureOnce else {
fatalError()
}
if Span.current().isNone() {
rootSpan.enter()
}
@@ -152,7 +133,7 @@ enum MXLog {
function: String = #function,
line: Int = #line,
column: Int = #column) {
guard didConfigureOnce else {
guard let rootSpan else {
return
}
+8 -8
View File
@@ -23,7 +23,7 @@ enum Tracing {
static let fileExtension = "log"
static func setup(logLevel: LogLevel, currentTarget: String, filePrefix: String?) {
static func buildConfiguration(logLevel: LogLevel, currentTarget: String, filePrefix: String?) -> TracingConfiguration {
let fileName = if let filePrefix {
"\(Tracing.filePrefix)-\(filePrefix)"
} else {
@@ -38,13 +38,13 @@ enum Tracing {
// the logs contain any sensitive data. See `integration-tests.yml`
let level: LogLevel = ProcessInfo.isRunningIntegrationTests ? .trace : logLevel
setupTracing(config: .init(logLevel: level.rustLogLevel,
extraTargets: [currentTarget],
writeToStdoutOrSystem: true,
writeToFiles: .init(path: logsDirectory.path(percentEncoded: false),
filePrefix: fileName,
fileSuffix: fileExtension,
maxFiles: maxFiles)))
return .init(logLevel: level.rustLogLevel,
extraTargets: [currentTarget],
writeToStdoutOrSystem: true,
writeToFiles: .init(path: logsDirectory.path(percentEncoded: false),
filePrefix: fileName,
fileSuffix: fileExtension,
maxFiles: maxFiles))
}
/// A list of all log file URLs, sorted chronologically. This is only public for testing purposes, within
@@ -43,7 +43,7 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType,
super.init(initialViewState: MediaUploadPreviewScreenViewState(url: url,
title: title,
shouldShowCaptionWarning: shouldShowCaptionWarning,
isRoomEncrypted: roomProxy.isEncrypted))
isRoomEncrypted: roomProxy.infoPublisher.value.isEncrypted))
}
override func process(viewAction: MediaUploadPreviewScreenViewAction) {
@@ -38,8 +38,8 @@ struct DMRecipientInfo {
struct RoomDetailsScreenViewState: BindableState {
var details: RoomDetails
let isEncrypted: Bool
let isDirect: Bool
var isEncrypted: Bool
var isDirect: Bool
var permalink: URL?
var topic: AttributedString?
@@ -65,7 +65,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
let topic = attributedStringBuilder.fromPlain(roomProxy.infoPublisher.value.topic)
super.init(initialViewState: .init(details: roomProxy.details,
isEncrypted: roomProxy.isEncrypted,
isEncrypted: roomProxy.infoPublisher.value.isEncrypted,
isDirect: roomProxy.infoPublisher.value.isDirect,
topic: topic,
topicSummary: topic?.unattributedStringByReplacingNewlinesWithSpaces(),
@@ -208,13 +208,18 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
}
private func updateRoomInfo(_ roomInfo: RoomInfoProxy) {
state.isEncrypted = roomInfo.isEncrypted
state.isDirect = roomInfo.isDirect
state.bindings.isFavourite = roomInfo.isFavourite
state.joinedMembersCount = roomInfo.joinedMembersCount
state.details = roomProxy.details
let topic = attributedStringBuilder.fromPlain(roomInfo.topic)
state.topic = topic
state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
state.joinedMembersCount = roomInfo.joinedMembersCount
state.bindings.isFavourite = roomInfo.isFavourite
switch roomInfo.joinRule {
case .knock, .knockRestricted:
state.isKnockableRoom = true
@@ -250,7 +255,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
}
private func updateMemberIdentityVerificationStates() async {
guard roomProxy.isEncrypted else {
guard roomProxy.infoPublisher.value.isEncrypted else {
// We don't care about identity statuses on non-encrypted rooms
return
}
@@ -309,7 +314,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
private func fetchRoomNotificationSettings() async {
do {
let notificationMode = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
isEncrypted: roomProxy.isEncrypted,
isEncrypted: roomProxy.infoPublisher.value.isEncrypted,
isOneToOne: roomProxy.infoPublisher.value.activeMembersCount == 2)
state.notificationSettingsState = .loaded(settings: notificationMode)
} catch {
@@ -327,7 +332,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
case .mute:
do {
try await notificationSettingsProxy.unmuteRoom(roomId: roomProxy.id,
isEncrypted: roomProxy.isEncrypted,
isEncrypted: roomProxy.infoPublisher.value.isEncrypted,
isOneToOne: roomProxy.infoPublisher.value.activeMembersCount == 2)
} catch {
state.bindings.alertInfo = AlertInfo(id: .alert,
@@ -120,7 +120,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
for member in members {
var verificationState: UserIdentityVerificationState = .notVerified
if roomProxy.isEncrypted, // We don't care about identity statuses on non-encrypted rooms
if roomProxy.infoPublisher.value.isEncrypted, // We don't care about identity statuses on non-encrypted rooms
case let .success(userIdentity) = await clientProxy.userIdentity(for: member.userID),
let userIdentity {
verificationState = userIdentity.verificationState
@@ -75,11 +75,14 @@ class RoomNotificationSettingsScreenViewModel: RoomNotificationSettingsScreenVie
}
private func fetchRoomNotificationSettings() async {
state.shouldDisplayMentionsOnlyDisclaimer = roomProxy.isEncrypted ? await !notificationSettingsProxy.canPushEncryptedEventsToDevice() : false
let isEncrypted = roomProxy.infoPublisher.value.isEncrypted
state.shouldDisplayMentionsOnlyDisclaimer = isEncrypted ? await !notificationSettingsProxy.canPushEncryptedEventsToDevice() : false
do {
// `isOneToOne` here is not the same as `isDirect` on the room. From the point of view of the push rule, a one-to-one room is a room with exactly two active members.
let settings = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
isEncrypted: roomProxy.isEncrypted,
isEncrypted: isEncrypted,
isOneToOne: roomProxy.infoPublisher.value.activeMembersCount == 2)
guard !Task.isCancelled else { return }
state.notificationSettingsState = .loaded(settings: settings)
@@ -73,7 +73,7 @@ struct ComposerToolbarViewState: BindableState {
var audioPlayerState: AudioPlayerState
var audioRecorderState: AudioRecorderState
let isRoomEncrypted: Bool
var isRoomEncrypted: Bool
var bindings: ComposerToolbarViewStateBindings
@@ -62,13 +62,18 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
mentionBuilder = MentionBuilder()
attributedStringBuilder = AttributedStringBuilder(cacheKey: "Composer", mentionBuilder: mentionBuilder)
super.init(initialViewState: ComposerToolbarViewState(audioPlayerState: .init(id: .recorderPreview,
title: L10n.commonVoiceMessage,
duration: 0),
super.init(initialViewState: ComposerToolbarViewState(audioPlayerState: .init(id: .recorderPreview, title: L10n.commonVoiceMessage, duration: 0),
audioRecorderState: .init(),
isRoomEncrypted: roomProxy.isEncrypted,
isRoomEncrypted: roomProxy.infoPublisher.value.isEncrypted,
bindings: .init()),
mediaProvider: mediaProvider)
roomProxy.infoPublisher
.map(\.isEncrypted)
.receive(on: DispatchQueue.main)
.removeDuplicates()
.weakAssign(to: \.state.isRoomEncrypted, on: self)
.store(in: &cancellables)
context.$viewState
.map(\.composerMode)
@@ -29,7 +29,7 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
self.userIndicatorController = userIndicatorController
super.init(initialViewState: SecurityAndPrivacyScreenViewState(serverName: clientProxy.userIDServerName ?? "",
accessType: roomProxy.infoPublisher.value.joinRule.toSecurityAndPrivacyRoomAccessType,
isEncryptionEnabled: roomProxy.isEncrypted,
isEncryptionEnabled: roomProxy.infoPublisher.value.isEncrypted,
historyVisibility: roomProxy.infoPublisher.value.historyVisibility.toSecurityAndPrivacyHistoryVisibility))
setupRoomDirectoryVisibility()
@@ -91,7 +91,8 @@ class AuthenticationService: AuthenticationServiceProtocol {
func urlForOIDCLogin() async -> Result<OIDCAuthorizationDataProxy, AuthenticationServiceError> {
guard let client else { return .failure(.oidcError(.urlFailure)) }
do {
let oidcData = try await client.urlForOidc(oidcConfiguration: appSettings.oidcConfiguration.rustValue, prompt: .consent)
let oidcData = try await client.urlForOidc(oidcConfiguration: appSettings.oidcConfiguration.rustValue,
prompt: .consent)
return .success(OIDCAuthorizationDataProxy(underlyingData: oidcData))
} catch {
MXLog.error("Failed to get URL for OIDC login: \(error)")
@@ -148,7 +148,7 @@ class ClientProxy: ClientProxyProtocol {
mediaLoader = MediaLoader(client: client)
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings())
notificationSettings = await NotificationSettingsProxy(notificationSettings: client.getNotificationSettings())
secureBackupController = SecureBackupController(encryption: client.encryption())
@@ -525,11 +525,11 @@ class ClientProxy: ClientProxyProtocol {
}
func roomSummaryForIdentifier(_ identifier: String) -> RoomSummary? {
staticRoomSummaryProvider.roomListPublisher.value.first(where: { $0.id == identifier })
staticRoomSummaryProvider.roomListPublisher.value.first { $0.id == identifier }
}
func roomSummaryForAlias(_ alias: String) -> RoomSummary? {
staticRoomSummaryProvider.roomListPublisher.value.first(where: { $0.canonicalAlias == alias || $0.alternativeAliases.contains(alias) })
staticRoomSummaryProvider.roomListPublisher.value.first { $0.canonicalAlias == alias || $0.alternativeAliases.contains(alias) }
}
func loadUserDisplayName() async -> Result<Void, ClientProxyError> {
@@ -806,16 +806,13 @@ class ClientProxy: ClientProxyProtocol {
private func loadUserAvatarURLFromCache() {
loadCachedAvatarURLTask = Task {
let urlString = await Task.dispatch(on: clientQueue) {
do {
return try self.client.cachedAvatarUrl()
} catch {
MXLog.error("Failed to look for the avatar url in the cache: \(error)")
return nil
}
do {
let urlString = try await self.client.cachedAvatarUrl()
guard !Task.isCancelled else { return }
self.userAvatarURLSubject.value = urlString.flatMap(URL.init)
} catch {
MXLog.error("Failed to look for the avatar url in the cache: \(error)")
}
guard !Task.isCancelled else { return }
self.userAvatarURLSubject.value = urlString.flatMap(URL.init)
}
}
@@ -70,7 +70,7 @@ class ElementCallWidgetDriver: WidgetCapabilitiesProvider, ElementCallWidgetDriv
return .failure(.roomInvalid)
}
let useEncryption = (try? room.isEncrypted()) ?? false
let useEncryption = await (try? room.latestEncryptionState() == .encrypted) ?? false
let widgetSettings: WidgetSettings
do {
@@ -100,10 +100,6 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
var ownUserID: String { room.ownUserId() }
var info: RoomInfoProxy { infoSubject.value }
var isEncrypted: Bool {
(try? room.isEncrypted()) ?? false
}
init(roomListService: RoomListServiceProtocol,
roomListItem: RoomListItemProtocol,
room: RoomProtocol) async throws {
@@ -116,6 +112,14 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
Task {
await updateMembers()
// Try to update the encryption state if it's unknown.
// This is an edge case as sliding sync should pass
// that information down to the room info on the rust side.
if room.encryptionState() == .unknown {
MXLog.error("The encryption state should almost always be known.")
_ = try? await room.latestEncryptionState()
}
}
}
@@ -142,7 +146,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
await subscribeToKnockRequests()
if isEncrypted { // This is actually blocking on the rust side and might make network requests
if infoPublisher.value.isEncrypted {
subscribeToIdentityStatusChanges()
}
}
@@ -42,6 +42,13 @@ struct RoomInfoProxy: BaseRoomInfoProxyProtocol {
return .room(id: id, name: displayName, avatarURL: avatarURL)
}
// Here we're assuming unknown rooms are unencrypted.
// Fortunately https://github.com/matrix-org/matrix-rust-sdk/pull/4778 makes that very much of an edge case and we
// also automatically start a `latestEncryptionState` fetch if needed.
// In the worst case, even if we are to assume a room is unencrypted, the SDK will still determine the correct
// state before any message is sent.
var isEncrypted: Bool { roomInfo.encryptionState == .encrypted }
var isDirect: Bool { roomInfo.isDirect }
var isPublic: Bool { roomInfo.isPublic }
var isSpace: Bool { roomInfo.isSpace }
@@ -63,8 +63,6 @@ enum KnockRequestsState {
// sourcery: AutoMockable
protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
var isEncrypted: Bool { get }
var infoPublisher: CurrentValuePublisher<RoomInfoProxy, Never> { get }
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
@@ -190,7 +188,7 @@ extension JoinedRoomProxyProtocol {
name: infoPublisher.value.displayName,
avatar: infoPublisher.value.avatar,
canonicalAlias: infoPublisher.value.canonicalAlias,
isEncrypted: isEncrypted,
isEncrypted: infoPublisher.value.isEncrypted,
isPublic: infoPublisher.value.isPublic,
isDirect: infoPublisher.value.isDirect)
}
@@ -30,7 +30,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate
windowManager.delegate = self
MXLog.configure(currentTarget: "uitests", filePrefix: nil, logLevel: .debug)
MXLog.configure(currentTarget: "uitests")
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())