Skip to content

Commit

Permalink
Finalize updated StorageAPI
Browse files Browse the repository at this point in the history
  • Loading branch information
sp4ce-cowboy committed Apr 21, 2024
1 parent 014670f commit 034525d
Showing 5 changed files with 99 additions and 21 deletions.
4 changes: 4 additions & 0 deletions TowerForge/TowerForge.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -207,6 +207,7 @@
BA436AF02BD437D900BE3E4F /* LocalStorage+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA436AEF2BD437D900BE3E4F /* LocalStorage+Metadata.swift */; };
BA436AF22BD443A500BE3E4F /* RemoteStorage+Access.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA436AF12BD443A500BE3E4F /* RemoteStorage+Access.swift */; };
BA436AF42BD4AB8400BE3E4F /* StorageHandler+Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA436AF32BD4AB8400BE3E4F /* StorageHandler+Auth.swift */; };
BA436AF62BD4AC2200BE3E4F /* StorageHandler+Conflict.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA436AF52BD4AC2200BE3E4F /* StorageHandler+Conflict.swift */; };
BA443D3D2BAD9557009F0FFB /* RemoveSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA443D3C2BAD9557009F0FFB /* RemoveSystem.swift */; };
BA443D3F2BAD9774009F0FFB /* RemoveEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA443D3E2BAD9774009F0FFB /* RemoveEvent.swift */; };
BA443D422BAD9885009F0FFB /* DamageEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA443D412BAD9885009F0FFB /* DamageEventTests.swift */; };
@@ -490,6 +491,7 @@
BA436AEF2BD437D900BE3E4F /* LocalStorage+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LocalStorage+Metadata.swift"; sourceTree = "<group>"; };
BA436AF12BD443A500BE3E4F /* RemoteStorage+Access.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RemoteStorage+Access.swift"; sourceTree = "<group>"; };
BA436AF32BD4AB8400BE3E4F /* StorageHandler+Auth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageHandler+Auth.swift"; sourceTree = "<group>"; };
BA436AF52BD4AC2200BE3E4F /* StorageHandler+Conflict.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageHandler+Conflict.swift"; sourceTree = "<group>"; };
BA443D3C2BAD9557009F0FFB /* RemoveSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveSystem.swift; sourceTree = "<group>"; };
BA443D3E2BAD9774009F0FFB /* RemoveEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveEvent.swift; sourceTree = "<group>"; };
BA443D412BAD9885009F0FFB /* DamageEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamageEventTests.swift; sourceTree = "<group>"; };
@@ -1058,6 +1060,7 @@
children = (
BA436AE92BD42F5400BE3E4F /* StorageHandler.swift */,
BA436AF32BD4AB8400BE3E4F /* StorageHandler+Auth.swift */,
BA436AF52BD4AC2200BE3E4F /* StorageHandler+Conflict.swift */,
BAEC99FB2BD15AAB00E0C437 /* StorageDatabase.swift */,
BA436AEB2BD42F7800BE3E4F /* LocalStorage.swift */,
BA436AEF2BD437D900BE3E4F /* LocalStorage+Metadata.swift */,
@@ -1774,6 +1777,7 @@
3C9955AF2BA48FD200D33FA5 /* MeleeUnit.swift in Sources */,
5240D0AD2BB33D4C004F1486 /* PositionSystem.swift in Sources */,
5295A2022BA9FBD9005018A8 /* SceneManagerDelegate.swift in Sources */,
BA436AF62BD4AC2200BE3E4F /* StorageHandler+Conflict.swift in Sources */,
9B274DC42BD24B210062715C /* DamagePowerUp.swift in Sources */,
52DF5FE12BA3349600135367 /* TFTextures.swift in Sources */,
520062582BA8ED73000DBA30 /* HomeComponent.swift in Sources */,
12 changes: 6 additions & 6 deletions TowerForge/TowerForge/Metrics/Statistics/Statistic.swift
Original file line number Diff line number Diff line change
@@ -181,19 +181,19 @@ extension Statistic {
func merge(with that: Self) -> Self {
let this = self

let largerPermanent = Double.maximum(this.permanentValue, that.permanentValue)
let largerCurrent = Double.maximum(this.currentValue, that.currentValue)
let largerMaxCurrent = Double.maximum(this.maximumCurrentValue, that.maximumCurrentValue)
let largerPermanent = max(this.permanentValue, that.permanentValue)
let largerCurrent = max(this.currentValue, that.currentValue)
let largerMaxCurrent = max(this.maximumCurrentValue, that.maximumCurrentValue)

return Self(permanentValue: largerPermanent,
currentValue: largerCurrent,
maxCurrentValue: largerMaxCurrent)
}

static func merge(this: Self, that: Self) -> Self {
let largerPermanent = Double.maximum(this.permanentValue, that.permanentValue)
let largerCurrent = Double.maximum(this.currentValue, that.currentValue)
let largerMaxCurrent = Double.maximum(this.maximumCurrentValue, that.maximumCurrentValue)
let largerPermanent = max(this.permanentValue, that.permanentValue)
let largerCurrent = max(this.currentValue, that.currentValue)
let largerMaxCurrent = max(this.maximumCurrentValue, that.maximumCurrentValue)

return Self(permanentValue: largerPermanent,
currentValue: largerCurrent,
26 changes: 11 additions & 15 deletions TowerForge/TowerForge/StorageAPI/StorageHandler+Auth.swift
Original file line number Diff line number Diff line change
@@ -62,40 +62,36 @@ extension StorageHandler {

/// Returns true if re-login success, false otherwise
func onReLogin(completion: @escaping (Bool) -> Void) {
// Executed upon confirmation that both types of data exist remotely
// 1. Load metadata from firebase
RemoteStorage.loadMetadataFromFirebase(player: Self.currentPlayerId) { remoteMetadata, _ in
guard let remoteMetadata = remoteMetadata else {
Logger.log("RELOGIN ERROR: REMOTE METADATA NOT FOUND")
completion(false)
return
}

// 2. Load statistics from firebase
RemoteStorage.loadDatabaseFromFirebase(player: Self.currentPlayerId) { remoteStorage, _ in
guard let remoteStorage = remoteStorage else {
Logger.log("RELOGIN ERROR: REMOTE STORAGE NOT FOUND")
completion(false)
return
}

guard let finalStorage = StatisticsDatabase.merge(this: remoteStorage, that: self.statisticsDatabase) else {
Logger.log("RELOGIN ERROR: REMOTE STORAGE NOT FOUND")
completion(false)
return
}

LocalStorage.saveDatabaseToLocalStorage(finalStorage)
RemoteStorage.saveDatabaseToFirebase(player: Self.currentPlayerId,
with: finalStorage) { saveStorageSuccess in
if !saveStorageSuccess {
// 3. Resolve conflict between remote statistics and current statistics
Self.resolveConflict(this: remoteStorage, that: self.statisticsDatabase) { resolvedStats in
guard let finalStorage = resolvedStats else {
Logger.log("RELOGIN ERROR: CONFLICT RESOLUTION FAILURE")
completion(false)
return
}

self.metadata = remoteMetadata
RemoteStorage.saveMetadataToFirebase(player: Self.currentPlayerId, with: self.metadata) {
saveMetadataSuccess in
// 4. Update current instance to resolve storage
self.statisticsDatabase = finalStorage

completion(saveMetadataSuccess)
}
// 4. Save newly resolved storage universally
self.save()
}
}
}
77 changes: 77 additions & 0 deletions TowerForge/TowerForge/StorageAPI/StorageHandler+Conflict.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// StorageHandler+Conflict.swift
// TowerForge
//
// Created by Rubesh on 21/4/24.
//

import Foundation

/// This extension adds conflict resolution methods to StorageHandler
extension StorageHandler {

/// Returns the StatisticsDatabase from the location that corresponds to the most recent save.
static func getLocationWithLatestMetadata(completion: @escaping (StorageLocation?) -> Void) {
RemoteStorage.loadMetadataFromFirebase(player: Self.currentPlayerId) { remoteMetadata, remoteError in
let localMetadata = LocalStorage.loadMetadataFromLocalStorage()

// Handle errors or nil cases
if let remoteError = remoteError {
Logger.log("Error occurred retrieving metadata: \(remoteError)", self)
}

switch (remoteMetadata, localMetadata) {
case (_?, nil):
completion(.Remote)
case (nil, _?):
completion(.Local)
case (let remote?, let local?):
completion(remote > local ? .Remote : .Local)
default:
completion(nil)
}
}
}

static func loadLatest(completion: @escaping (StatisticsDatabase?) -> Void) {
Self.getLocationWithLatestMetadata { location in
switch location {

case .Local:
if let stats = LocalStorage.loadDatabaseFromLocalStorage() {
completion(stats)
} else {
Logger.log("Error: Failed to load local database.", self)
completion(nil)
}

case .Remote:
RemoteStorageManager.loadDatabaseFromFirebase { statsData, error in
if let error = error {
Logger.log("Error occurred loading from database: \(error)", self)
completion(nil)
} else {
completion(statsData)
}
}

default:
Logger.log("No valid metadata found, cannot determine latest storage.", self)
completion(nil)
}
}
}

static func resolveConflict(this: StatisticsDatabase,
that: StatisticsDatabase,
completion: @escaping (StatisticsDatabase?) -> Void) {

switch CONFLICT_RESOLUTION {
case .MERGE:
completion(StatisticsDatabase.merge(this: this, that: that))
case .KEEP_LATEST_ONLY:
Self.loadLatest { completion($0) }
}
}

}
1 change: 1 addition & 0 deletions TowerForge/TowerForge/StorageAPI/StorageHandler.swift
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ class StorageHandler: AuthenticationDelegate {
static let fileName = Constants.LOCAL_STORAGE_FILE_NAME
static let metadataName = Constants.METADATA_FILE_NAME

static var CONFLICT_RESOLUTION: StorageConflictResolution { Constants.CONFLICT_RESOLTION }
static var currentPlayerId: String { Constants.CURRENT_PLAYER_ID }
static var currentDeviceId: String { Constants.CURRENT_DEVICE_ID }

0 comments on commit 034525d

Please sign in to comment.