Skip to content

Commit

Permalink
#4: Toggle connection on client request
Browse files Browse the repository at this point in the history
  • Loading branch information
lika-vorobeva committed Oct 5, 2022
1 parent 699c17c commit 6d40715
Show file tree
Hide file tree
Showing 6 changed files with 432 additions and 62 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,110 @@
//

import Foundation
import SentinelWallet
import SOLARAPI

protocol NoContext {}

final class CommonContext {
// Providers
let nodesProvider: NodesProviderType
typealias Storage = StoresConnectInfo & StoresWallet & StoresDNSServers
let storage: Storage

// Providers
let nodesProvider: SOLARAPI.NodesProviderType

// Services
let securityService: SecurityService
let nodesService: NodesServiceType

let walletService: WalletService
let subscriptionsService: SubscriptionsServiceType
let sessionsService: SessionsServiceType

let tunnelManager: TunnelManagerType

init(
nodesProvider: NodesProviderType,
nodesService: NodesServiceType
storage: Storage,
nodesProvider: SOLARAPI.NodesProviderType,
securityService: SecurityService,
walletService: WalletService,
nodesService: NodesServiceType,
subscriptionsService: SubscriptionsServiceType,
sessionsService: SessionsServiceType,
tunnelManager: TunnelManagerType
) {
self.storage = storage
self.nodesProvider = nodesProvider
self.securityService = securityService
self.walletService = walletService
self.nodesService = nodesService
self.subscriptionsService = subscriptionsService
self.sessionsService = sessionsService
self.tunnelManager = tunnelManager
}
}

protocol HasNodesProvider { var nodesProvider: NodesProviderType { get } }
protocol HasWalletService {
var walletService: WalletService { get }

func updateWalletContext()
func resetWalletContext()
}

extension CommonContext: HasWalletService {
func updateWalletContext() {
let walletAddress = storage.walletAddress
guard !walletAddress.isEmpty else { return }
walletService.manage(address: walletAddress)
}

func resetWalletContext() {
let mnemonics = securityService.generateMnemonics().components(separatedBy: " ")
switch securityService.restore(from: mnemonics) {
case .failure(let error):
fatalError("failed to generate wallet due to \(error), terminate")
case .success(let address):
saveMnemonicsIfNeeded(for: address, mnemonics: mnemonics)
storage.set(wallet: address)
updateWalletContext()
}
}

private func saveMnemonicsIfNeeded(for account: String, mnemonics: [String]) {
guard !securityService.mnemonicsExists(for: account) else { return }
if !self.securityService.save(mnemonics: mnemonics, for: account) {
log.error("Failed to save mnemonics info")
}
}
}

protocol HasSubscriptionsService { var subscriptionsService: SubscriptionsServiceType { get } }
extension CommonContext: HasSubscriptionsService {}

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

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

protocol HasTunnelManager { var tunnelManager: TunnelManagerType { get } }
extension CommonContext: HasTunnelManager {}

protocol HasSessionsService { var sessionsService: SessionsServiceType { get } }
extension CommonContext: HasSessionsService {}

// MARK: - Storages

protocol HasConnectionInfoStorage { var connectionInfoStorage: StoresConnectInfo { get } }
extension CommonContext: HasConnectionInfoStorage {
var connectionInfoStorage: StoresConnectInfo {
storage as StoresConnectInfo
}
}

protocol HasWalletStorage { var walletStorage: StoresWallet { get } }
extension CommonContext: HasWalletStorage {
var walletStorage: StoresWallet {
storage as StoresWallet
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,82 @@
//

import Foundation
import SentinelWallet
import SOLARAPI

/// This class should configure all required services and inject them into a Context
final class ContextBuilder {
func buildContext() -> CommonContext {
let nodesProvider = NodesProvider(configuration: .init(baseURL: ClientConstants.backendURL))
let generalSettingsStorage = GeneralSettingsStorage()

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

let securityService = SecurityService()
let subscriptionsProvider = SubscriptionsProvider(configuration: ApplicationConfiguration.shared)
let sessionProvider = NodeSessionProvider()
let walletService = buildWalletService(storage: generalSettingsStorage, securityService: securityService)

let sessionsService = SessionsService(
sessionProvider: sessionProvider,
subscriptionsProvider: subscriptionsProvider,
walletService: walletService
)
let subscriptionsService = SubscriptionsService(
subscriptionsProvider: subscriptionsProvider,
walletService: walletService
)

let tunnelManager = TunnelManager(storage: generalSettingsStorage)

return CommonContext(
storage: generalSettingsStorage,
nodesProvider: nodesProvider,
nodesService: nodesService
securityService: securityService,
walletService: walletService,
nodesService: nodesService,
subscriptionsService: subscriptionsService,
sessionsService: sessionsService,
tunnelManager: tunnelManager
)
}

func buildWalletService(
storage: StoresWallet,
securityService: SecurityService
) -> WalletService {
let walletAddress = storage.walletAddress
let grpc = ApplicationConfiguration.shared
guard !walletAddress.isEmpty else {
let mnemonic = securityService.generateMnemonics().components(separatedBy: " ")
switch securityService.restore(from: mnemonic) {
case .failure(let error):
fatalError("failed to generate wallet due to \(error), terminate")
case .success(let address):
saveMnemonicsIfNeeded(for: address, mnemonics: mnemonic, securityService: securityService)
storage.set(wallet: address)
return .init(
for: address,
configuration: grpc,
securityService: securityService
)
}
}
return WalletService(
for: walletAddress,
configuration: grpc,
securityService: securityService
)
}

private func saveMnemonicsIfNeeded(
for account: String,
mnemonics: [String],
securityService: SecurityService
) {
guard !securityService.mnemonicsExists(for: account) else { return }
if !securityService.save(mnemonics: mnemonics, for: account) {
log.error("Failed to save mnemonics info")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// TunnelRouteCollection.swift
// SOLARdVPNCommunityCoreiOS
//
// Created by Lika Vorobeva on 30.09.2022.
//

import Vapor
import Combine

enum TunnelRouteEvent: String {
case alreadyConnected
case subscriptionCanceled
}

class TunnelRouteCollection: RouteCollection {
private let model: ConnectionModel
private var cancellables = Set<AnyCancellable>()

// Connection Status
@Published private(set) var isConnected: Bool = false
private weak var delegate: WebSocketDelegate?

init(model: ConnectionModel, delegate: WebSocketDelegate?) {
self.model = model
self.delegate = delegate

subscribeToEvents()
model.setInitData()
}

func boot(routes: RoutesBuilder) throws {
routes.post("connection", use: createNewSession)
routes.delete("connection", use: startDeactivationOfActiveTunnel)
}
}

extension TunnelRouteCollection {
#warning("TODO add result")
func startDeactivationOfActiveTunnel(_ req: Request) async throws -> Bool {
model.disconnect()

return true
}

#warning("TODO add result & pass node")
func createNewSession(_ req: Request) async throws -> Bool {
if isConnected {
return true // && add status TunnelRouteEvent
}
model.connect()
return true
}
}

// MARK: - Subscribe to events

extension TunnelRouteCollection {
private func subscribeToEvents() {
model.eventPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case let .error(error):
self.send(error: error)
case let .warning(warning):
self.send(warning: warning)
case let .info(text):
self.send(info: text)
case let .updateTunnelActivity(isActive):
self.updateConnection(isConnected: isActive)
}
}
.store(in: &cancellables)
}
}

// MARK: - Handle events

extension TunnelRouteCollection {
private func send(error: Error) {
#warning("TODO: send json with error")
delegate?.send(event: error.localizedDescription)
}

private func send(warning: Error) {
#warning("TODO: send json with warning")
delegate?.send(event: warning.localizedDescription)
}

private func send(info: String) {
#warning("TODO: send json with info")
delegate?.send(event: info)
}

private func updateConnection(isConnected: Bool) {
#warning("TODO: send json with isConnected")
self.isConnected = isConnected
delegate?.send(event: "isConnected \(isConnected)")
}
}

This file was deleted.

0 comments on commit 6d40715

Please sign in to comment.