Add a TracingHook. (#4345)

This commit is contained in:
Doug
2025-07-23 14:29:31 +01:00
committed by GitHub
parent b7867dac85
commit ee9f055822
16 changed files with 178 additions and 40 deletions

View File

@@ -254,6 +254,7 @@
2D0E3983288E2D35613AD681 /* SecureBackupControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AB29A2D95D3469B5F016655 /* SecureBackupControllerMock.swift */; };
2D2D8A53B35BE8D8A01449C6 /* PinnedEventsBannerStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FA38E813BE14149F173F461 /* PinnedEventsBannerStateTests.swift */; };
2D38D39B1789B91AE69F477F /* PhotoLibraryManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD955A0380C287C418F1A74D /* PhotoLibraryManagerMock.swift */; };
2D45A04699BB6BA3B3A0CB9A /* TracingHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */; };
2DA27D78560D5F79B917E163 /* AudioConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E44E35AA87F49503E7B3BF6E /* AudioConverter.swift */; };
2DD9D0FE7CB5CFC80D071451 /* AppLockScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C3E67E09FE5A35D73818C39 /* AppLockScreenModels.swift */; };
2E43A3D221BE9587BC19C3F1 /* MatrixEntityRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */; };
@@ -391,6 +392,7 @@
494970EA811FE4D93AC68482 /* SettingsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FE8A35B4AD5256F4B562274 /* SettingsScreenViewModelTests.swift */; };
4949C8C12669D1B5E082366E /* QRCodeLoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA9EA59D5C0DA1BFC7B3621 /* QRCodeLoginScreen.swift */; };
49500BBA1CD65A5AE252D970 /* RoomDirectorySearchScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41BB37D96C3EA18F3CE8675D /* RoomDirectorySearchScreenModels.swift */; };
49BBEC46D523BF6A41400048 /* URLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB34956C87731AB094DB33A /* URLTests.swift */; };
4A4110369DBB79E4A314F415 /* ComposerToolbarViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0618820D26F9871A4BBB40E /* ComposerToolbarViewModelProtocol.swift */; };
4A618590DEB72C4F186BFED4 /* UserSessionFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C99FDEEB71173C4C6FA2734C /* UserSessionFlowCoordinator.swift */; };
4A8287E5281B44A8754BE509 /* SessionVerificationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */; };
@@ -434,6 +436,7 @@
50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; };
5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; };
510C4EDF826CA9C6CEEC6C95 /* ManageRoomMemberSheetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A34D9BCA1A7D9A56E1EAF1D /* ManageRoomMemberSheetViewModel.swift */; };
51263FC33CC961A14F5D6BCA /* TracingHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */; };
5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */; };
513AF15E0E84711B80D04B1B /* ReportRoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3E9684DCE6B66BD0B5DF67 /* ReportRoomScreenViewModelTests.swift */; };
51B3B19FA5F91B455C807BA7 /* RoomPollsHistoryScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E964AF2DFEB31E2B799999F /* RoomPollsHistoryScreenModels.swift */; };
@@ -1159,6 +1162,7 @@
DF8F1211F2B0B56F0FCCA5C2 /* CertificateValidatorHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3865AD7B7249C939D7C69C33 /* CertificateValidatorHook.swift */; };
DFD5AA8688A34C72D48AF3B1 /* StaticLocationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5311C989EC15B4C2D699025 /* StaticLocationScreenViewModel.swift */; };
DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; };
E010DDE938032D3B8E84CC35 /* TracingHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */; };
E0B6A569AC3E81D233B43D60 /* SettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E625B0EB2F86B37C14EF7E6 /* SettingsScreenViewModel.swift */; };
E0C167D41A48EDB30B447DE3 /* VoiceMessageRecordingComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A5C3F7C9C1DA10CAEC6A98 /* VoiceMessageRecordingComposer.swift */; };
E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE52983FAFB4E0998C00EE8A /* CancellableTask.swift */; };
@@ -1650,6 +1654,7 @@
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
2A2BB38DF61F5100B8723112 /* TimelineMediaPreviewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewModels.swift; sourceTree = "<group>"; };
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingHook.swift; sourceTree = "<group>"; };
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenViewModelTests.swift; sourceTree = "<group>"; };
2AE807361805463F5AEDD1CA /* VoiceMessagePreviewComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessagePreviewComposer.swift; sourceTree = "<group>"; };
@@ -1720,6 +1725,7 @@
39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerMock.swift; sourceTree = "<group>"; };
3A12D3D8138F1B71AFA7C858 /* CompletionSuggestionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionService.swift; sourceTree = "<group>"; };
3A21027F05874B1BCC3E452B /* InvitedRoomProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitedRoomProxyMock.swift; sourceTree = "<group>"; };
3AB34956C87731AB094DB33A /* URLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLTests.swift; sourceTree = "<group>"; };
3AD253E7EFF88F308D644272 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/SAS.strings"; sourceTree = "<group>"; };
3B5E97E9615A158C76B2AB77 /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = "<group>"; };
3B927A399A5418DA40A5CA15 /* StartChatScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenTests.swift; sourceTree = "<group>"; };
@@ -3306,6 +3312,7 @@
8B89D6C760E8CAE29CA28FB1 /* CompoundHook.swift */,
D5D186A6DB8FAC5C9D0E4D61 /* RemoteSettingsHook.swift */,
B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */,
2A95C9B8299A36A6495DECA6 /* TracingHook.swift */,
);
path = Hooks;
sourceTree = "<group>";
@@ -4479,6 +4486,7 @@
5C1F000589F2CEE6B03ECFAB /* TimelineMediaPreviewViewModelTests.swift */,
6509708F54FC883604DFDC95 /* TimelineViewModelTests.swift */,
76310030C831D4610A705603 /* URLComponentsTests.swift */,
3AB34956C87731AB094DB33A /* URLTests.swift */,
EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */,
2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */,
BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */,
@@ -6976,6 +6984,7 @@
CE4B342F9DD747CF4BEDB5AB /* TestablePreview.swift in Sources */,
AC3C3D6D4AD31F13EE987390 /* TraceLogPack.swift in Sources */,
B81840E45D8746A4692DA774 /* Tracing.swift in Sources */,
2D45A04699BB6BA3B3A0CB9A /* TracingHook.swift in Sources */,
DDB47D29C6865669288BF87C /* UIFont+AttributedStringBuilder.m in Sources */,
45D6DC594816288983627484 /* UITestsScreenIdentifier.swift in Sources */,
281BED345D59A9A6A99E9D98 /* UNNotificationContent.swift in Sources */,
@@ -7109,6 +7118,7 @@
8E650379587C31D7912ED67B /* UNNotification+Creator.swift in Sources */,
AF33B9044498211C3D82F1E1 /* UNTextInputNotificationResponse+Creator.swift in Sources */,
20C16A3F718802B0E4A19C83 /* URLComponentsTests.swift in Sources */,
49BBEC46D523BF6A41400048 /* URLTests.swift in Sources */,
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */,
E313BDD2B8813144139B2E00 /* UserDiscoveryServiceTest.swift in Sources */,
A1DF0E1E526A981ED6D5DF44 /* UserIndicatorControllerTests.swift in Sources */,
@@ -7163,6 +7173,7 @@
6E03A710799E6C65C0AB36BC /* TargetConfiguration.swift in Sources */,
A5FD8284744E2FECFC842FC1 /* TraceLogPack.swift in Sources */,
89DF67AECBF9D0EE0DDB7737 /* Tracing.swift in Sources */,
51263FC33CC961A14F5D6BCA /* TracingHook.swift in Sources */,
03BD83E8BDD23AE059802E0D /* UITestsScreenIdentifier.swift in Sources */,
26252AA9AED64010788F4C26 /* UIView.swift in Sources */,
66E9202BED03B5BB00E812A1 /* URL.swift in Sources */,
@@ -8032,6 +8043,7 @@
B3D8AA9988F8A000B162DCB5 /* TombstonedAvatarImage.swift in Sources */,
6E44638FDF7D4B0F80EFA7EA /* TraceLogPack.swift in Sources */,
126CBCF5B0145FA1377C1316 /* Tracing.swift in Sources */,
E010DDE938032D3B8E84CC35 /* TracingHook.swift in Sources */,
298F9EC30E918F12AB7F1EE8 /* TypingIndicatorView.swift in Sources */,
36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */,
A37EED79941AD3B7140B3822 /* UIDevice.swift in Sources */,

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

View File

@@ -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 {

View File

@@ -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>) { }
}

View File

@@ -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

View File

@@ -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() }

View File

@@ -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
}
}
}

View File

@@ -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,

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 {

View File

@@ -5,6 +5,7 @@
// Please see LICENSE files in the repository root for full details.
//
import Combine
import MatrixRustSDK
import UserNotifications
@@ -28,7 +29,7 @@ import UserNotifications
// notification.
class NotificationServiceExtension: UNNotificationServiceExtension {
private static var targetConfiguration: Target.Configuration?
private static var targetConfiguration: Target.ConfigurationResult?
private let settings: CommonSettingsProtocol = AppSettings()
private let appHooks: AppHooks
@@ -36,6 +37,8 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
private let keychainController = KeychainController(service: .sessions,
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
private var cancellables: Set<AnyCancellable> = []
// We can make the whole NSE a MainActor after https://github.com/swiftlang/swift-evolution/blob/main/proposals/0371-isolated-synchronous-deinit.md
// otherwise we wouldn't be able to log the tag in the deinit.
deinit {
@@ -50,8 +53,12 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
if Self.targetConfiguration == nil {
Self.targetConfiguration = Target.nse.configure(logLevel: settings.logLevel,
traceLogPacks: settings.traceLogPacks,
sentryURL: nil)
sentryURL: nil,
rageshakeURL: settings.bugReportRageshakeURL,
appHooks: appHooks)
}
super.init()
}
override func didReceive(_ request: UNNotificationRequest,

View File

@@ -81,6 +81,7 @@ targets:
- path: ../Sources
- path: ../SupportingFiles
- path: ../../ElementX/Sources/AppHooks/AppHooks.swift
- path: ../../ElementX/Sources/AppHooks/Hooks/TracingHook.swift
- path: ../../ElementX/Sources/AppHooks/Hooks/ClientBuilderHook.swift
- path: ../../ElementX/Sources/AppHooks/Hooks/RemoteSettingsHook.swift
- path: ../../Secrets/Secrets.swift

View File

@@ -5,17 +5,20 @@
// Please see LICENSE files in the repository root for full details.
//
import Combine
import IntentsUI
import SwiftUI
class ShareExtensionViewController: UIViewController {
private static var targetConfiguration: Target.Configuration?
private static var targetConfiguration: Target.ConfigurationResult?
private let appSettings: CommonSettingsProtocol = AppSettings()
private var appHooks: AppHooks!
private let keychainController = KeychainController(service: .sessions,
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
private var cancellables: Set<AnyCancellable> = []
private let hostingController = UIHostingController(rootView: ShareExtensionView())
override func viewDidLoad() {
@@ -27,7 +30,9 @@ class ShareExtensionViewController: UIViewController {
if Self.targetConfiguration == nil {
Self.targetConfiguration = Target.shareExtension.configure(logLevel: appSettings.logLevel,
traceLogPacks: appSettings.traceLogPacks,
sentryURL: nil)
sentryURL: nil,
rageshakeURL: appSettings.bugReportRageshakeURL,
appHooks: appHooks)
}
addChild(hostingController)

View File

@@ -81,6 +81,7 @@ targets:
- path: ../SupportingFiles
- path: ../../ElementX/Sources/ShareExtension
- path: ../../ElementX/Sources/AppHooks/AppHooks.swift
- path: ../../ElementX/Sources/AppHooks/Hooks/TracingHook.swift
- path: ../../ElementX/Sources/AppHooks/Hooks/ClientBuilderHook.swift
- path: ../../ElementX/Sources/AppHooks/Hooks/RemoteSettingsHook.swift
- path: ../../Secrets/Secrets.swift

View File

@@ -10,7 +10,7 @@
import XCTest
class LoggingTests: XCTestCase {
static var targetConfiguration: Target.Configuration?
static var targetConfiguration: Target.ConfigurationResult?
private enum Constants {
static let genericFailure = "Test failed"
@@ -25,7 +25,11 @@ class LoggingTests: XCTestCase {
XCTAssertTrue(Tracing.logFiles.isEmpty)
if Self.targetConfiguration == nil {
Self.targetConfiguration = Target.tests.configure(logLevel: .info, traceLogPacks: [], sentryURL: nil)
Self.targetConfiguration = Target.tests.configure(logLevel: .info,
traceLogPacks: [],
sentryURL: nil,
rageshakeURL: ServiceLocator.shared.settings.bugReportRageshakeURL,
appHooks: AppHooks())
}
// There is something weird with Rust logging where the file writing handle doesn't
@@ -180,7 +184,11 @@ class LoggingTests: XCTestCase {
// When logging that value
if Self.targetConfiguration == nil {
Self.targetConfiguration = Target.tests.configure(logLevel: .info, traceLogPacks: [], sentryURL: nil)
Self.targetConfiguration = Target.tests.configure(logLevel: .info,
traceLogPacks: [],
sentryURL: nil,
rageshakeURL: ServiceLocator.shared.settings.bugReportRageshakeURL,
appHooks: AppHooks())
}
MXLog.info(textMessage)

View File

@@ -0,0 +1,44 @@
//
// 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 XCTest
@testable import ElementX
class URLTests: XCTestCase {
func testURLDirectoryName() {
let url: URL = "https://matrix.example.com/foo/bar/"
let directoryName = url.asDirectoryName()
XCTAssertEqual(directoryName, "matrix.example.com-foo-bar")
createDirectory(with: directoryName)
}
func testComplexURLDirectoryName() {
let url: URL = "https://us%3Aer:pa%40%3Ass@[2001:db8:85a3::8a2e:370:7334]:8443/..//folder/./fi%20le(1).html;p=1;q=2"
let directoryName = url.asDirectoryName()
XCTAssertEqual(directoryName, "us%3Aer-pa%40%3Ass@[2001-db8-85a3--8a2e-370-7334]-8443-..--folder-.-fi%20le(1).html;p=1;q=2")
createDirectory(with: directoryName)
}
// MARK: - Helpers
func createDirectory(with directoryName: String) {
let url = URL.temporaryDirectory.appending(path: directoryName)
try? FileManager.default.removeItem(at: url)
do {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
} catch {
XCTFail("Invalid file path: \(error.localizedDescription)")
}
guard FileManager.default.directoryExists(at: url) else {
XCTFail("Invalid file path")
return
}
}
}