Skip to content

Commit

Permalink
[MOB-3166] Tabs migration cleanup (#863)
Browse files Browse the repository at this point in the history
* [MOB-3166] Remove tabs migration from version <10.0.4

* [MOB-3166] Restore `TabManagerImplementation` as per Firefox v133 codebase
  • Loading branch information
d4r1091 authored Mar 7, 2025
1 parent d66b0ea commit 4e7f7b6
Show file tree
Hide file tree
Showing 5 changed files with 4 additions and 200 deletions.
3 changes: 0 additions & 3 deletions firefox-ios/Client/TabManagement/Legacy/LegacySavedTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
import Foundation
import Shared

// TODO Ecosia Upgrade: Do we still want the logic to restore tabs? [MOB-3166]
// https://github.com/ecosia/ios-browser/commit/5e5ab45a1c9c61eb3c863c269292c787c6bfee7e

class LegacySavedTab: Codable {
var isSelected: Bool
var title: String?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ struct LegacyTabDataRetrieverImplementation: LegacyTabDataRetriever {

init(fileManager: LegacyTabFileManager = FileManager.default) {
self.fileManager = fileManager
// Ecosia: Tabs architecture implementation from ~v112 to ~116
self.tabsStateArchivePath = deprecatedTabsStateArchivePath()
}

func getTabData() -> Data? {
Expand All @@ -26,16 +24,3 @@ struct LegacyTabDataRetrieverImplementation: LegacyTabDataRetriever {
return try? Data(contentsOf: tabStateArchivePath)
}
}

// Ecosia: Tabs architecture implementation from ~v112 to ~116
// This is temprorary in order to fix a migration error, can be removed after our Ecosia 10.0.0 has been well adopted

extension LegacyTabDataRetrieverImplementation {

private func deprecatedTabsStateArchivePath() -> URL? {
guard let path = fileManager.tabPath else { return nil }
return URL(fileURLWithPath: path).appendingPathComponent("tabsState.archive")
}
}

// Ecosia: End Tabs architecture implementation from ~v112 to ~116
35 changes: 2 additions & 33 deletions firefox-ios/Client/TabManagement/Legacy/LegacyTabGroupData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ enum LegacyTabGroupTimerState: String, Codable {
case none
}

// Ecosia: Tabs architecture implementation from ~v112 to ~116
// class LegacyTabGroupData: Codable {
class LegacyTabGroupData: NSObject, Codable, NSCoding {

class LegacyTabGroupData: Codable {
var tabAssociatedSearchTerm: String = ""
var tabAssociatedSearchUrl: String = ""
var tabAssociatedNextUrl: String = ""
Expand All @@ -41,9 +38,7 @@ class LegacyTabGroupData: NSObject, Codable, NSCoding {
case tabHistoryCurrentState
}

// Ecosia: Tabs architecture implementation from ~v112 to ~116
// convenience init() {
override convenience init() {
convenience init() {
self.init(searchTerm: "",
searchUrl: "",
nextReferralUrl: "",
Expand All @@ -56,30 +51,4 @@ class LegacyTabGroupData: NSObject, Codable, NSCoding {
self.tabAssociatedNextUrl = nextReferralUrl
self.tabHistoryCurrentState = tabHistoryCurrentState
}

// Ecosia: Tabs architecture implementation from ~v112 to ~116
// This is temprorary in order to fix a migration error, can be removed after our Ecosia 10.0.0 has been well adopted

var jsonDictionary: [String: Any] {
return [
CodingKeys.tabAssociatedSearchTerm.rawValue: String(self.tabAssociatedSearchTerm),
CodingKeys.tabAssociatedSearchUrl.rawValue: String(self.tabAssociatedSearchUrl),
CodingKeys.tabAssociatedNextUrl.rawValue: String(self.tabAssociatedNextUrl),
CodingKeys.tabHistoryCurrentState.rawValue: String(self.tabHistoryCurrentState),
]
}

public required init?(coder: NSCoder) {
self.tabAssociatedSearchTerm = coder.decodeObject(forKey: CodingKeys.tabAssociatedSearchTerm.rawValue) as? String ?? ""
self.tabAssociatedSearchUrl = coder.decodeObject(forKey: CodingKeys.tabAssociatedSearchUrl.rawValue) as? String ?? ""
self.tabAssociatedNextUrl = coder.decodeObject(forKey: CodingKeys.tabAssociatedNextUrl.rawValue) as? String ?? ""
self.tabHistoryCurrentState = coder.decodeObject(forKey: CodingKeys.tabHistoryCurrentState.rawValue) as? String ?? ""
}

public func encode(with coder: NSCoder) {
coder.encode(tabAssociatedSearchTerm, forKey: CodingKeys.tabAssociatedSearchTerm.rawValue)
coder.encode(tabAssociatedSearchUrl, forKey: CodingKeys.tabAssociatedSearchUrl.rawValue)
coder.encode(tabAssociatedNextUrl, forKey: CodingKeys.tabAssociatedNextUrl.rawValue)
coder.encode(tabHistoryCurrentState, forKey: CodingKeys.tabHistoryCurrentState.rawValue)
}
}
90 changes: 1 addition & 89 deletions firefox-ios/Client/TabManagement/TabManagerImplementation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import Storage
import Common
import Shared
import WebKit
import Ecosia

// Ecosia: Used to get last visited sites
import struct MozillaAppServices.VisitTransitionSet

// This class subclasses the legacy tab manager temporarily so we can
// gradually migrate to the new system
Expand Down Expand Up @@ -113,16 +109,7 @@ class TabManagerImplementation: LegacyTabManager, Notifiable, WindowSimpleTabsPr
tabs = [Tab]()
Task {
// Only attempt a tab data store fetch if we know we should have tabs on disk (ignore new windows)
var windowData: WindowData? = windowIsNew ? nil : await self.tabDataStore.fetchWindowData(uuid: windowUUID)

// TODO Ecosia Upgrade: Do we want to keep this? [MOB-3166]
/* Ecosia: Upgrading from v9.x to v10.0.0 caused an issue where migrated URLs were blank.
await buildTabRestore(window: await self.tabDataStore.fetchWindowData())
*/
if shouldRestoreMigratedv10TabsMissingUrl {
windowData = await restoreMigratedv10TabsMissingUrlIfNeeded(window: windowData)
}

let windowData: WindowData? = windowIsNew ? nil : await self.tabDataStore.fetchWindowData(uuid: windowUUID)
await buildTabRestore(window: windowData)
logger.log("Tabs restore ended after fetching window data", level: .debug, category: .tabs)
logger.log("Normal tabs count; \(normalTabs.count), Inactive tabs count; \(inactiveTabs.count), Private tabs count; \(privateTabs.count)", level: .debug, category: .tabs)
Expand Down Expand Up @@ -585,78 +572,3 @@ class TabManagerImplementation: LegacyTabManager, Notifiable, WindowSimpleTabsPr
return SimpleTab.convertToSimpleTabs(windowData.tabData)
}
}

extension TabManagerImplementation {
/// Ecosia: Get last visited sites from Places DB.
/// - Parameter count: How many sites should be fetched.
/// - Returns: Array of fetched sites.
private func fetchLastVisitedSitesFromDB(count: Int) async -> [Site] {
do {
let sites = try await withCheckedThrowingContinuation { continuation in
profile.places.getSitesWithBound(
limit: count,
offset: 0,
excludedTypes: VisitTransitionSet(0)
).upon { result in
if let successValue = result.successValue {
continuation.resume(returning: successValue.asArray())
} else {
continuation.resume(returning: [])
}
}
}
return sites
} catch {
return []
}
}

private static let restoreMigratedv10TabsMissingUrlKey = "restoreMigratedv10TabsMissingUrl"
private var shouldRestoreMigratedv10TabsMissingUrl: Bool {
!UserDefaults.standard.bool(forKey: Self.restoreMigratedv10TabsMissingUrlKey)
}
/// Fix tabs that where migrated from v9.x to v10.0.0 by fetching from last visited sites instead.
/// This should be removed after there are no significant number of users on v10.0.0.
/// - Parameter window: Window to be updated.
/// - Returns: Updated window.
private func restoreMigratedv10TabsMissingUrlIfNeeded(window: WindowData?) async -> WindowData? {
defer {
UserDefaults.standard.setValue(true, forKey: Self.restoreMigratedv10TabsMissingUrlKey)
}
// We only want to run it if the user just upgraded to the version containing this restoration code.
// Otherwise it means the user is a fresh install and we just mark it as restoration done.
guard EcosiaInstallType.get() == .upgrade else {
return window
}
// We only restore if there are actually any tabs with empty url.
guard let window = window,
window.tabData.contains(where: { $0.siteUrl.isEmpty }) else {
return window
}
let sites = await fetchLastVisitedSitesFromDB(count: 1000)
var restoredTabs = [TabData]()
window.tabData.forEach { tab in
var restoredUrl = tab.siteUrl
if restoredUrl.isEmpty {
restoredUrl = sites.first(where: { $0.title == tab.title })?.url ?? ""
// If we don't have a URL and the tab has no title, it means it should be the homepage (or at least that's better than blank)
if restoredUrl.isEmpty && (tab.title ?? "").isEmpty {
restoredUrl = URL.homepageUrlString
}
}
restoredTabs.append(
.init(id: tab.id,
title: tab.title,
siteUrl: restoredUrl,
faviconURL: tab.faviconURL,
isPrivate: tab.isPrivate,
lastUsedTime: tab.lastUsedTime,
createdAtTime: tab.createdAtTime,
tabGroupData: tab.tabGroupData)
)
}
return WindowData(id: window.id,
activeTabId: window.activeTabId,
tabData: restoredTabs)
}
}
61 changes: 1 addition & 60 deletions firefox-ios/Client/TabManagement/TabMigrationUtility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import Common
import Shared
import TabDataStore
import Ecosia

protocol TabMigrationUtility {
var shouldRunMigration: Bool { get }
Expand Down Expand Up @@ -44,22 +43,10 @@ class DefaultTabMigrationUtility: TabMigrationUtility {
logger.log("Key exists - running migration? \(shouldRunMigration)",
level: .debug,
category: .tabs)
/*
Ecosia: Tabs architecture implementation from ~v112 to ~116
This is temprorary in order to fix a migration error, can be removed after our Ecosia 10.0.0 has been well adopted
return shouldRunMigration
*/
let hasLegacyTabData = legacyTabDataRetriever.getTabData() != nil
return shouldRunMigration || hasLegacyTabData
return shouldRunMigration
}

func getLegacyTabs() -> [LegacySavedTab] {

// Ecosia: Tabs architecture implementation from ~v112 to ~116
if let deprecatedMigratedTabs = getDeprecatedTabsToMigrate() {
return deprecatedMigratedTabs
}

guard let tabData = legacyTabDataRetriever.getTabData() else {
return []
}
Expand Down Expand Up @@ -98,9 +85,6 @@ class DefaultTabMigrationUtility: TabMigrationUtility {
let tabData = TabData(
id: savedTabUUID,
title: savedTab.title,
/* TODO Ecosia Upgrade: Do we still want the logic to restore tabs? [MOB-3166]
savedTab.url?.absoluteString ?? savedTab.sessionData?.urls.last?.absoluteString ?? ""
*/
siteUrl: savedTab.url?.absoluteString ?? "",
faviconURL: savedTab.faviconURL,
isPrivate: savedTab.isPrivate,
Expand Down Expand Up @@ -132,49 +116,6 @@ class DefaultTabMigrationUtility: TabMigrationUtility {
// Save migration WindowData
await tabDataStore.saveWindowData(window: windowData, forced: true)
prefs.setBool(false, forKey: migrationKey)
// Ecosia: Tabs architecture implementation from ~v112 to ~116
clearDeprecatedArchive()
Analytics.shared.migration(true)
return windowData
}
}

// Ecosia: Tabs architecture implementation from ~v112 to ~116
// This is temprorary in order to fix a migration error, can be removed after our Ecosia 10.0.0 has been well adopted

extension DefaultTabMigrationUtility {

func getDeprecatedTabsToMigrate() -> [LegacySavedTab]? {
guard let tabData = legacyTabDataRetriever.getTabData()
else { return [LegacySavedTab]() }
let deprecatedUnarchiver = try NSKeyedUnarchiver(forReadingWith: tabData)
deprecatedUnarchiver.setClass(LegacySavedTab.self, forClassName: "Client.SavedTab")
deprecatedUnarchiver.setClass(LegacySessionData.self, forClassName: "Client.SessionData")
deprecatedUnarchiver.setClass(LegacyTabGroupData.self, forClassName: "Client.TabGroupData")
deprecatedUnarchiver.decodingFailurePolicy = .setErrorAndReturn
guard let migratedTabs = deprecatedUnarchiver.decodeObject(forKey: tabsKey) as? [LegacySavedTab] else {
let error = String(describing: deprecatedUnarchiver.error)
let message = "Deprecated unarchiver could not decode Saved tab with: \(error)"
logger.log(message, level: .warning, category: .tabs, description: error.localizedDescription)
Analytics.shared.migration(false)
Analytics.shared.migrationError(in: .tabs, message: message)
return nil
}
return migratedTabs
}

private func clearDeprecatedArchive() {
guard let deprecatedPath = legacyTabDataRetriever.tabsStateArchivePath else { return }

do {
try (legacyTabDataRetriever as? LegacyTabDataRetrieverImplementation)?.fileManager.removeItem(at: deprecatedPath)
} catch let error {
logger.log("Clear deprecated archive couldn't be completed",
level: .warning,
category: .tabs,
description: error.localizedDescription)
}
}
}

// Ecosia: End Tabs architecture implementation from ~v112 to ~116

0 comments on commit 4e7f7b6

Please sign in to comment.