exocore 0.1.1

Distributed applications framework
Documentation

import SwiftUI
import Combine
import KeychainSwift
import Exocore

class AppState: ObservableObject {
    private let keychain = KeychainSwift()

    let objectWillChange = PassthroughSubject<AppState, Never>()

    @Published var node: LocalNode?
    @Published var nodeConfig: Exocore_Core_LocalNodeConfig?
    @Published var currentError: String?
    @Published var forceDiscovery: Bool = false

    var currentView: Page {
        get {
            if forceDiscovery || !nodeHasCell {
                return .discovery
            }

            return .list
        }
    }

    var nodeHasCell: Bool {
        get {
            (self.nodeConfig?.cells.count ?? 0) > 0
        }
    }

    static func fromPersisted() -> AppState {
        let state = AppState()

        if let configData = state.keychain.getData("node"),
           let nodeConfig = try? Exocore_Core_LocalNodeConfig(serializedData: configData),
           let node = try? LocalNode.from(config: nodeConfig) {
            state.node = node
            state.nodeConfig = nodeConfig
        }

        if state.node == nil {
            state.node = try? LocalNode.generate()
            state.refreshNodeConfig()
        }

        state.maybeInitializeExocore()
        state.triggerChanged()

        return state
    }

    func refreshNodeConfig() {
        // update latest config
        if let node = self.node,
           let newConfig = try? node.config() {
            self.nodeConfig = newConfig
        }

        // save config to keychain
        if let config = self.nodeConfig {
            let configData = try! config.serializedData()
            self.keychain.set(configData, forKey: "node")
        }

        self.maybeInitializeExocore()
        self.triggerChanged()
    }

    func maybeInitializeExocore() {
        if let node = self.node, self.nodeHasCell {
            do {
                try ExocoreClient.initialize(node: node)
                self.currentError = nil
            } catch {
                print("Error initializing client with configured node: \(error)")
                self.node = nil
                self.nodeConfig = nil
                self.currentError = error.localizedDescription
            }
        }
    }

    func triggerChanged() {
        self.objectWillChange.send(self)
    }
}

enum Page {
    case discovery
    case list
}