feat(onbaording): implement basic function for the new onboarding

Fixes #16832

Implements all the needed basic Nim functions for the new onboarding.

They do no do anything just yet. They shall be integrated in another commit.
This commit is contained in:
Jonathan Rainville 2024-12-19 14:33:10 -05:00
parent 3dd5fa9443
commit a54d864120
15 changed files with 386 additions and 17 deletions

View File

@ -3,6 +3,7 @@ import NimQml, sequtils, sugar, chronicles, uuids
import app_service/service/general/service as general_service import app_service/service/general/service as general_service
import app_service/service/keychain/service as keychain_service import app_service/service/keychain/service as keychain_service
import app_service/service/keycard/service as keycard_service import app_service/service/keycard/service as keycard_service
import app_service/service/keycardV2/service as keycard_serviceV2
import app_service/service/accounts/service as accounts_service import app_service/service/accounts/service as accounts_service
import app_service/service/contacts/service as contacts_service import app_service/service/contacts/service as contacts_service
import app_service/service/language/service as language_service import app_service/service/language/service as language_service
@ -70,6 +71,7 @@ type
# Services # Services
generalService: general_service.Service generalService: general_service.Service
keycardService*: keycard_service.Service keycardService*: keycard_service.Service
keycardServiceV2*: keycard_serviceV2.Service
keychainService: keychain_service.Service keychainService: keychain_service.Service
accountsService: accounts_service.Service accountsService: accounts_service.Service
contactsService: contacts_service.Service contactsService: contacts_service.Service
@ -169,6 +171,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
# Services # Services
result.generalService = general_service.newService(statusFoundation.events, statusFoundation.threadpool) result.generalService = general_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.keycardService = keycard_service.newService(statusFoundation.events, statusFoundation.threadpool) result.keycardService = keycard_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.keycardServiceV2 = keycard_serviceV2.newService(statusFoundation.events, statusFoundation.threadpool)
result.nodeConfigurationService = node_configuration_service.newService(statusFoundation.fleetConfiguration, result.nodeConfigurationService = node_configuration_service.newService(statusFoundation.fleetConfiguration,
result.settingsService, statusFoundation.events) result.settingsService, statusFoundation.events)
result.keychainService = keychain_service.newService(statusFoundation.events) result.keychainService = keychain_service.newService(statusFoundation.events)
@ -255,6 +258,10 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.onboardingModule = onboarding_module.newModule[AppController]( result.onboardingModule = onboarding_module.newModule[AppController](
result, result,
statusFoundation.events, statusFoundation.events,
result.generalService,
result.accountsService,
result.devicesService,
result.keycardServiceV2,
) )
result.mainModule = main_module.newModule[AppController]( result.mainModule = main_module.newModule[AppController](
result, result,
@ -353,6 +360,7 @@ proc delete*(self: AppController) =
self.ensService.delete self.ensService.delete
self.tokensService.delete self.tokensService.delete
self.keycardService.delete self.keycardService.delete
self.keycardServiceV2.delete
self.networkConnectionService.delete self.networkConnectionService.delete
self.metricsService.delete self.metricsService.delete
@ -421,6 +429,7 @@ proc mainDidLoad*(self: AppController) =
proc start*(self: AppController) = proc start*(self: AppController) =
self.keycardService.init() self.keycardService.init()
self.keycardServiceV2.init()
self.keychainService.init() self.keychainService.init()
self.generalService.init() self.generalService.init()
self.accountsService.init() self.accountsService.init()

View File

@ -106,5 +106,5 @@ proc validateConnectionString*(self: Controller, connectionString: string): stri
proc getConnectionStringForBootstrappingAnotherDevice*(self: Controller, password, chatKey: string): string = proc getConnectionStringForBootstrappingAnotherDevice*(self: Controller, password, chatKey: string): string =
return self.devicesService.getConnectionStringForBootstrappingAnotherDevice(password, chatKey) return self.devicesService.getConnectionStringForBootstrappingAnotherDevice(password, chatKey)
proc inputConnectionStringForBootstrapping*(self: Controller, connectionString: string): string = proc inputConnectionStringForBootstrapping*(self: Controller, connectionString: string) =
return self.devicesService.inputConnectionStringForBootstrapping(connectionString) self.devicesService.inputConnectionStringForBootstrapping(connectionString)

View File

@ -59,7 +59,7 @@ method onLoggedInUserAuthenticated*(self: AccessInterface, pin: string, password
proc validateConnectionString*(self: AccessInterface, connectionString: string): string = proc validateConnectionString*(self: AccessInterface, connectionString: string): string =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method inputConnectionStringForBootstrapping*(self: AccessInterface, connectionString: string): string {.base.} = method inputConnectionStringForBootstrapping*(self: AccessInterface, connectionString: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onLocalPairingStatusUpdate*(self: AccessInterface, status: LocalPairingStatus) {.base.} = method onLocalPairingStatusUpdate*(self: AccessInterface, status: LocalPairingStatus) {.base.} =

View File

@ -120,8 +120,8 @@ method onLoggedInUserAuthenticated*(self: Module, pin: string, password: string,
proc validateConnectionString*(self: Module, connectionString: string): string = proc validateConnectionString*(self: Module, connectionString: string): string =
return self.controller.validateConnectionString(connectionString) return self.controller.validateConnectionString(connectionString)
method inputConnectionStringForBootstrapping*(self: Module, connectionString: string): string = method inputConnectionStringForBootstrapping*(self: Module, connectionString: string) =
return self.controller.inputConnectionStringForBootstrapping(connectionString) self.controller.inputConnectionStringForBootstrapping(connectionString)
method onLocalPairingStatusUpdate*(self: Module, status: LocalPairingStatus) = method onLocalPairingStatusUpdate*(self: Module, status: LocalPairingStatus) =
self.view.onLocalPairingStatusUpdate(status) self.view.onLocalPairingStatusUpdate(status)

View File

@ -139,5 +139,5 @@ QtObject:
proc validateConnectionString*(self: View, connectionString: string): string {.slot.} = proc validateConnectionString*(self: View, connectionString: string): string {.slot.} =
return self.delegate.validateConnectionString(connectionString) return self.delegate.validateConnectionString(connectionString)
proc inputConnectionStringForBootstrapping*(self: View, connectionString: string): string {.slot.} = proc inputConnectionStringForBootstrapping*(self: View, connectionString: string) {.slot.} =
return self.delegate.inputConnectionStringForBootstrapping(connectionString) self.delegate.inputConnectionStringForBootstrapping(connectionString)

View File

@ -1,7 +1,12 @@
import chronicles import chronicles, strutils
import io_interface import io_interface
import app/core/eventemitter import app/core/eventemitter
import app_service/service/general/service as general_service
import app_service/service/accounts/service as accounts_service
import app_service/service/accounts/dto/image_crop_rectangle
import app_service/service/devices/service as devices_service
import app_service/service/keycardV2/service as keycard_serviceV2
logScope: logScope:
topics = "onboarding-controller" topics = "onboarding-controller"
@ -10,15 +15,80 @@ type
Controller* = ref object of RootObj Controller* = ref object of RootObj
delegate: io_interface.AccessInterface delegate: io_interface.AccessInterface
events: EventEmitter events: EventEmitter
generalService: general_service.Service
accountsService: accounts_service.Service
devicesService: devices_service.Service
keycardServiceV2: keycard_serviceV2.Service
proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter): proc newController*(
delegate: io_interface.AccessInterface,
events: EventEmitter,
generalService: general_service.Service,
accountsService: accounts_service.Service,
devicesService: devices_service.Service,
keycardServiceV2: keycard_serviceV2.Service,
):
Controller = Controller =
result = Controller() result = Controller()
result.delegate = delegate result.delegate = delegate
result.events = events result.events = events
result.generalService = generalService
result.accountsService = accountsService
result.devicesService = devicesService
result.keycardServiceV2 = keycardServiceV2
proc delete*(self: Controller) = proc delete*(self: Controller) =
discard discard
proc init*(self: Controller) = proc init*(self: Controller) =
discard discard
proc setPin*(self: Controller, pin: string): bool =
self.keycardServiceV2.setPin(pin)
discard
proc getPasswordStrengthScore*(self: Controller, password, userName: string): int =
return self.generalService.getPasswordStrengthScore(password, userName)
proc validMnemonic*(self: Controller, mnemonic: string): bool =
let (_, err) = self.accountsService.validateMnemonic(mnemonic)
if err.len == 0:
return true
return false
proc buildSeedPhrasesFromIndexes(self: Controller, seedPhraseIndexes: seq[int]): string =
if seedPhraseIndexes.len == 0:
error "keycard error: cannot generate mnemonic"
return
let sp = self.keycardServiceV2.buildSeedPhrasesFromIndexes(seedPhraseIndexes)
return sp.join(" ")
proc getMnemonic*(self: Controller): string =
let indexes = self.keycardServiceV2.getMnemonicIndexes()
return self.buildSeedPhrasesFromIndexes(indexes)
proc validateLocalPairingConnectionString*(self: Controller, connectionString: string): bool =
let err = self.devicesService.validateConnectionString(connectionString)
return err.len == 0
proc inputConnectionStringForBootstrapping*(self: Controller, connectionString: string) =
self.devicesService.inputConnectionStringForBootstrapping(connectionString)
proc createAccountAndLogin*(self: Controller, password: string): string =
return self.accountsService.createAccountAndLogin(
password,
displayName = "",
imagePath = "",
ImageCropRectangle(),
)
proc restoreAccountAndLogin*(self: Controller, password, mnemonic: string, recoverAccount: bool, keycardInstanceUID: string): string =
return self.accountsService.importAccountAndLogin(
mnemonic,
password,
recoverAccount,
displayName = "",
imagePath = "",
ImageCropRectangle(),
keycardInstanceUID,
)

View File

@ -10,6 +10,27 @@ method onAppLoaded*(self: AccessInterface) {.base.} =
method load*(self: AccessInterface) {.base.} = method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setPin*(self: AccessInterface, pin: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getPasswordStrengthScore*(self: AccessInterface, password, userName: string): int {.base.} =
raise newException(ValueError, "No implementation available")
method validMnemonic*(self: AccessInterface, mnemonic: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getMnemonic*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method validateLocalPairingConnectionString*(self: AccessInterface, connectionString: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method inputConnectionStringForBootstrapping*(self: AccessInterface, connectionString: string) {.base.} =
raise newException(ValueError, "No implementation available")
method finishOnboardingFlow*(self: AccessInterface, primaryFlowInt, secondaryFlowInt: int, dataJson: string): string {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController # This way (using concepts) is used only for the modules managed by AppController
type type
DelegateInterface* = concept c DelegateInterface* = concept c

View File

@ -5,12 +5,32 @@ import view, controller
import app/global/global_singleton import app/global/global_singleton
import app/core/eventemitter import app/core/eventemitter
import app_service/service/general/service as general_service
import app_service/service/accounts/service as accounts_service
import app_service/service/devices/service as devices_service
import app_service/service/keycardV2/service as keycard_serviceV2
export io_interface export io_interface
logScope: logScope:
topics = "onboarding-module" topics = "onboarding-module"
type PrimaryFlow* {.pure} = enum
Unknown = 0,
CreateProfile,
Login
type SecondaryFlow* {.pure} = enum
Unknown = 0,
CreateProfileWithPassword,
CreateProfileWithSeedphrase,
CreateProfileWithKeycard,
CreateProfileWithKeycardNewSeedphrase,
CreateProfileWithKeycardExistingSeedphrase,
LoginWithSeedphrase,
LoginWithSyncing,
LoginWithKeycard
type type
Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T delegate: T
@ -18,12 +38,26 @@ type
viewVariant: QVariant viewVariant: QVariant
controller: Controller controller: Controller
proc newModule*[T](delegate: T, events: EventEmitter): Module[T] = proc newModule*[T](
delegate: T,
events: EventEmitter,
generalService: general_service.Service,
accountsService: accounts_service.Service,
devicesService: devices_service.Service,
keycardServiceV2: keycard_serviceV2.Service,
): Module[T] =
result = Module[T]() result = Module[T]()
result.delegate = delegate result.delegate = delegate
result.view = view.newView(result) result.view = view.newView(result)
result.viewVariant = newQVariant(result.view) result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events) result.controller = controller.newController(
result,
events,
generalService,
accountsService,
devicesService,
keycardServiceV2,
)
{.push warning[Deprecated]: off.} {.push warning[Deprecated]: off.}
@ -46,4 +80,83 @@ method load*[T](self: Module[T]) =
self.controller.init() self.controller.init()
self.delegate.onboardingDidLoad() self.delegate.onboardingDidLoad()
method setPin*[T](self: Module[T], pin: string): bool =
self.controller.setPin(pin)
method getPasswordStrengthScore*[T](self: Module[T], password, userName: string): int =
self.controller.getPasswordStrengthScore(password, userName)
method validMnemonic*[T](self: Module[T], mnemonic: string): bool =
self.controller.validMnemonic(mnemonic)
method getMnemonic*[T](self: Module[T]): string =
self.controller.getMnemonic()
method validateLocalPairingConnectionString*[T](self: Module[T], connectionString: string): bool =
self.controller.validateLocalPairingConnectionString(connectionString)
method inputConnectionStringForBootstrapping*[T](self: Module[T], connectionString: string) =
self.controller.inputConnectionStringForBootstrapping(connectionString)
method finishOnboardingFlow*[T](self: Module[T], primaryFlowInt, secondaryFlowInt: int, dataJson: string): string =
try:
let primaryFlow = PrimaryFlow(primaryFlowInt)
let secondaryFlow = SecondaryFlow(secondaryFlowInt)
let data = parseJson(dataJson)
let password = data["password"].str
let seedPhrase = data["seedPhrase"].str
var err = ""
# CREATE PROFILE PRIMARY FLOW
if primaryFlow == PrimaryFlow.CreateProfile:
case secondaryFlow:
of SecondaryFlow.CreateProfileWithPassword:
err = self.controller.createAccountAndLogin(password)
of SecondaryFlow.CreateProfileWithSeedphrase:
err = self.controller.restoreAccountAndLogin(
password,
seedPhrase,
recoverAccount = false,
keycardInstanceUID = "",
)
of SecondaryFlow.CreateProfileWithKeycard:
# TODO implement keycard function
discard
of SecondaryFlow.CreateProfileWithKeycardNewSeedphrase:
# TODO implement keycard function
discard
of SecondaryFlow.CreateProfileWithKeycardExistingSeedphrase:
# TODO implement keycard function
discard
else:
raise newException(ValueError, "Unknown secondary flow for CreateProfile: " & $secondaryFlow)
# LOGIN PRIMARY FLOW
elif primaryFlow == PrimaryFlow.Login:
case secondaryFlow:
of SecondaryFlow.LoginWithSeedphrase:
err = self.controller.restoreAccountAndLogin(
password,
seedPhrase,
recoverAccount = true,
keycardInstanceUID = "",
)
of SecondaryFlow.LoginWithSyncing:
self.controller.inputConnectionStringForBootstrapping(data["connectionString"].str)
of SecondaryFlow.LoginWithKeycard:
# TODO implement keycard function
discard
else:
raise newException(ValueError, "Unknown secondary flow for Login: " & $secondaryFlow)
if err != "":
raise newException(ValueError, err)
else:
raise newException(ValueError, "Unknown primary flow: " & $primaryFlow)
except Exception as e:
error "Error finishing Onboarding Flow", msg = e.msg
return e.msg
{.pop.} {.pop.}

View File

@ -1,10 +1,14 @@
import NimQml, json import NimQml
import io_interface import io_interface
QtObject: QtObject:
type type
View* = ref object of QObject View* = ref object of QObject
delegate: io_interface.AccessInterface delegate: io_interface.AccessInterface
syncState: int
keycardState: int
keycardRemainingPinAttempts: int
addKeyPairState: int
proc delete*(self: View) = proc delete*(self: View) =
self.QObject.delete self.QObject.delete
@ -13,3 +17,72 @@ QtObject:
new(result, delete) new(result, delete)
result.QObject.setup result.QObject.setup
result.delegate = delegate result.delegate = delegate
proc syncStateChanged*(self: View) {.signal.}
proc getSyncState(self: View): int {.slot.} =
return self.syncState
QtProperty[int] syncState:
read = getSyncState
notify = syncStateChanged
proc setSyncState(self: View, syncState: int) =
self.syncState = syncState
self.syncStateChanged()
proc keycardStateChanged*(self: View) {.signal.}
proc getKeycardState(self: View): int {.slot.} =
return self.keycardState
QtProperty[int] keycardState:
read = getKeycardState
notify = keycardStateChanged
proc setKeycardState(self: View, keycardState: int) =
self.keycardState = keycardState
self.keycardStateChanged()
proc keycardRemainingPinAttemptsChanged*(self: View) {.signal.}
proc getKeycardRemainingPinAttempts(self: View): int {.slot.} =
return self.keycardRemainingPinAttempts
QtProperty[int] keycardRemainingPinAttempts:
read = getKeycardRemainingPinAttempts
notify = keycardRemainingPinAttemptsChanged
proc setKeycardRemainingPinAttempts(self: View, keycardRemainingPinAttempts: int) =
self.keycardRemainingPinAttempts = keycardRemainingPinAttempts
self.keycardRemainingPinAttemptsChanged()
proc addKeyPairStateChanged*(self: View) {.signal.}
proc getAddKeyPairState(self: View): int {.slot.} =
return self.addKeyPairState
QtProperty[int] addKeyPairState:
read = getAddKeyPairState
notify = addKeyPairStateChanged
proc setAddKeyPairState(self: View, addKeyPairState: int) =
self.addKeyPairState = addKeyPairState
self.addKeyPairStateChanged()
proc setPin(self: View, pin: string): bool {.slot.} =
return self.delegate.setPin(pin)
# TODO find what does this do
# proc startKeypairTransfer(self: View) {.slot.} =
# self.delegate.startKeypairTransfer()
proc getPasswordStrengthScore(self: View, password: string, userName: string): int {.slot.} =
return self.delegate.getPasswordStrengthScore(password, userName)
proc validMnemonic(self: View, mnemonic: string): bool {.slot.} =
return self.delegate.validMnemonic(mnemonic)
proc getMnemonic(self: View): string {.slot.} =
return self.delegate.getMnemonic()
proc validateLocalPairingConnectionString(self: View, connectionString: string): bool {.slot.} =
return self.delegate.validateLocalPairingConnectionString(connectionString)
proc inputConnectionStringForBootstrapping(self: View, connectionString: string) {.slot.} =
self.delegate.inputConnectionStringForBootstrapping(connectionString)
# TODO find what does this do
# proc mnemonicWasShown(self: View): string {.slot.} =
# return self.delegate.getMnemonic()
proc finishOnboardingFlow(self: View, primaryFlowInt: int, secondaryFlowInt: int, dataJson: string): string {.slot.} =
self.delegate.finishOnboardingFlow(primaryFlowInt, secondaryFlowInt, dataJson)

View File

@ -609,8 +609,8 @@ proc setConnectionString*(self: Controller, connectionString: string) =
proc validateLocalPairingConnectionString*(self: Controller, connectionString: string): string = proc validateLocalPairingConnectionString*(self: Controller, connectionString: string): string =
return self.devicesService.validateConnectionString(connectionString) return self.devicesService.validateConnectionString(connectionString)
proc inputConnectionStringForBootstrapping*(self: Controller, connectionString: string): string = proc inputConnectionStringForBootstrapping*(self: Controller, connectionString: string) =
return self.devicesService.inputConnectionStringForBootstrapping(connectionString) self.devicesService.inputConnectionStringForBootstrapping(connectionString)
proc setLoggedInAccount*(self: Controller, account: AccountDto) = proc setLoggedInAccount*(self: Controller, account: AccountDto) =
self.accountsService.setLoggedInAccount(account) self.accountsService.setLoggedInAccount(account)

View File

@ -10,7 +10,7 @@ proc delete*(self: SyncDeviceWithSyncCodeState) =
method executePrimaryCommand*(self: SyncDeviceWithSyncCodeState, controller: Controller) = method executePrimaryCommand*(self: SyncDeviceWithSyncCodeState, controller: Controller) =
let connectionString = controller.getConnectionString() let connectionString = controller.getConnectionString()
discard controller.inputConnectionStringForBootstrapping(connectionString) controller.inputConnectionStringForBootstrapping(connectionString)
method getNextPrimaryState*(self: SyncDeviceWithSyncCodeState, controller: Controller): State = method getNextPrimaryState*(self: SyncDeviceWithSyncCodeState, controller: Controller): State =
return createState(StateType.SyncDeviceResult, self.flowType, self) return createState(StateType.SyncDeviceResult, self.flowType, self)

View File

@ -233,7 +233,7 @@ QtObject:
self.localPairingStatus = newLocalPairingStatus(PairingType.AppSync, LocalPairingMode.Sender) self.localPairingStatus = newLocalPairingStatus(PairingType.AppSync, LocalPairingMode.Sender)
return status_go.getConnectionStringForBootstrappingAnotherDevice($configJSON) return status_go.getConnectionStringForBootstrappingAnotherDevice($configJSON)
proc inputConnectionStringForBootstrapping*(self: Service, connectionString: string): string = proc inputConnectionStringForBootstrapping*(self: Service, connectionString: string) =
let configJSON = %* { let configJSON = %* {
"receiverConfig": %* { "receiverConfig": %* {
"createAccount": %*accounts_service.defaultCreateAccountRequest(), "createAccount": %*accounts_service.defaultCreateAccountRequest(),

View File

@ -0,0 +1,16 @@
type
AsyncSetPinTaskArg = ref object of QObjectTaskArg
pin: string
proc asyncSetPinTask(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncSetPinTaskArg](argEncoded)
try:
# TODO Call function from keycard_go
echo "Set pin ", arg.pin
arg.finish(%*{
"error": ""
})
except Exception as e:
arg.finish(%* {
"error": e.msg,
})

View File

@ -0,0 +1,67 @@
import NimQml, json, chronicles, strutils
# import keycard_go
import app/global/global_singleton
import app/core/eventemitter
import app/core/tasks/[qt, threadpool]
include ../../common/mnemonics
include async_tasks
logScope:
topics = "keycardV2-service"
QtObject:
type Service* = ref object of QObject
events: EventEmitter
threadpool: ThreadPool
proc delete*(self: Service) =
self.QObject.delete
proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
new(result, delete)
result.QObject.setup
result.events = events
result.threadpool = threadpool
proc init*(self: Service) =
discard
proc receiveKeycardSignal(self: Service, signal: string) {.slot.} =
var jsonSignal: JsonNode
try:
jsonSignal = signal.parseJson
except:
error "Invalid signal received", data = signal
return
debug "keycard_signal", response=signal
proc buildSeedPhrasesFromIndexes*(self: Service, seedPhraseIndexes: seq[int]): seq[string] =
var seedPhrase: seq[string]
for ind in seedPhraseIndexes:
seedPhrase.add(englishWords[ind])
return seedPhrase
proc getMnemonicIndexes*(self: Service): seq[int] =
# TODO call lib to get mnemonic indexes
echo "Get mnemonic indexes"
return @[]
proc setPin*(self: Service, pin: string) =
let arg = AsyncSetPinTaskArg(
tptr: asyncSetPinTask,
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncSetPinResponse",
pin: pin,
)
self.threadpool.start(arg)
proc onAsyncSetPinResponse*(self: Service, response: string) {.slot.} =
try:
let rpcResponseObj = response.parseJson
echo "Set the pin ", response
if (rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != ""):
raise newException(CatchableError, rpcResponseObj{"error"}.getStr)
except Exception as e:
error "error set pin: ", msg = e.msg

View File

@ -46,6 +46,6 @@ QtObject {
} }
function inputConnectionStringForBootstrapping(connectionString) { function inputConnectionStringForBootstrapping(connectionString) {
return root.devicesModule.inputConnectionStringForBootstrapping(connectionString) root.devicesModule.inputConnectionStringForBootstrapping(connectionString)
} }
} }