Skip to content

Commit

Permalink
Hardcode the sliding sync proxy. (#502)
Browse files Browse the repository at this point in the history
* Add support for migrating between versions.
* Rename InfoPlistReader property.
* Bump SDK version.
  • Loading branch information
pixlwave authored Jan 31, 2023
1 parent 4f8cc08 commit f6629e0
Show file tree
Hide file tree
Showing 31 changed files with 143 additions and 99 deletions.
65 changes: 41 additions & 24 deletions ElementX.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
"state" : {
"revision" : "f6b5ccd904da60ccf39f41161c7db19e87b09870",
"version" : "1.0.35-alpha"
"revision" : "f001ac9e4b72647a2b5a9f3f210d72384915164f",
"version" : "1.0.36-alpha"
}
},
{
Expand Down Expand Up @@ -152,6 +152,15 @@
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
"version" : "1.9.6"
}
},
{
"identity" : "version",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mxcl/Version",
"state" : {
"revision" : "1fe824b80d89201652e7eca7c9252269a1d85e25",
"version" : "2.0.1"
}
}
],
"version" : 2
Expand Down
37 changes: 32 additions & 5 deletions ElementX/Sources/Application/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import Combine
import MatrixRustSDK
import SwiftUI
import Version

class AppCoordinator: AppCoordinatorProtocol {
private let stateMachine: AppCoordinatorStateMachine
Expand Down Expand Up @@ -66,12 +67,17 @@ class AppCoordinator: AppCoordinatorProtocol {

userSessionStore = UserSessionStore(backgroundTaskService: backgroundTaskService)

// Reset everything if the app has been deleted since the previous run
if !ServiceLocator.shared.settings.hasAppLaunchedOnce {
AppSettings.reset()
userSessionStore.reset()
ServiceLocator.shared.settings.hasAppLaunchedOnce = true
guard let currentVersion = Version(InfoPlistReader(bundle: .main).bundleShortVersionString) else {
fatalError("The app's version number **must** use semver for migration purposes.")
}

if let previousVersion = ServiceLocator.shared.settings.lastVersionLaunched.flatMap(Version.init) {
performMigrationsIfNecessary(from: previousVersion, to: currentVersion)
} else {
// The app has been deleted since the previous run. Reset everything.
wipeUserData(includingSettings: true)
}
ServiceLocator.shared.settings.lastVersionLaunched = currentVersion.description

setupStateMachine()

Expand Down Expand Up @@ -126,6 +132,27 @@ class AppCoordinator: AppCoordinatorProtocol {
MXLog.configure(loggerConfiguration)
}

/// Perform any required migrations for the app to function correctly.
private func performMigrationsIfNecessary(from oldVersion: Version, to newVersion: Version) {
guard oldVersion != newVersion else { return }

if oldVersion < Version(1, 0, 17) {
// Version 1.0.17 hardcoded a new sliding sync proxy for matrix.org
// Force a sign out for the user to log in with the new proxy.
MXLog.warning("Clearing user data for hardcoded proxy.")
wipeUserData()
}
}

/// Clears the keychain, app support directory etc ready for a fresh use.
/// - Parameter includingSettings: Whether to additionally wipe the user's app settings too.
private func wipeUserData(includingSettings: Bool = false) {
if includingSettings {
AppSettings.reset()
}
userSessionStore.reset()
}

// swiftlint:disable:next cyclomatic_complexity
private func setupStateMachine() {
stateMachine.addTransitionHandler { [weak self] context in
Expand Down
32 changes: 17 additions & 15 deletions ElementX/Sources/Application/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import SwiftUI
/// Store Element specific app settings.
final class AppSettings: ObservableObject {
private enum UserDefaultsKeys: String {
case hasAppLaunchedOnce
case lastVersionLaunched
case timelineStyle
case enableAnalytics
case isIdentifiedForAnalytics
Expand All @@ -29,7 +29,7 @@ final class AppSettings: ObservableObject {
case pusherProfileTag
}

private static var suiteName: String = InfoPlistReader.target.appGroupIdentifier
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier

/// UserDefaults to be used on reads and writes.
private static var store: UserDefaults! = UserDefaults(suiteName: suiteName)
Expand All @@ -50,20 +50,27 @@ final class AppSettings: ObservableObject {

// MARK: - Application

/// Simple flag to check if app has been deleted between runs.
/// Used to clear data stored in the shared container and keychain
@AppStorage(UserDefaultsKeys.hasAppLaunchedOnce.rawValue, store: store)
var hasAppLaunchedOnce = false
/// The last known version of the app that was launched on this device, which is
/// used to detect when migrations should be run. When `nil` the app may have been
/// deleted between runs so should clear data in the shared container and keychain.
@AppStorage(UserDefaultsKeys.lastVersionLaunched.rawValue, store: store)
var lastVersionLaunched: String?

/// The default homeserver address used. This is intentionally a string without a scheme
/// so that it can be passed to Rust as a ServerName for well-known discovery.
let defaultHomeserverAddress = "matrix.org"

/// An override of the homeserver's Sliding Sync proxy URL. This allows development against servers
/// that don't yet have an officially trusted proxy configured in their well-known.
let slidingSyncProxyURL = URL(staticString: "https://slidingsync.lab.matrix.org")

// MARK: - Notifications

var pusherAppId: String {
#if DEBUG
InfoPlistReader.target.baseBundleIdentifier + ".ios.dev"
InfoPlistReader.main.baseBundleIdentifier + ".ios.dev"
#else
InfoPlistReader.target.baseBundleIdentifier + ".ios.prod"
InfoPlistReader.main.baseBundleIdentifier + ".ios.prod"
#endif
}

Expand All @@ -84,14 +91,14 @@ final class AppSettings: ObservableObject {
#if DEBUG
/// The configuration to use for analytics during development. Set `isEnabled` to false to disable analytics in debug builds.
/// **Note:** Analytics are disabled by default for forks. If you are maintaining a fork, set custom configurations.
let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.target.bundleIdentifier.starts(with: "io.element.elementx"),
let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.main.bundleIdentifier.starts(with: "io.element.elementx"),
host: "https://posthog.element.dev",
apiKey: "phc_VtA1L35nw3aeAtHIx1ayrGdzGkss7k1xINeXcoIQzXN",
termsURL: URL(staticString: "https://element.io/cookie-policy"))
#else
/// The configuration to use for analytics. Set `isEnabled` to false to disable analytics.
/// **Note:** Analytics are disabled by default for forks. If you are maintaining a fork, set custom configurations.
let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.target.bundleIdentifier.starts(with: "io.element.elementx"),
let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.main.bundleIdentifier.starts(with: "io.element.elementx"),
host: "https://posthog.hss.element.io",
apiKey: "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
termsURL: URL(staticString: "https://element.io/cookie-policy"))
Expand All @@ -117,11 +124,6 @@ final class AppSettings: ObservableObject {
@AppStorage(UserDefaultsKeys.timelineStyle.rawValue, store: store)
var timelineStyle = TimelineStyle.bubbles

// MARK: - Client

@AppStorage(UserDefaultsKeys.slidingSyncProxyBaseURLString.rawValue, store: store)
var slidingSyncProxyBaseURLString = "https://slidingsync.lab.element.dev"

// MARK: - Notifications

@AppStorage(UserDefaultsKeys.enableInAppNotifications.rawValue, store: store)
Expand Down
2 changes: 1 addition & 1 deletion ElementX/Sources/Other/Extensions/UIDevice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ extension UIDevice {
}

var initialDisplayName: String {
ElementL10n.defaultSessionDisplayName(InfoPlistReader.target.bundleDisplayName)
ElementL10n.defaultSessionDisplayName(InfoPlistReader.main.bundleDisplayName)
}
}
4 changes: 2 additions & 2 deletions ElementX/Sources/Other/Extensions/URL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension URL {

/// The URL of the primary app group container.
static var appGroupContainerDirectory: URL {
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: InfoPlistReader.target.appGroupIdentifier) else {
guard let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: InfoPlistReader.main.appGroupIdentifier) else {
fatalError("Should always be able to retrieve the container directory")
}
return url
Expand Down Expand Up @@ -64,7 +64,7 @@ extension URL {
var url = appGroupContainerDirectory
.appendingPathComponent("Library", isDirectory: true)
.appendingPathComponent("Application Support", isDirectory: true)
.appendingPathComponent(InfoPlistReader.target.baseBundleIdentifier, isDirectory: true)
.appendingPathComponent(InfoPlistReader.main.baseBundleIdentifier, isDirectory: true)

try? FileManager.default.createDirectoryIfNeeded(at: url)

Expand Down
4 changes: 2 additions & 2 deletions ElementX/Sources/Other/InfoPlistReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ struct InfoPlistReader {
static let bundleDisplayName = "CFBundleDisplayName"
}

/// Info.plist reader on the current target
static let target = InfoPlistReader(bundle: .main)
/// Info.plist reader on the bundle object that contains the current executable.
static let main = InfoPlistReader(bundle: .main)

private let bundle: Bundle

Expand Down
6 changes: 3 additions & 3 deletions ElementX/Sources/Other/Logging/MXLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ class MXLogger {
MXLogger.logCrashes(false)

// Extract running app information
let app = InfoPlistReader.target.bundleExecutable
let appId = InfoPlistReader.target.bundleIdentifier
let appVersion = "\(InfoPlistReader.target.bundleShortVersionString) (r\(InfoPlistReader.target.bundleVersion))"
let app = InfoPlistReader.main.bundleExecutable
let appId = InfoPlistReader.main.bundleIdentifier
let appVersion = "\(InfoPlistReader.main.bundleShortVersionString) (r\(InfoPlistReader.main.bundleVersion))"

// Build the crash log
let model = UIDevice.current.model
Expand Down
4 changes: 2 additions & 2 deletions ElementX/Sources/Other/UserAgentBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ final class UserAgentBuilder {
}

private class func makeUserAgent() -> String? {
let clientName = InfoPlistReader.target.bundleDisplayName
let clientVersion = InfoPlistReader.target.bundleShortVersionString
let clientName = InfoPlistReader.main.bundleDisplayName
let clientVersion = InfoPlistReader.main.bundleShortVersionString

#if os(iOS)
return String(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ struct AnalyticsPromptStrings {
init() {
// Create the opt in content with a placeholder.
let linkPlaceholder = "{link}"
var optInContent = AttributedString(ElementL10n.analyticsOptInContent(InfoPlistReader.target.bundleDisplayName, linkPlaceholder))
var optInContent = AttributedString(ElementL10n.analyticsOptInContent(InfoPlistReader.main.bundleDisplayName, linkPlaceholder))

guard let range = optInContent.range(of: linkPlaceholder) else {
self.optInContent = AttributedString(ElementL10n.analyticsOptInContent(InfoPlistReader.target.bundleDisplayName,
self.optInContent = AttributedString(ElementL10n.analyticsOptInContent(InfoPlistReader.main.bundleDisplayName,
ElementL10n.analyticsOptInContentLink))
MXLog.failure("Failed to add a link attribute to the opt in content.")
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct AnalyticsPrompt: View {
Image(uiImage: Asset.Images.analyticsLogo.image)
.padding(.bottom, 25)

Text(ElementL10n.analyticsOptInTitle(InfoPlistReader.target.bundleDisplayName))
Text(ElementL10n.analyticsOptInTitle(InfoPlistReader.main.bundleDisplayName))
.font(.element.title2Bold)
.multilineTextAlignment(.center)
.foregroundColor(.element.primaryContent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct LoginScreen: View {
LoginServerInfoSection(address: context.viewState.homeserver.address) {
context.send(viewAction: .selectServer)
}
.disabled(true) // The button is disabled for this demo.
}

/// The form with text fields for username and password, along with a submit button.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct LoginServerInfoSection: View {
Image(systemName: "chevron.right")
.foregroundColor(.element.tertiaryContent)
.padding(.trailing, 16)
.hidden() // The button is disabled for this demo.
}
.background(RoundedRectangle(cornerRadius: 14).fill(Color.element.system))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ struct ServerSelectionViewState: BindableState {
struct ServerSelectionBindings {
/// The homeserver address input by the user.
var homeserverAddress: String
/// The sliding sync proxy address input by the user.
var slidingSyncProxyAddress: String
/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<ServerSelectionErrorType>?
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
var callback: (@MainActor (ServerSelectionViewModelAction) -> Void)?

init(homeserverAddress: String, isModallyPresented: Bool) {
let bindings = ServerSelectionBindings(homeserverAddress: homeserverAddress,
slidingSyncProxyAddress: ServiceLocator.shared.settings.slidingSyncProxyBaseURLString)
let bindings = ServerSelectionBindings(homeserverAddress: homeserverAddress)

super.init(initialViewState: ServerSelectionViewState(bindings: bindings,
isModallyPresented: isModallyPresented))
Expand All @@ -32,11 +31,6 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
override func process(viewAction: ServerSelectionViewAction) async {
switch viewAction {
case .confirm:
if !state.bindings.slidingSyncProxyAddress.isEmpty,
state.bindings.slidingSyncProxyAddress != ServiceLocator.shared.settings.slidingSyncProxyBaseURLString {
ServiceLocator.shared.settings.slidingSyncProxyBaseURLString = state.bindings.slidingSyncProxyAddress
}

callback?(.confirm(homeserverAddress: state.bindings.homeserverAddress))
case .dismiss:
callback?(.dismiss)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,6 @@ struct ServerSelectionScreen: View {
.onSubmit(submit)
.accessibilityIdentifier("addressTextField")

TextField(ElementL10n.ftueAuthChooseServerEntryHint, text: $context.slidingSyncProxyAddress)
.textFieldStyle(.elementInput(labelText: "Sliding sync proxy URL"))
.keyboardType(.URL)
.autocapitalization(.none)
.disableAutocorrection(true)
.submitLabel(.done)
.onSubmit(submit)
.accessibilityIdentifier("slidingSyncProxyAddressTextField")
.padding(.bottom, 8)

Button(action: submit) {
Text(context.viewState.buttonTitle)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct OnboardingViewState: BindableState {
init() {
content = [
OnboardingPageContent(title: ElementL10n.ftueAuthCarouselWelcomeTitle.tinting(".", color: .element.accent),
message: ElementL10n.ftueAuthCarouselWelcomeBody(InfoPlistReader.target.bundleDisplayName),
message: ElementL10n.ftueAuthCarouselWelcomeBody(InfoPlistReader.main.bundleDisplayName),
image: Asset.Images.onboardingAppLogo)
]
bindings = OnboardingBindings()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct InviteFriendsCoordinator: CoordinatorProtocol {
guard let permalink = try? PermalinkBuilder.permalinkTo(userIdentifier: userId).absoluteString else {
return AnyView(EmptyView())
}
let shareText = ElementL10n.inviteFriendsText(InfoPlistReader.target.bundleDisplayName, permalink)
let shareText = ElementL10n.inviteFriendsText(InfoPlistReader.main.bundleDisplayName, permalink)

return AnyView(UIActivityViewControllerWrapper(activityItems: [shareText])
.presentationDetents([.medium])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct SettingsScreen: View {
}

private var versionText: some View {
Text(ElementL10n.settingsVersion + ": " + InfoPlistReader.target.bundleShortVersionString + " (" + InfoPlistReader.target.bundleVersion + ")")
Text(ElementL10n.settingsVersion + ": " + InfoPlistReader.main.bundleShortVersionString + " (" + InfoPlistReader.main.bundleVersion + ")")
}

private var backgroundColor: Color {
Expand Down
6 changes: 3 additions & 3 deletions ElementX/Sources/Services/BugReport/BugReportService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class BugReportService: BugReportServiceProtocol {
// also enable logging crashes, to send them with bug reports
MXLogger.logCrashes(true)
// set build version for logger
MXLogger.buildVersion = InfoPlistReader.target.bundleShortVersionString
MXLogger.buildVersion = InfoPlistReader.main.bundleShortVersionString
}

// MARK: - BugReportServiceProtocol
Expand Down Expand Up @@ -148,8 +148,8 @@ class BugReportService: BugReportServiceProtocol {
return [
MultipartFormData(key: "user_agent", type: .text(value: "iOS")),
MultipartFormData(key: "app", type: .text(value: applicationId)),
MultipartFormData(key: "version", type: .text(value: InfoPlistReader.target.bundleShortVersionString)),
MultipartFormData(key: "build", type: .text(value: InfoPlistReader.target.bundleVersion)),
MultipartFormData(key: "version", type: .text(value: InfoPlistReader.main.bundleShortVersionString)),
MultipartFormData(key: "build", type: .text(value: InfoPlistReader.main.bundleVersion)),
MultipartFormData(key: "os", type: .text(value: os)),
MultipartFormData(key: "resolved_language", type: .text(value: Bundle.preferredLanguages[0])),
MultipartFormData(key: "user_language", type: .text(value: Bundle.elementLanguage ?? "null")),
Expand Down
2 changes: 1 addition & 1 deletion ElementX/Sources/Services/Client/ClientProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ class ClientProxy: ClientProxyProtocol {
}

do {
let slidingSyncBuilder = try client.slidingSync().homeserver(url: ServiceLocator.shared.settings.slidingSyncProxyBaseURLString)
let slidingSyncBuilder = try client.slidingSync().homeserver(url: ServiceLocator.shared.settings.slidingSyncProxyURL.absoluteString)

// Build the visibleRoomsSlidingSyncView here so that it can take advantage of the SS builder cold cache
// We will still register the allRoomsSlidingSyncView later, and than will have no cache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ enum KeychainControllerService: String {
case tests

var identifier: String {
InfoPlistReader.target.baseBundleIdentifier + "." + rawValue
InfoPlistReader.main.baseBundleIdentifier + "." + rawValue
}
}

Expand Down
Loading

0 comments on commit f6629e0

Please sign in to comment.