From 1767a9afa14d68c76ec9c61ae193ed632afcdf3f Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Thu, 15 Feb 2024 20:13:28 +0700 Subject: [PATCH 1/4] feat(token-service): fix race condition loading --- .../Solana/SolanaTokenService.swift | 72 +++++++++++-------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift index 7c190cb68..60db9bc35 100644 --- a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift +++ b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift @@ -11,7 +11,7 @@ public protocol SolanaTokensService: TokenRepository { } public actor KeyAppSolanaTokenRepository: SolanaTokensService { - static let version: Int = 1 + static let version: Int = 2 struct Database: Codable, Hashable { var timestamps: Date? @@ -35,6 +35,8 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { let errorObserver: ErrorObserver var status: Status = .initialising + + var setupTask: Task? public init(provider: KeyAppTokenProvider, errorObserver: ErrorObserver) { self.provider = provider @@ -46,42 +48,49 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { return } - // Load from local storage - if status == Status.initialising { - if let encodedData = try? await storage.load(for: filename) { - if let database = try? JSONDecoder().decode(Database.self, from: encodedData) { - if let migratedDatabase = migrate(database: database) { - self.database = migratedDatabase - setupStaticToken(data: migratedDatabase.data) + if let setupTask { + await setupTask.value + return + } + + setupTask = Task { + // Load from local storage + if status == Status.initialising { + if let encodedData = try? await storage.load(for: filename) { + if let database = try? JSONDecoder().decode(Database.self, from: encodedData) { + if let migratedDatabase = migrate(database: database) { + self.database = migratedDatabase + setupStaticToken(data: migratedDatabase.data) + } } } } - } - do { - let result = try await provider.getSolanaTokens(modifiedSince: database.timestamps) - switch result { - case .noChanges: - status = .ready - return - case let .result(result): - // Update database - database.timestamps = result.timestamp - let tokens = result.tokens.map { token in - (token.mintAddress, token) + do { + let result = try await provider.getSolanaTokens(modifiedSince: database.timestamps) + switch result { + case .noChanges: + status = .ready + return + case let .result(result): + // Update database + database.timestamps = result.timestamp + let tokens = result.tokens.map { token in + (token.mintAddress, token) + } + let data = Dictionary(tokens, uniquingKeysWith: { lhs, _ in lhs }) + database.version = Self.version + database.data = data + setupStaticToken(data: data) + status = .ready } - let data = Dictionary(tokens, uniquingKeysWith: { lhs, _ in lhs }) - database.version = Self.version - database.data = data - setupStaticToken(data: data) - status = .ready - } - if let encodedData = try? JSONEncoder().encode(database) { - try? await storage.save(for: filename, data: encodedData) + if let encodedData = try? JSONEncoder().encode(database) { + try await storage.save(for: filename, data: encodedData) + } + } catch { + errorObserver.handleError(error) } - } catch { - errorObserver.handleError(error) } } @@ -90,6 +99,9 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { case .none: return nil case 1: + // Clear all data to ensure user has been updated with the latest data by using new algorithm. + return .init(data: [:]) + case 2: return database default: return database From 703f3bd8ed92beca3126a328d39696815299c697 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Thu, 15 Feb 2024 20:15:19 +0700 Subject: [PATCH 2/4] feat(token-service): wait result of task --- .../Sources/TokenService/Solana/SolanaTokenService.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift index 60db9bc35..678010232 100644 --- a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift +++ b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift @@ -92,6 +92,8 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { errorObserver.handleError(error) } } + + await setupTask?.value } func migrate(database: Database) -> Database? { From 285b37681d51b77e469cb992f6f93470d0ad78a0 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Thu, 15 Feb 2024 21:47:28 +0700 Subject: [PATCH 3/4] feat(token-service): deallocate task after running --- .../Sources/TokenService/Solana/SolanaTokenService.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift index 678010232..d7aba0fbe 100644 --- a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift +++ b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift @@ -94,6 +94,7 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { } await setupTask?.value + setupTask = nil } func migrate(database: Database) -> Database? { From 1bf674693102121d6b92e26dd06a5604988ac51f Mon Sep 17 00:00:00 2001 From: runner Date: Thu, 15 Feb 2024 14:48:29 +0000 Subject: [PATCH 4/4] fix(swiftformat): Apply Swiftformat changes --- .../Sources/TokenService/Solana/SolanaTokenService.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift index d7aba0fbe..be6feab88 100644 --- a/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift +++ b/Packages/KeyAppKit/Sources/TokenService/Solana/SolanaTokenService.swift @@ -35,7 +35,7 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { let errorObserver: ErrorObserver var status: Status = .initialising - + var setupTask: Task? public init(provider: KeyAppTokenProvider, errorObserver: ErrorObserver) { @@ -52,7 +52,7 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { await setupTask.value return } - + setupTask = Task { // Load from local storage if status == Status.initialising { @@ -92,7 +92,7 @@ public actor KeyAppSolanaTokenRepository: SolanaTokensService { errorObserver.handleError(error) } } - + await setupTask?.value setupTask = nil }