Files
2022-05-27 20:21:01 +03:00

169 lines
7.8 KiB
Swift

//
// MainService.swift
// PayCash
//
// Created by Igor on 05.03.2021.
// Copyright © 2021 AM. All rights reserved.
//
import UIKit
import Alamofire
import EosioSwift
import struct Resolver.Injected
import class Resolver.ResolverScope
class RuntimeConfiguration {
// var serverTime: Date = Date()
var serverTimeDiff: Double = 0
var currentTimestamp: Double { Date().timeIntervalSince1970 + serverTimeDiff }
var dealsActiveOnly = true
}
extension Main {
class Service {
@Injected var runtimeConfiguration: RuntimeConfiguration
func loadNodes() async {
let nodes = try? await AF.request(
Network.servers.current.paycashQraphql,
method: .post,
parameters: GetEOSNodesGraphQLRequest(),
encoder: JSONParameterEncoder.default
)
.serializingDecodable(GraphQLResponse<GetEOSNodesGraphQLRequest.ResponseData>.self)
.value.data?.getEOSNodes?.nodes.map({ $0.url }) ?? []
if let nodes = nodes, !nodes.isEmpty {
// Network.servers.current.nodes = nodes
Network.servers.update(nodes: nodes)
}
}
func loadVersion() async -> String? {
let results = await withTaskGroup(of: (String, TimeInterval, Int, Int, Int, Int).self) { taskGroup -> [(String, TimeInterval, Int, Int, Int, Int)] in
let systemName = await UIDevice.current.systemName
for node in Network.servers.current.nodes {
taskGroup.addTask {
let startTime = Date().timeIntervalSince1970
let result = await Network.Service.Blockchain
.queryRaw(endpoint: node, contract: .appSettings, scope: Network.servers.current.contract(.appSettings), table: "build")
let timeSpent = Date().timeIntervalSince1970 - startTime
print("Node \(node) loaded version in \(timeSpent) seconds")
if let rows = result.value,
let minBuildVersionString = rows.compactMap({ $0["min_version_build"] as? String }).first,
let minBuildVersionJson = (try? JSONSerialization.jsonObject(with: minBuildVersionString.data(using: .utf8) ?? Data(), options: [])) as? [String: Any],
let minBuildVersion = minBuildVersionJson[systemName] as? String,
let major = Int(minBuildVersion.split(separator: ".").first ?? ""),
let minor = Int(minBuildVersion.split(separator: ".").dropFirst().first ?? ""),
let patch = Int(minBuildVersion.split(separator: ".").dropFirst().dropFirst().first ?? ""),
let build = Int(minBuildVersion.split(separator: ".").dropFirst().dropFirst().dropFirst().first ?? "0") {
return (node, timeSpent, major, minor, patch, build)
}
return (node, 1000, 1000, 1000, 1000, 1000)
}
}
var childTaskResults = [(String, TimeInterval, Int, Int, Int, Int)]()
for await result in taskGroup {
if !childTaskResults.isEmpty {
print("Too late for version from \(result.0) some node was faster \(childTaskResults.sorted(by: { $0.1 < $1.1 }).map({ $0.0 }).joined(separator: ", "))")
}
childTaskResults.append(result)
if result.2 < 1000 {
Network.servers.update(nodes: [result.0] + Network.servers.current.nodes.filter({ $0 != result.0 }))
return [result]
}
}
return childTaskResults
}
// let node = results.sorted(by: { $0.1 < $1.1 })
if let result = results.first(where: { $0.2 < 1000 }) {
if Bundle.main.major < result.2 {
return L10n.Main.wrongVersion
} else if Bundle.main.major == result.2 {
if Bundle.main.minor < result.3 {
return L10n.Main.wrongVersion
} else if Bundle.main.minor == result.3 {
if Bundle.main.patch < result.4 {
return L10n.Main.wrongVersion
} else if Bundle.main.patch == result.4 {
if Bundle.main.build < result.5 {
return L10n.Main.wrongVersion
}
}
}
}
} else {
return L10n.Main.noVersion
}
return nil
}
func loadServerTime() {
EosioRpcProvider(endpoint: URL(string: Network.servers.current.node)!).getInfo(completion: { [weak self] (result: EosioResult<EosioRpcInfoResponse, EosioError>) in
switch result {
case let .success(response):
// self?.runtimeConfiguration.serverTime = response.headBlockTime.asISODate() ?? Date()
self?.runtimeConfiguration.serverTimeDiff = (response.headBlockTime.asISODate() ?? Date()).timeIntervalSince1970 - Date().timeIntervalSince1970
case .failure:
break
}
})
}
func loadHyperions() {
let groupFailed = DispatchGroup()
let queue = DispatchQueue(label: "")
var success = false
for node in Network.servers.current.nodes {
groupFailed.enter()
let startTime = Date().timeIntervalSince1970
Network.Service.Blockchain.queryRaw(endpoint: node, contract: .appSettings, scope: Network.servers.current.contract(.appSettings), table: "data", closure: {
switch $0 {
case let .success(rows):
DispatchQueue.main.async {
print("Node \(node) loaded hyperions in \(Date().timeIntervalSince1970 - startTime) seconds")
}
queue.async {
print(rows)
print(rows.compactMap({ $0["endpoint"] as? String }))
if rows.compactMap({ $0["endpoint"] as? String }).count > 0 {
guard !success else {
print("Too late for hyperions from \(node) some node was faster \(Network.servers.current.node)")
return
}
success = true
Network.servers.update(hyperions: rows.compactMap({ $0["endpoint"] as? String }).shuffled())
Network.servers.update(nodes: [node] + Network.servers.current.nodes.filter({ $0 != node }))
DispatchQueue.main.async {
self.loadServerTime()
Account.Service.History.shared.fetch()
ResolverScope.userSession.reset()
Notification.post(name: .didChangeAccount)
}
} else {
groupFailed.leave()
}
}
case let .failure(error):
print(error)
groupFailed.leave()
}
})
}
groupFailed.notify(queue: .main) {
print("All Tasks are failed")
Alert.success(text: L10n.Main.noHyperion)
}
}
}
}