Skip to content

Commit

Permalink
Merge branch 'develop' into 4-tunnel
Browse files Browse the repository at this point in the history
# Conflicts:
#	SolardVPNCommunityCoreiOS/SOLARdVPNCommunityCoreiOS/Common/Context/CommonContext.swift
#	SolardVPNCommunityCoreiOS/SOLARdVPNCommunityCoreiOS/Common/Context/ContextBuilder.swift
  • Loading branch information
lika-vorobeva committed Oct 3, 2022
2 parents 6fb544f + 2b27f8d commit f49fcb3
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Country.swift
// SOLARAPI
//
// Created by Viktoriia Kostyleva on 03.10.2022.
//

import Foundation

public struct Country: Codable {
public let code: String
public let nodesCount: Int

public init(code: String, nodesCount: Int) {
self.code = code
self.nodesCount = nodesCount
}
}

// MARK: - Codable implementation

public extension Country {
enum CodingKeys: String, CodingKey {
case code
case nodesCount = "nodes_count"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Alamofire
enum NodesAPITarget {
case getNodes(GetNodesRequest)
case postNodesByAddress(PostNodesByAddressRequest)
case getCountries
}

extension NodesAPITarget: APITarget {
Expand All @@ -20,6 +21,8 @@ extension NodesAPITarget: APITarget {
return .get
case .postNodesByAddress:
return .post
case .getCountries:
return .get
}
}

Expand All @@ -29,6 +32,8 @@ extension NodesAPITarget: APITarget {
return "dvpn/getNodes"
case .postNodesByAddress:
return "dvpn/postNodesByAddress"
case .getCountries:
return "dvpn/getCountries"
}
}

Expand All @@ -38,6 +43,8 @@ extension NodesAPITarget: APITarget {
return .requestParameters(parameters: request.dictionary ?? [:], encoding: URLEncoding.default)
case let .postNodesByAddress(request):
return .requestJSONEncodable(request)
case .getCountries:
return .requestPlain
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ extension NodesProvider: NodesProviderType {
.validate()
.responseDecodable(completionHandler: getResponseHandler(completion: completion))
}

public func getCountries(completion: @escaping (Result<[Country], NetworkError>) -> Void) {
AF
.request(request(for: .getCountries))
.validate()
.responseDecodable(completionHandler: getResponseHandler(completion: completion))
}
}

private extension NodesProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ public protocol NodesProviderType {
_ postNodesRequest: PostNodesByAddressRequest,
completion: @escaping (Result<PageResponse<Node>, NetworkError>) -> Void
)

func getCountries(completion: @escaping (Result<[Country], NetworkError>) -> Void)
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
923C372028E71D19003CFC03 /* PostNodesByAddressRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923C371F28E71D19003CFC03 /* PostNodesByAddressRequest.swift */; };
923C372228E72C87003CFC03 /* NodesByAddressPostBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923C372128E72C87003CFC03 /* NodesByAddressPostBody.swift */; };
923C372628EAE93E003CFC03 /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923C372528EAE93E003CFC03 /* Encoder.swift */; };
923C372828EAF0E8003CFC03 /* Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923C372728EAF0E8003CFC03 /* Country.swift */; };
923C372A28EAFAA5003CFC03 /* NodesServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923C372928EAFAA5003CFC03 /* NodesServiceError.swift */; };
92D6B3FD28E19E20004CF9DF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92D6B3FC28E19E20004CF9DF /* AppDelegate.swift */; };
92D6B3FF28E19E20004CF9DF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92D6B3FE28E19E20004CF9DF /* SceneDelegate.swift */; };
92D6B40128E19E20004CF9DF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92D6B40028E19E20004CF9DF /* ViewController.swift */; };
Expand Down Expand Up @@ -195,6 +197,8 @@
923C371F28E71D19003CFC03 /* PostNodesByAddressRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostNodesByAddressRequest.swift; sourceTree = "<group>"; };
923C372128E72C87003CFC03 /* NodesByAddressPostBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodesByAddressPostBody.swift; sourceTree = "<group>"; };
923C372528EAE93E003CFC03 /* Encoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encoder.swift; sourceTree = "<group>"; };
923C372728EAF0E8003CFC03 /* Country.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Country.swift; sourceTree = "<group>"; };
923C372928EAFAA5003CFC03 /* NodesServiceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodesServiceError.swift; sourceTree = "<group>"; };
92D6B3F928E19E20004CF9DF /* SOLARdVPNCommunityCoreiOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SOLARdVPNCommunityCoreiOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
92D6B3FC28E19E20004CF9DF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
92D6B3FE28E19E20004CF9DF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -448,6 +452,7 @@
children = (
92D6B47228E47EC9004CF9DF /* Models */,
92D6B46E28E47E2E004CF9DF /* NodesService.swift */,
923C372928EAFAA5003CFC03 /* NodesServiceError.swift */,
92D6B47028E47E71004CF9DF /* NodesServiceType.swift */,
);
path = NodesService;
Expand Down Expand Up @@ -583,6 +588,7 @@
92D6B45B28E46350004CF9DF /* Models */ = {
isa = PBXGroup;
children = (
923C372728EAF0E8003CFC03 /* Country.swift */,
92D6B45C28E4636B004CF9DF /* GetNodesRequest.swift */,
92D6B46228E47240004CF9DF /* Node.swift */,
92D6B46028E463EF004CF9DF /* NodeStatusType.swift */,
Expand Down Expand Up @@ -889,6 +895,7 @@
22C3EEAA28E4733C007DB01B /* NETunnelProviderProtocol+Extension.swift in Sources */,
22488AA328E72C4E00FE29C3 /* StoresWallet.swift in Sources */,
22C3EED128E48B52007DB01B /* TunnelStatus.swift in Sources */,
923C372A28EAFAA5003CFC03 /* NodesServiceError.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -905,6 +912,7 @@
92D6B46328E47240004CF9DF /* Node.swift in Sources */,
92D6B45F28E4639D004CF9DF /* OrderType.swift in Sources */,
92D6B45228E45F03004CF9DF /* NodesProvider.swift in Sources */,
923C372828EAF0E8003CFC03 /* Country.swift in Sources */,
92D6B44628E34D7C004CF9DF /* APIRequest.swift in Sources */,
92D6B42828E32900004CF9DF /* SOLARAPI.docc in Sources */,
92D6B45A28E46283004CF9DF /* NetworkError.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import SOLARAPI
protocol NoContext {}

final class CommonContext {
// Providers
let nodesProvider: NodesProviderType

// Services
let nodesService: NodesServiceType
let tunnelManager: TunnelManagerType

init(
nodesService: NodesServiceType,
tunnelManager: TunnelManagerType
nodesProvider: NodesProviderType,
nodesService: NodesServiceType
) {
self.nodesProvider = nodesProvider
self.nodesService = nodesService
self.tunnelManager = tunnelManager
}
}

protocol HasNodesProvider { var nodesProvider: NodesProviderType { get } }
extension CommonContext: HasNodesProvider {}

protocol HasNodesService { var nodesService: NodesServiceType { get } }
extension CommonContext: HasNodesService {}

protocol HasTunnelManager { var tunnelManager: TunnelManagerType { get } }
extension CommonContext: HasTunnelManager {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@ import SOLARAPI
/// This class should configure all required services and inject them into a Context
final class ContextBuilder {
func buildContext() -> CommonContext {
let generalSettingsStorage = GeneralSettingsStorage()

let nodesProvider = NodesProvider(configuration: .init(baseURL: ClientConstants.backendURL))

let nodesService = NodesService(nodesProvider: nodesProvider)

let tunnelManager = TunnelManager(storage: generalSettingsStorage)

return CommonContext(
nodesService: nodesService,
tunnelManager: tunnelManager
nodesProvider: nodesProvider,
nodesService: nodesService
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
//

import Vapor
import SOLARAPI

struct NodesRouteCollection: RouteCollection {
let context: HasNodesService
let context: HasNodesProvider

func boot(routes: RoutesBuilder) throws {
routes.get("nodes", use: getNodes)
routes.get("nodes", use: getNodes)
routes.post("nodesByAddress", use: postNodesByAddress)
routes.get("countries", use: getCountries)
}
}

Expand All @@ -26,23 +28,56 @@ extension NodesRouteCollection {
let query = req.query[String.self, at: GetNodesRequest.CodingKeys.query.rawValue]
let page = req.query[Int.self, at: GetNodesRequest.CodingKeys.page.rawValue]

return try await context.nodesService.loadNodes(
continentCode: continentCode,
countryCode: countryCode,
minPrice: minPrice,
maxPrice: maxPrice,
orderBy: orderBy,
query: query,
page: page
)
return try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<String, Error>) in
context.nodesProvider.getNodes(
.init(
status: .active,
continentCode: continentCode,
countryCode: countryCode,
minPrice: minPrice,
maxPrice: maxPrice,
orderBy: orderBy,
query: query,
page: page
)
) { result in
switch result {
case let .success(response):
Encoder.encode(model: response, continuation: continuation)
case let .failure(error):
continuation.resume(throwing: Abort(.init(statusCode: error.code), reason: error.localizedDescription))
}
}
})
}

func postNodesByAddress(_ req: Request) async throws -> String {
let body = try req.content.decode(NodesByAddressPostBody.self)

return try await context.nodesService.getNodes(
by: body.blockchain_addresses,
page: body.page
)
return try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<String, Error>) in
context.nodesProvider.postNodesByAddress(
.init(addresses: body.blockchain_addresses, page: body.page)
) { result in
switch result {
case let .success(response):
Encoder.encode(model: response, continuation: continuation)
case let .failure(error):
continuation.resume(throwing: Abort(.init(statusCode: error.code), reason: error.localizedDescription))
}
}
})
}

func getCountries(_ req: Request) async throws -> String {
try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<String, Error>) in
context.nodesProvider.getCountries() { result in
switch result {
case let .success(response):
Encoder.encode(model: response, continuation: continuation)
case let .failure(error):
continuation.resume(throwing: Abort(.init(statusCode: error.code), reason: error.localizedDescription))
}
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import Foundation
import SOLARAPI
import Vapor

final class NodesService {
private let nodesProvider: NodesProviderType

private var loadedNodes: [Node] = []

init(
nodesProvider: NodesProviderType
) {
Expand All @@ -22,51 +23,61 @@ final class NodesService {
// MARK: - NodesServiceType

extension NodesService: NodesServiceType {
var nodes: [Node] {
loadedNodes
}

/// Loads active nodes and saves them to local variable
func loadNodes(
continentCode: String?,
continent: Continent?,
countryCode: String?,
minPrice: Int?,
maxPrice: Int?,
orderBy: OrderType?,
query: String?,
page: Int?
) async throws -> String {
try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<String, Error>) in
nodesProvider.getNodes(
.init(
status: .active,
continentCode: continentCode,
countryCode: countryCode,
minPrice: minPrice,
maxPrice: maxPrice,
orderBy: orderBy,
query: query,
page: page
)
) { result in
switch result {
case let .success(response):
Encoder.encode(model: response, continuation: continuation)
case let .failure(error):
continuation.resume(throwing: Abort(.init(statusCode: error.code), reason: error.localizedDescription))
}
page: Int?,
completion: @escaping (Result<PageResponse<Node>, Error>) -> Void
) {
nodesProvider.getNodes(
.init(
status: .active,
continentCode: continent?.code,
countryCode: countryCode,
minPrice: minPrice,
maxPrice: maxPrice,
orderBy: orderBy,
query: query,
page: page
)
) { [weak self] result in
switch result {
case .failure(let error):
log.error(error)
completion(.failure(NodesServiceError.failToLoadData))
case .success(let response):
completion(.success(response))
self?.loadedNodes = response.data
}
})
}
}

func getNodes(
by addresses: [String],
page: Int?
) async throws -> String {
try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<String, Error>) in
nodesProvider.postNodesByAddress(.init(addresses: addresses, page: page)) { result in
switch result {
case let .success(response):
Encoder.encode(model: response, continuation: continuation)
case let .failure(error):
continuation.resume(throwing: Abort(.init(statusCode: error.code), reason: error.localizedDescription))
func getNode(
by address: String,
completion: @escaping (Result<Node, Error>) -> Void
) {
nodesProvider.postNodesByAddress(.init(addresses: [address], page: nil)) { result in
switch result {
case .failure(let error):
log.error(error)
completion(.failure(NodesServiceError.failToLoadData))
case .success(let response):
guard let node = response.data.first else {
completion(.failure(NodesServiceError.failToLoadData))
return
}

completion(.success(node))
}
})
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// NodesServiceError.swift
// SOLARdVPNCommunityCoreiOS
//
// Created by Viktoriia Kostyleva on 03.10.2022.
//

import Foundation

enum NodesServiceError: LocalizedError {
case failToLoadData
}
Loading

0 comments on commit f49fcb3

Please sign in to comment.