Refactor Enjin OpenSea providers #3757

pull/3758/head
Krypto Pank 3 years ago
parent 5cb5efc8b4
commit 6154410c1a
  1. 8
      AlphaWallet.xcodeproj/project.pbxproj
  2. 2
      AlphaWallet/AppCoordinator.swift
  3. 31
      AlphaWallet/Core/Enjin/EnjinProvider.swift
  4. 32
      AlphaWallet/Core/Enjin/EnjinUserManagementInterceptor.swift
  5. 7
      AlphaWallet/EtherClient/OpenSea.swift
  6. 6
      AlphaWallet/TokenScriptClient/Coordinators/AssetDefinitionStoreCoordinator.swift

@ -1013,7 +1013,7 @@
87FB0A8226D8D307000EC15F /* TokenProviderType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FB0A8126D8D307000EC15F /* TokenProviderType.swift */; }; 87FB0A8226D8D307000EC15F /* TokenProviderType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FB0A8126D8D307000EC15F /* TokenProviderType.swift */; };
87FBAE0124A1EE67005EF293 /* AddressOrEnsNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FBAE0024A1EE67005EF293 /* AddressOrEnsNameLabel.swift */; }; 87FBAE0124A1EE67005EF293 /* AddressOrEnsNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FBAE0024A1EE67005EF293 /* AddressOrEnsNameLabel.swift */; };
87FF2E422567F0A3002350EB /* BlockieGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FF2E412567F0A3002350EB /* BlockieGenerator.swift */; }; 87FF2E422567F0A3002350EB /* BlockieGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FF2E412567F0A3002350EB /* BlockieGenerator.swift */; };
87FF649927355FDD00D59E20 /* EnjinAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FF649827355FDD00D59E20 /* EnjinAuthorization.swift */; }; 87FF649927355FDD00D59E20 /* EnjinUserManagementInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FF649827355FDD00D59E20 /* EnjinUserManagementInterceptor.swift */; };
AA26C61F20412A1E00318B9B /* TokensCardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA26C61D20412A1D00318B9B /* TokensCardViewController.swift */; }; AA26C61F20412A1E00318B9B /* TokensCardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA26C61D20412A1D00318B9B /* TokensCardViewController.swift */; };
AA26C62320412A4100318B9B /* UIViewInspectableEnhancements.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA26C62120412A4100318B9B /* UIViewInspectableEnhancements.swift */; }; AA26C62320412A4100318B9B /* UIViewInspectableEnhancements.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA26C62120412A4100318B9B /* UIViewInspectableEnhancements.swift */; };
AA26C62420412A4100318B9B /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA26C62220412A4100318B9B /* Double.swift */; }; AA26C62420412A4100318B9B /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA26C62220412A4100318B9B /* Double.swift */; };
@ -2105,7 +2105,7 @@
87FB0A8126D8D307000EC15F /* TokenProviderType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenProviderType.swift; sourceTree = "<group>"; }; 87FB0A8126D8D307000EC15F /* TokenProviderType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenProviderType.swift; sourceTree = "<group>"; };
87FBAE0024A1EE67005EF293 /* AddressOrEnsNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressOrEnsNameLabel.swift; sourceTree = "<group>"; }; 87FBAE0024A1EE67005EF293 /* AddressOrEnsNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressOrEnsNameLabel.swift; sourceTree = "<group>"; };
87FF2E412567F0A3002350EB /* BlockieGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockieGenerator.swift; sourceTree = "<group>"; }; 87FF2E412567F0A3002350EB /* BlockieGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockieGenerator.swift; sourceTree = "<group>"; };
87FF649827355FDD00D59E20 /* EnjinAuthorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnjinAuthorization.swift; sourceTree = "<group>"; }; 87FF649827355FDD00D59E20 /* EnjinUserManagementInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnjinUserManagementInterceptor.swift; sourceTree = "<group>"; };
AA26C61D20412A1D00318B9B /* TokensCardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokensCardViewController.swift; sourceTree = "<group>"; }; AA26C61D20412A1D00318B9B /* TokensCardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokensCardViewController.swift; sourceTree = "<group>"; };
AA26C62120412A4100318B9B /* UIViewInspectableEnhancements.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewInspectableEnhancements.swift; sourceTree = "<group>"; }; AA26C62120412A4100318B9B /* UIViewInspectableEnhancements.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewInspectableEnhancements.swift; sourceTree = "<group>"; };
AA26C62220412A4100318B9B /* Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; }; AA26C62220412A4100318B9B /* Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
@ -5000,7 +5000,7 @@
87D5BBDA2727DA7B0053E6D2 /* EnjinToken.graphql */, 87D5BBDA2727DA7B0053E6D2 /* EnjinToken.graphql */,
87D5BBDC2727DCB40053E6D2 /* EnjinBalances.graphql */, 87D5BBDC2727DCB40053E6D2 /* EnjinBalances.graphql */,
87D5BBD62727D69E0053E6D2 /* EnjinProvider.swift */, 87D5BBD62727D69E0053E6D2 /* EnjinProvider.swift */,
87FF649827355FDD00D59E20 /* EnjinAuthorization.swift */, 87FF649827355FDD00D59E20 /* EnjinUserManagementInterceptor.swift */,
); );
path = Enjin; path = Enjin;
sourceTree = "<group>"; sourceTree = "<group>";
@ -5672,7 +5672,7 @@
29F114F21FA7966300114A29 /* PrivateKeyRule.swift in Sources */, 29F114F21FA7966300114A29 /* PrivateKeyRule.swift in Sources */,
29E2E33A1F7A008C000CF94A /* UIView.swift in Sources */, 29E2E33A1F7A008C000CF94A /* UIView.swift in Sources */,
87509A6226F8D67E00D3EE85 /* CollectUsersEmailViewController.swift in Sources */, 87509A6226F8D67E00D3EE85 /* CollectUsersEmailViewController.swift in Sources */,
87FF649927355FDD00D59E20 /* EnjinAuthorization.swift in Sources */, 87FF649927355FDD00D59E20 /* EnjinUserManagementInterceptor.swift in Sources */,
87A0C93225AEF1E400E73F60 /* EventInstanceValue.swift in Sources */, 87A0C93225AEF1E400E73F60 /* EventInstanceValue.swift in Sources */,
299B5E491FD2C8900051361C /* ConfigureTransaction.swift in Sources */, 299B5E491FD2C8900051361C /* ConfigureTransaction.swift in Sources */,
77872D25202505B70032D687 /* EnterPasswordViewController.swift in Sources */, 77872D25202505B70032D687 /* EnterPasswordViewController.swift in Sources */,

@ -331,7 +331,6 @@ extension AppCoordinator: InitialWalletCreationCoordinatorDelegate {
extension AppCoordinator: InCoordinatorDelegate { extension AppCoordinator: InCoordinatorDelegate {
func didRestart(in coordinator: InCoordinator, reason: RestartReason, wallet: Wallet) { func didRestart(in coordinator: InCoordinator, reason: RestartReason, wallet: Wallet) {
OpenSea.resetInstances()
disconnectWalletConnectSessionsSelectively(for: reason, walletConnectCoordinator: coordinator.walletConnectCoordinator) disconnectWalletConnectSessionsSelectively(for: reason, walletConnectCoordinator: coordinator.walletConnectCoordinator)
keystore.recentlyUsedWallet = wallet keystore.recentlyUsedWallet = wallet
@ -530,7 +529,6 @@ extension AppCoordinator: AccountsCoordinatorDelegate {
pendingCoordinator.showTabBar(animated: true) pendingCoordinator.showTabBar(animated: true)
} else { } else {
if let coordinator = pendingInCoordinator { if let coordinator = pendingInCoordinator {
OpenSea.resetInstances()
disconnectWalletConnectSessionsSelectively(for: .walletChange, walletConnectCoordinator: coordinator.walletConnectCoordinator) disconnectWalletConnectSessionsSelectively(for: .walletChange, walletConnectCoordinator: coordinator.walletConnectCoordinator)
} }

@ -13,26 +13,27 @@ struct EnjinError: Error {
var localizedDescription: String var localizedDescription: String
} }
class EnjinProvider { class WeakRef<T: AnyObject> {
weak var object: T?
private class WeakRef<T: AnyObject> { init(object: T) {
weak var object: T? self.object = object
init(object: T) {
self.object = object
}
} }
}
class EnjinProvider {
typealias PromiseResult = Promise<[AlphaWallet.Address: [GetEnjinTokenQuery.Data.EnjinToken]]> typealias PromiseResult = Promise<[AlphaWallet.Address: [GetEnjinTokenQuery.Data.EnjinToken]]>
private static let numberOfTokenIdsBeforeRateLimitingRequests = 25 private static let numberOfTokenIdsBeforeRateLimitingRequests = 25
private static let minimumSecondsBetweenRequests = TimeInterval(60) private static let minimumSecondsBetweenRequests = TimeInterval(60)
private(set) lazy var graphqlClient: ApolloClient = { static let client = URLSessionClient()
let client = URLSessionClient() static let cache = InMemoryNormalizedCache()
let cache = InMemoryNormalizedCache() static let store = ApolloStore(cache: cache)
let store = ApolloStore(cache: cache)
private static var graphqlClient: ApolloClient = {
let provider = NetworkInterceptorProvider(store: store, client: client) let provider = NetworkInterceptorProvider(store: store, client: client)
let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: Constants.enjinApiUrl) let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: Constants.enjinApiUrl)
return ApolloClient(networkTransport: transport, store: store) return ApolloClient(networkTransport: transport, store: store)
}() }()
@ -109,7 +110,7 @@ class EnjinProvider {
} }
}.then({ balances -> Promise<[AlphaWallet.Address: [GetEnjinTokenQuery.Data.EnjinToken]]> in }.then({ balances -> Promise<[AlphaWallet.Address: [GetEnjinTokenQuery.Data.EnjinToken]]> in
let ids = (balances[owner] ?? []).compactMap { $0.token?.id } let ids = (balances[owner] ?? []).compactMap { $0.token?.id }
return EnjinProvider.functional.getTokens(graphqlClient: self.graphqlClient, ids: ids, owner: owner) return EnjinProvider.functional.getTokens(graphqlClient: EnjinProvider.graphqlClient, ids: ids, owner: owner)
}) })
} }
return fetch return fetch
@ -119,7 +120,7 @@ class EnjinProvider {
typealias MappedEnjinBalances = [AlphaWallet.Address: EnjinBalances] typealias MappedEnjinBalances = [AlphaWallet.Address: EnjinBalances]
private func fetchPage(forOwner owner: AlphaWallet.Address, offset: Int, completion: @escaping (Swift.Result<MappedEnjinBalances, EnjinError>) -> Void) { private func fetchPage(forOwner owner: AlphaWallet.Address, offset: Int, completion: @escaping (Swift.Result<MappedEnjinBalances, EnjinError>) -> Void) {
EnjinProvider.functional.fetchPage(graphqlClient: graphqlClient, forOwner: owner, offset: offset) { [weak self] response in EnjinProvider.functional.fetchPage(graphqlClient: EnjinProvider.graphqlClient, forOwner: owner, offset: offset) { [weak self] response in
switch response { switch response {
case .success(let result): case .success(let result):
self?.cachePromise(withTokenIdCount: result.tokenIdCount, forOwner: result.owner) self?.cachePromise(withTokenIdCount: result.tokenIdCount, forOwner: result.owner)
@ -268,7 +269,7 @@ extension EnjinProvider.functional {
} }
} }
final class NetworkInterceptorProvider: InterceptorProvider { final private class NetworkInterceptorProvider: InterceptorProvider {
// These properties will remain the same throughout the life of the `InterceptorProvider`, even though they // These properties will remain the same throughout the life of the `InterceptorProvider`, even though they
// will be handed to different interceptors. // will be handed to different interceptors.
private let store: ApolloStore private let store: ApolloStore
@ -283,7 +284,7 @@ final class NetworkInterceptorProvider: InterceptorProvider {
return [ return [
MaxRetryInterceptor(), MaxRetryInterceptor(),
CacheReadInterceptor(store: self.store), CacheReadInterceptor(store: self.store),
UserManagementInterceptor(), EnjinUserManagementInterceptor(),
NetworkFetchInterceptor(client: self.client), NetworkFetchInterceptor(client: self.client),
ResponseCodeInterceptor(), ResponseCodeInterceptor(),
JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject), JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject),

@ -25,23 +25,21 @@ extension Config {
} }
} }
class UserManager { private class EnjinUserManager {
static let shared = UserManager() static let shared = EnjinUserManager()
private init() { private init() {
} }
private var config = Config()
private var config = Config()
private let graphqlClient: ApolloClient = { private let graphqlClient: ApolloClient = {
let client = URLSessionClient() let provider = InterceptorProviderForAuthorization(client: EnjinProvider.client, store: EnjinProvider.store)
let cache = InMemoryNormalizedCache()
let store = ApolloStore(cache: cache)
let provider = InterceptorProviderForAuthorization(client: client, store: store)
let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: Constants.enjinApiUrl) let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: Constants.enjinApiUrl)
return ApolloClient(networkTransport: transport, store: store)
return ApolloClient(networkTransport: transport, store: EnjinProvider.store)
}() }()
enum UserManagerError: Error { enum EnjinUserManagerError: Error {
case fetchAccessTokenFailure case fetchAccessTokenFailure
} }
@ -59,7 +57,7 @@ class UserManager {
if let accessToken = oauth.accessTokens?.compactMap({ $0 }).first { if let accessToken = oauth.accessTokens?.compactMap({ $0 }).first {
return accessToken return accessToken
} else { } else {
throw UserManagerError.fetchAccessTokenFailure throw EnjinUserManagerError.fetchAccessTokenFailure
} }
}.get { accessToken in }.get { accessToken in
self.config.accessToken = accessToken self.config.accessToken = accessToken
@ -165,7 +163,7 @@ struct FallbackJSONResponseParsingInterceptor: ApolloInterceptor {
private func parseResult<Data>(from response: GraphQLResponse<Data>, cachePolicy: CachePolicy) throws -> GraphQLResult<Data> { private func parseResult<Data>(from response: GraphQLResponse<Data>, cachePolicy: CachePolicy) throws -> GraphQLResult<Data> {
switch cachePolicy { switch cachePolicy {
case .fetchIgnoringCacheCompletely: case .fetchIgnoringCacheCompletely:
// There is no cache, so we don't need to get any info on dependencies. Use fast parsing. // There is no cache, so we don't need to get any info on dependencies. Use fast parsing.
return try response.parseResultFast() return try response.parseResultFast()
default: default:
let (parsedResult, _) = try response.parseResult(cacheKeyForObject: self.cacheKeyForObject) let (parsedResult, _) = try response.parseResult(cacheKeyForObject: self.cacheKeyForObject)
@ -175,7 +173,7 @@ struct FallbackJSONResponseParsingInterceptor: ApolloInterceptor {
} }
class UserManagementInterceptor: ApolloInterceptor { class EnjinUserManagementInterceptor: ApolloInterceptor {
enum UserError: Error { enum UserError: Error {
case noUserLoggedIn case noUserLoggedIn
@ -193,7 +191,7 @@ class UserManagementInterceptor: ApolloInterceptor {
} }
let performAuthorizeEnjinUser: () -> Void = { let performAuthorizeEnjinUser: () -> Void = {
let promise = UserManager.shared.enjinAuthorize() let promise = EnjinUserManager.shared.enjinAuthorize()
promise.done { accessToken in promise.done { accessToken in
addTokenAndProceed(accessToken, to: request, chain: chain, response: response, completion: completion) addTokenAndProceed(accessToken, to: request, chain: chain, response: response, completion: completion)
}.catch { error in }.catch { error in
@ -211,9 +209,9 @@ class UserManagementInterceptor: ApolloInterceptor {
if let accessToken = promise.value { if let accessToken = promise.value {
addTokenAndProceed(accessToken, to: request, chain: chain, response: response, completion: completion) addTokenAndProceed(accessToken, to: request, chain: chain, response: response, completion: completion)
} else if promise.isPending { } else if promise.isPending {
//NOTE: wait until access token resolved //NOTE: wait until access token resolved
let block: () -> Void = { let block: () -> Void = {
guard let accessToken = UserManager.shared.accessToken else { return } guard let accessToken = EnjinUserManager.shared.accessToken else { return }
addTokenAndProceed(accessToken, to: request, chain: chain, response: response, completion: completion) addTokenAndProceed(accessToken, to: request, chain: chain, response: response, completion: completion)
} }
Self.pending.append(block) Self.pending.append(block)
@ -245,7 +243,7 @@ class UserManagementInterceptor: ApolloInterceptor {
} }
} }
guard let token = UserManager.shared.accessToken else { guard let token = EnjinUserManager.shared.accessToken else {
authorizeEnjinUser() authorizeEnjinUser()
return return
} }

@ -8,13 +8,6 @@ import Result
import SwiftyJSON import SwiftyJSON
class OpenSea { class OpenSea {
private class WeakRef<T: AnyObject> {
weak var object: T?
init(object: T) {
self.object = object
}
}
typealias PromiseResult = Promise<[AlphaWallet.Address: [OpenSeaNonFungible]]> typealias PromiseResult = Promise<[AlphaWallet.Address: [OpenSeaNonFungible]]>
//Assuming 1 token (token ID, rather than a token) is 4kb, 1500 HyperDragons is 6MB. So we rate limit requests //Assuming 1 token (token ID, rather than a token) is 4kb, 1500 HyperDragons is 6MB. So we rate limit requests

@ -30,12 +30,6 @@ enum OpenURLError: Error {
} }
class AssetDefinitionStoreCoordinator: Coordinator { class AssetDefinitionStoreCoordinator: Coordinator {
private class WeakRef<T: AnyObject> {
weak var object: T?
init(object: T) {
self.object = object
}
}
private static var inboxDirectory: URL? { private static var inboxDirectory: URL? {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .allDomainsMask, true).compactMap { URL(fileURLWithPath: $0) } let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .allDomainsMask, true).compactMap { URL(fileURLWithPath: $0) }

Loading…
Cancel
Save