mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:02:10 +00:00
Refactor Rageshake URL and Target configuration. (#4337)
* Move the rageshakeURL configuration from the BugReportService to AppSettings. * Refactor Target to return a handle when configuring. This helps with reconfiguration and removes the @MainActor constraint.
This commit is contained in:
@@ -18,6 +18,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
private let stateMachine: AppCoordinatorStateMachine
|
||||
private let navigationRootCoordinator: NavigationRootCoordinator
|
||||
private let userSessionStore: UserSessionStoreProtocol
|
||||
private let targetConfiguration: Target.Configuration
|
||||
private let appMediator: AppMediator
|
||||
private let appSettings: AppSettings
|
||||
private let appDelegate: AppDelegate
|
||||
@@ -74,9 +75,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
let appSettings = appHooks.appSettingsHook.configure(AppSettings())
|
||||
|
||||
Target.mainApp.configure(logLevel: appSettings.logLevel,
|
||||
traceLogPacks: appSettings.traceLogPacks,
|
||||
sentryURL: appSettings.bugReportSentryRustURL)
|
||||
targetConfiguration = Target.mainApp.configure(logLevel: appSettings.logLevel,
|
||||
traceLogPacks: appSettings.traceLogPacks,
|
||||
sentryURL: appSettings.bugReportSentryRustURL)
|
||||
|
||||
let appName = InfoPlistReader.main.bundleDisplayName
|
||||
let appVersion = InfoPlistReader.main.bundleShortVersionString
|
||||
@@ -372,7 +373,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
private static func setupServiceLocator(appSettings: AppSettings, appHooks: AppHooks) {
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
|
||||
ServiceLocator.shared.register(appSettings: appSettings)
|
||||
ServiceLocator.shared.register(bugReportService: BugReportService(rageshakeURL: appSettings.bugReportRageshakeURL,
|
||||
ServiceLocator.shared.register(bugReportService: BugReportService(rageshakeURLPublisher: appSettings.bugReportRageshakeURL.publisher,
|
||||
applicationID: appSettings.bugReportApplicationID,
|
||||
sdkGitSHA: sdkGitSha(),
|
||||
maxUploadSize: appSettings.bugReportMaxUploadSize,
|
||||
@@ -403,7 +404,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
}
|
||||
}
|
||||
|
||||
// This could be removed once the adotpion of 25.06.x is widespread.
|
||||
// This could be removed once the adoption of 25.06.x is widespread.
|
||||
private func performSettingsToAccountDataMigration(userSession: UserSessionProtocol) {
|
||||
guard let userDefaults = UserDefaults(suiteName: InfoPlistReader.main.appGroupIdentifier) else {
|
||||
return
|
||||
|
||||
+2
-3
@@ -65,7 +65,6 @@ final class AppSettings {
|
||||
}
|
||||
|
||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||
private static var remoteSuiteName = "\(InfoPlistReader.main.appGroupIdentifier).remote"
|
||||
|
||||
/// UserDefaults to be used on reads and writes.
|
||||
private static var store: UserDefaults! = UserDefaults(suiteName: suiteName)
|
||||
@@ -252,8 +251,8 @@ final class AppSettings {
|
||||
var pusherProfileTag: String?
|
||||
|
||||
// MARK: - Bug report
|
||||
|
||||
let bugReportRageshakeURL: URL? = Secrets.rageshakeURL.map { URL(string: $0)! } // swiftlint:disable:this force_unwrapping
|
||||
|
||||
let bugReportRageshakeURL: ConfigurableSetting<RageshakeConfiguration> = .init(Secrets.rageshakeURL.map { .url(URL(string: $0)!) } ?? .disabled) // swiftlint:disable:this force_unwrapping
|
||||
let bugReportSentryURL: URL? = Secrets.sentryDSN.map { URL(string: $0)! } // swiftlint:disable:this force_unwrapping
|
||||
let bugReportSentryRustURL: URL? = Secrets.sentryRustDSN.map { URL(string: $0)! } // swiftlint:disable:this force_unwrapping
|
||||
/// The name allocated by the bug report server
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright 2025 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 Combine
|
||||
|
||||
/// A setting that can be instantiated with an initial value, overridden and reset back again,
|
||||
/// automatically publishing the changes for downstream subscribers to react to.
|
||||
///
|
||||
/// Unlike ``UserPreference``, this type of setting isn't settable by the user, nor is the
|
||||
/// override persisted between app launches.
|
||||
struct ConfigurableSetting<T: Equatable> {
|
||||
private let initialValue: T
|
||||
private let subject: CurrentValueSubject<T, Never>
|
||||
var publisher: CurrentValuePublisher<T, Never> { subject.asCurrentValuePublisher() }
|
||||
var isOverridden: Bool { subject.value != initialValue }
|
||||
|
||||
init(_ initialValue: T) {
|
||||
self.initialValue = initialValue
|
||||
subject = .init(initialValue)
|
||||
}
|
||||
|
||||
func override(_ value: T) {
|
||||
subject.send(value)
|
||||
}
|
||||
|
||||
func reset() {
|
||||
if isOverridden {
|
||||
subject.send(initialValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,51 +8,42 @@
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
@MainActor
|
||||
enum Target: String {
|
||||
case mainApp = "elementx"
|
||||
case nse
|
||||
case shareExtension = "shareextension"
|
||||
case tests
|
||||
|
||||
private static var isConfigured = false
|
||||
|
||||
func configure(logLevel: LogLevel, traceLogPacks: Set<TraceLogPack>, sentryURL: URL?) {
|
||||
guard !Self.isConfigured else {
|
||||
return
|
||||
var useLightweightTokioRuntime: Bool {
|
||||
switch self {
|
||||
case .mainApp: false
|
||||
case .nse: true
|
||||
case .shareExtension: true
|
||||
case .tests: false
|
||||
}
|
||||
}
|
||||
|
||||
var logFilePrefix: String? {
|
||||
switch self {
|
||||
case .mainApp: nil
|
||||
default: rawValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Configures the target with logging and an appropriate runtime.
|
||||
///
|
||||
/// Returns a `Configuration` which should be stored to
|
||||
/// a) detect whether the platform is already configured.
|
||||
/// b) reconfigure the platform if necessary.
|
||||
func configure(logLevel: LogLevel, traceLogPacks: Set<TraceLogPack>, sentryURL: URL?) -> Configuration {
|
||||
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel,
|
||||
traceLogPacks: traceLogPacks,
|
||||
currentTarget: rawValue,
|
||||
filePrefix: logFilePrefix,
|
||||
sentryURL: sentryURL)
|
||||
|
||||
do {
|
||||
switch self {
|
||||
case .mainApp:
|
||||
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel,
|
||||
traceLogPacks: traceLogPacks,
|
||||
currentTarget: rawValue,
|
||||
filePrefix: nil,
|
||||
sentryURL: sentryURL)
|
||||
try initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: false)
|
||||
case .nse:
|
||||
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel,
|
||||
traceLogPacks: traceLogPacks,
|
||||
currentTarget: rawValue,
|
||||
filePrefix: rawValue,
|
||||
sentryURL: sentryURL)
|
||||
try initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: true)
|
||||
case .shareExtension:
|
||||
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel,
|
||||
traceLogPacks: traceLogPacks,
|
||||
currentTarget: rawValue,
|
||||
filePrefix: rawValue,
|
||||
sentryURL: sentryURL)
|
||||
try initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: true)
|
||||
case .tests:
|
||||
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel,
|
||||
traceLogPacks: traceLogPacks,
|
||||
currentTarget: rawValue,
|
||||
filePrefix: rawValue,
|
||||
sentryURL: sentryURL)
|
||||
try initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: false)
|
||||
}
|
||||
try initPlatform(config: tracingConfiguration, useLightweightTokioRuntime: useLightweightTokioRuntime)
|
||||
} catch {
|
||||
fatalError("Failed configuring target \(self) with error: \(error)")
|
||||
}
|
||||
@@ -63,6 +54,14 @@ enum Target: String {
|
||||
|
||||
MXLog.configure(currentTarget: rawValue)
|
||||
|
||||
Self.isConfigured = true
|
||||
return Configuration(tracingConfiguration: tracingConfiguration)
|
||||
}
|
||||
|
||||
/// Represents the configuration that was applied by ``configure(logLevel:traceLogPacks:sentryURL:)``.
|
||||
struct Configuration {
|
||||
/// The configuration applied when calling ``configure(logLevel:traceLogPacks:sentryURL:)``.
|
||||
///
|
||||
/// **Note:** This is immutable and won't be updated to reflect further changes.
|
||||
let tracingConfiguration: TracingConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1995,47 +1995,6 @@ class BugReportServiceMock: BugReportServiceProtocol, @unchecked Sendable {
|
||||
var underlyingCrashedLastRun: Bool!
|
||||
var lastCrashEventID: String?
|
||||
|
||||
//MARK: - applyConfiguration
|
||||
|
||||
var applyConfigurationUnderlyingCallsCount = 0
|
||||
var applyConfigurationCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return applyConfigurationUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = applyConfigurationUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
applyConfigurationUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
applyConfigurationUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var applyConfigurationCalled: Bool {
|
||||
return applyConfigurationCallsCount > 0
|
||||
}
|
||||
var applyConfigurationReceivedConfiguration: RageshakeConfiguration?
|
||||
var applyConfigurationReceivedInvocations: [RageshakeConfiguration] = []
|
||||
var applyConfigurationClosure: ((RageshakeConfiguration) -> Void)?
|
||||
|
||||
func applyConfiguration(_ configuration: RageshakeConfiguration) {
|
||||
applyConfigurationCallsCount += 1
|
||||
applyConfigurationReceivedConfiguration = configuration
|
||||
DispatchQueue.main.async {
|
||||
self.applyConfigurationReceivedInvocations.append(configuration)
|
||||
}
|
||||
applyConfigurationClosure?(configuration)
|
||||
}
|
||||
//MARK: - submitBugReport
|
||||
|
||||
var submitBugReportProgressListenerUnderlyingCallsCount = 0
|
||||
|
||||
@@ -185,13 +185,23 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
}
|
||||
|
||||
// We only set the analytics configuration if analytics are enabled
|
||||
let analyticsConfiguration = analyticsService.isEnabled ? ElementCallAnalyticsConfiguration(posthogAPIHost: appSettings.elementCallPosthogAPIHost,
|
||||
posthogAPIKey: appSettings.elementCallPosthogAPIKey,
|
||||
sentryDSN: appSettings.elementCallPosthogSentryDSN) : nil
|
||||
let analyticsConfiguration: ElementCallAnalyticsConfiguration? = if analyticsService.isEnabled {
|
||||
.init(posthogAPIHost: appSettings.elementCallPosthogAPIHost,
|
||||
posthogAPIKey: appSettings.elementCallPosthogAPIKey,
|
||||
sentryDSN: appSettings.elementCallPosthogSentryDSN)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
let rageshakeURL: String? = if case let .url(baseURL) = appSettings.bugReportRageshakeURL.publisher.value {
|
||||
baseURL.absoluteString
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
|
||||
switch await widgetDriver.start(baseURL: baseURL,
|
||||
clientID: clientID,
|
||||
colorScheme: colorScheme,
|
||||
rageshakeURL: appSettings.bugReportRageshakeURL?.absoluteString,
|
||||
rageshakeURL: rageshakeURL,
|
||||
analyticsConfiguration: analyticsConfiguration) {
|
||||
case .success(let url):
|
||||
state.url = url
|
||||
|
||||
@@ -12,10 +12,7 @@ import Sentry
|
||||
import UIKit
|
||||
|
||||
class BugReportService: NSObject, BugReportServiceProtocol {
|
||||
/// The rageshake URL as provided in the init.
|
||||
private let defaultRageshakeURL: URL?
|
||||
/// The rageshake URL currently being used by the service.
|
||||
private var rageshakeURL: URL?
|
||||
private var rageshakeURL: RageshakeConfiguration
|
||||
private let applicationID: String
|
||||
private let sdkGitSHA: String
|
||||
private let maxUploadSize: Int
|
||||
@@ -25,23 +22,27 @@ class BugReportService: NSObject, BugReportServiceProtocol {
|
||||
private let progressSubject = PassthroughSubject<Double, Never>()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
var isEnabled: Bool { rageshakeURL != nil }
|
||||
var isEnabled: Bool { rageshakeURL != .disabled }
|
||||
var lastCrashEventID: String?
|
||||
|
||||
init(rageshakeURL: URL?,
|
||||
init(rageshakeURLPublisher: CurrentValuePublisher<RageshakeConfiguration, Never>,
|
||||
applicationID: String,
|
||||
sdkGitSHA: String,
|
||||
maxUploadSize: Int,
|
||||
session: URLSession = .shared,
|
||||
appHooks: AppHooks) {
|
||||
defaultRageshakeURL = rageshakeURL
|
||||
self.rageshakeURL = rageshakeURL
|
||||
rageshakeURL = rageshakeURLPublisher.value
|
||||
self.applicationID = applicationID
|
||||
self.sdkGitSHA = sdkGitSHA
|
||||
self.maxUploadSize = maxUploadSize
|
||||
self.session = session
|
||||
self.appHooks = appHooks
|
||||
|
||||
super.init()
|
||||
|
||||
rageshakeURLPublisher
|
||||
.weakAssign(to: \.rageshakeURL, on: self)
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
// MARK: - BugReportServiceProtocol
|
||||
@@ -50,21 +51,10 @@ class BugReportService: NSObject, BugReportServiceProtocol {
|
||||
SentrySDK.crashedLastRun
|
||||
}
|
||||
|
||||
func applyConfiguration(_ configuration: RageshakeConfiguration) {
|
||||
switch configuration {
|
||||
case .url(let url):
|
||||
rageshakeURL = url
|
||||
case .disabled:
|
||||
rageshakeURL = nil
|
||||
case .default:
|
||||
rageshakeURL = defaultRageshakeURL
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
func submitBugReport(_ bugReport: BugReport,
|
||||
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
|
||||
guard let rageshakeURL else {
|
||||
guard case let .url(rageshakeURL) = rageshakeURL else {
|
||||
fatalError("No bug report URL set, the screen should not be shown in this case.")
|
||||
}
|
||||
|
||||
|
||||
@@ -46,13 +46,11 @@ enum BugReportServiceError: LocalizedError {
|
||||
}
|
||||
}
|
||||
|
||||
enum RageshakeConfiguration {
|
||||
enum RageshakeConfiguration: Equatable {
|
||||
/// Rageshakes should be sent to the provided URL
|
||||
case url(URL)
|
||||
/// Rageshakes are disabled.
|
||||
case disabled
|
||||
/// No customisations are made, use the default configuration.
|
||||
case `default`
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
@@ -62,8 +60,6 @@ protocol BugReportServiceProtocol: AnyObject {
|
||||
|
||||
var lastCrashEventID: String? { get set }
|
||||
|
||||
func applyConfiguration(_ configuration: RageshakeConfiguration)
|
||||
|
||||
func submitBugReport(_ bugReport: BugReport,
|
||||
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user