Add a TracingHook. (#4345)

This commit is contained in:
Doug
2025-07-23 14:29:31 +01:00
committed by GitHub
parent 5e165be8c3
commit 76e83462a8
16 changed files with 178 additions and 40 deletions
+5
View File
@@ -39,6 +39,11 @@ class AppHooks: AppHooksProtocol {
}
#endif
private(set) var tracingHook: TracingHookProtocol = DefaultTracingHook()
func registerTracingHook(_ hook: TracingHookProtocol) {
tracingHook = hook
}
private(set) var clientBuilderHook: ClientBuilderHookProtocol = DefaultClientBuilderHook()
func registerClientBuilderHook(_ hook: ClientBuilderHookProtocol) {
clientBuilderHook = hook
@@ -18,7 +18,7 @@ protocol RemoteSettingsHookProtocol {
func updateCache(using client: ClientProtocol) async
func reset(_ appSettings: CommonSettingsProtocol)
#endif
func loadCache(forHomeserver: String, applyingTo appSettings: CommonSettingsProtocol)
func loadCache(forHomeserver homeserver: String, applyingTo appSettings: CommonSettingsProtocol)
}
struct DefaultRemoteSettingsHook: RemoteSettingsHookProtocol {
@@ -51,7 +51,7 @@ struct DefaultRemoteSettingsHook: RemoteSettingsHookProtocol {
func reset(_ appSettings: any CommonSettingsProtocol) { }
#endif
func loadCache(forHomeserver: String, applyingTo appSettings: CommonSettingsProtocol) { }
func loadCache(forHomeserver homeserver: String, applyingTo appSettings: CommonSettingsProtocol) { }
}
private struct ElementWellKnown: Decodable {
@@ -0,0 +1,16 @@
//
// 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 MatrixRustSDK
protocol TracingHookProtocol {
func update(_ configuration: TracingConfiguration, with rageshakeURL: RemotePreference<RageshakeConfiguration>)
}
struct DefaultTracingHook: TracingHookProtocol {
func update(_ configuration: TracingConfiguration, with rageshakeURL: RemotePreference<RageshakeConfiguration>) { }
}
@@ -18,7 +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 targetConfiguration: Target.ConfigurationResult
private let appMediator: AppMediator
private let appSettings: AppSettings
private let appDelegate: AppDelegate
@@ -77,7 +77,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
targetConfiguration = Target.mainApp.configure(logLevel: appSettings.logLevel,
traceLogPacks: appSettings.traceLogPacks,
sentryURL: appSettings.bugReportSentryRustURL)
sentryURL: appSettings.bugReportSentryRustURL,
rageshakeURL: appSettings.bugReportRageshakeURL,
appHooks: appHooks)
let appName = InfoPlistReader.main.bundleDisplayName
let appVersion = InfoPlistReader.main.bundleShortVersionString
@@ -12,7 +12,7 @@ import Combine
///
/// Unlike ``UserPreference``, this type of setting isn't settable by the user, nor is the
/// remote value persisted between app launches.
struct RemotePreference<T: Equatable> {
class RemotePreference<T: Equatable> {
private let defaultValue: T
private let subject: CurrentValueSubject<T, Never>
var publisher: CurrentValuePublisher<T, Never> { subject.asCurrentValuePublisher() }
@@ -5,6 +5,7 @@
// Please see LICENSE files in the repository root for full details.
//
import Combine
import Foundation
import MatrixRustSDK
@@ -32,10 +33,14 @@ enum Target: String {
/// Configures the target with logging and an appropriate runtime.
///
/// Returns a `Configuration` which should be stored to
/// Returns a `ConfigurationResult` 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 {
/// b) automatically reconfigure the platform as necessary.
func configure(logLevel: LogLevel,
traceLogPacks: Set<TraceLogPack>,
sentryURL: URL?,
rageshakeURL: RemotePreference<RageshakeConfiguration>,
appHooks: AppHooks) -> ConfigurationResult {
let tracingConfiguration = Tracing.buildConfiguration(logLevel: logLevel,
traceLogPacks: traceLogPacks,
currentTarget: rawValue,
@@ -54,14 +59,21 @@ enum Target: String {
MXLog.configure(currentTarget: rawValue)
return Configuration(tracingConfiguration: tracingConfiguration)
let hookCancellable = rageshakeURL.publisher
.sink { _ in
appHooks.tracingHook.update(tracingConfiguration, with: rageshakeURL)
}
return ConfigurationResult(hookCancellable: hookCancellable)
}
/// 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
/// The result of calling ``configure(logLevel:traceLogPacks:sentryURL:)``.
/// This must be stored - see the docs on the configure method to learn more.
struct ConfigurationResult {
private let hookCancellable: AnyCancellable
init(hookCancellable: AnyCancellable) {
self.hookCancellable = hookCancellable
}
}
}
@@ -42,6 +42,7 @@ extension ClientSDKMock {
slidingSyncVersionReturnValue = configuration.slidingSyncVersion
userIdServerNameThrowableError = MockError.generic
serverReturnValue = "https://\(configuration.serverAddress)"
homeserverReturnValue = configuration.homeserverURL
urlForOidcOidcConfigurationPromptLoginHintDeviceIdReturnValue = OAuthAuthorizationDataSDKMock(configuration: configuration)
loginUsernamePasswordInitialDeviceNameDeviceIdClosure = { username, password, _, _ in
guard username == configuration.validCredentials.username,
+41 -17
View File
@@ -7,15 +7,9 @@
import Foundation
extension URL: @retroactive ExpressibleByStringLiteral {
public init(stringLiteral value: StaticString) {
guard let url = URL(string: "\(value)") else {
fatalError("The static string used to create this URL is invalid")
}
self = url
}
// MARK: - Custom URLs
extension URL {
/// The URL of the primary app group container.
static var appGroupContainerDirectory: URL {
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: InfoPlistReader.main.appGroupIdentifier) else {
@@ -104,6 +98,45 @@ extension URL: @retroactive ExpressibleByStringLiteral {
return nil
}
// MARK: Mocks
static var mockMXCAudio: URL { "mxc://matrix.org/1234567890AuDiO" }
static var mockMXCFile: URL { "mxc://matrix.org/1234567890FiLe" }
static var mockMXCImage: URL { "mxc://matrix.org/1234567890ImAgE" }
static var mockMXCVideo: URL { "mxc://matrix.org/1234567890ViDeO" }
static var mockMXCAvatar: URL { "mxc://matrix.org/1234567890AvAtAr" }
static var mockMXCUserAvatar: URL { "mxc://matrix.org/1234567890AvAtArUsEr" }
}
// MARK: - Helpers
extension URL: @retroactive ExpressibleByStringLiteral {
public init(stringLiteral value: StaticString) {
guard let url = URL(string: "\(value)") else {
fatalError("The static string used to create this URL is invalid")
}
self = url
}
/// Sanitises the URL for use as the name of a directory.
func asDirectoryName() -> String {
absoluteString.asURLDirectoryName()
}
}
extension String {
/// Assumes that the string is a URL and sanitises it for use as the name of a directory.
func asURLDirectoryName() -> String {
replacingOccurrences(of: "https://", with: "")
.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
.replacing(/[:\/\p{C}]/, with: "-")
}
}
// MARK: - Phishing Confirmation URL
extension URL {
static let confirmationScheme = "confirm"
var requiresConfirmation: Bool {
@@ -117,15 +150,6 @@ extension URL: @retroactive ExpressibleByStringLiteral {
}
return ConfirmURLParameters(queryItems: queryItems)
}
// MARK: Mocks
static var mockMXCAudio: URL { "mxc://matrix.org/1234567890AuDiO" }
static var mockMXCFile: URL { "mxc://matrix.org/1234567890FiLe" }
static var mockMXCImage: URL { "mxc://matrix.org/1234567890ImAgE" }
static var mockMXCVideo: URL { "mxc://matrix.org/1234567890ViDeO" }
static var mockMXCAvatar: URL { "mxc://matrix.org/1234567890AvAtAr" }
static var mockMXCUserAvatar: URL { "mxc://matrix.org/1234567890AvAtArUsEr" }
}
struct ConfirmURLParameters {