Skip to content

Commit

Permalink
🔀 Merge branch 'yann/improvements/lekaupdater/fix-persistant-sha256-o…
Browse files Browse the repository at this point in the history
…n-ipad-and-remove-verify-after-file-sended-transition'
  • Loading branch information
ladislas committed Oct 13, 2023
2 parents 458e6a0 + 6ab2602 commit d558c93
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ enum UpdateProcessError: Error {
case failedToLoadFile
case robotNotUpToDate
case robotUnexpectedDisconnection

// LekaOS 1.3.0+
case failedToVerifyFile
}

// MARK: - Controller
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,83 @@ private class StateSettingDestinationPath: GKState, StateEventProcessor {
}
}

private class StateVerifyingFile: GKState, StateEventProcessor {

private var cancellables: Set<AnyCancellable> = []

private var isFileValid = false
private let defaultValue = "0000000000000000000000000000000000000000000000000000000000000000"

override func isValidNextState(_ stateClass: AnyClass) -> Bool {
stateClass is StateClearingFile.Type || stateClass is StateApplyingUpdate.Type
|| stateClass is StateErrorRobotUnexpectedDisconnection.Type
}

override func didEnter(from previousState: GKState?) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: startFileVerification)
}

override func willExit(to nextState: GKState) {
cancellables.removeAll()
globalRobotManager.sha256 = nil
}

func process(event: UpdateEvent) {
switch event {
case .fileVerificationReceived:
if isFileValid {
self.stateMachine?.enter(StateApplyingUpdate.self)
} else {
self.stateMachine?.enter(StateClearingFile.self)
}
case .robotDisconnected:
self.stateMachine?.enter(StateErrorRobotUnexpectedDisconnection.self)
default:
return
}
}

private func startFileVerification() {
DispatchQueue.main.asyncAfter(deadline: .now(), execute: subscribeActualSHA256Updates)
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: readRequestSHA256)
}

private func subscribeActualSHA256Updates() {
globalRobotManager.$sha256
.receive(on: DispatchQueue.main)
.sink { value in
guard let value = value else { return }

if value == self.defaultValue {
return
}

self.isFileValid = value == globalFirmwareManager.sha256
self.process(event: .fileVerificationReceived)
}
.store(in: &cancellables)
}

private func readRequestSHA256() {
globalRobotManager.robotPeripheral?.peripheral
.readValue(
forCharacteristic: BLESpecs.FileExchange.Characteristics.fileSHA256,
inService: BLESpecs.FileExchange.service
)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { _ in
// nothing to do
},
receiveValue: { data in
// nothing to do
}
)
.store(in: &cancellables)
}

}

private class StateClearingFile: GKState, StateEventProcessor {

override func isValidNextState(_ stateClass: AnyClass) -> Bool {
Expand Down Expand Up @@ -244,7 +321,7 @@ private class StateSendingFile: GKState, StateEventProcessor {
}

override func isValidNextState(_ stateClass: AnyClass) -> Bool {
stateClass is StateVerifyingFile.Type || stateClass is StateErrorRobotUnexpectedDisconnection.Type
stateClass is StateApplyingUpdate.Type || stateClass is StateErrorRobotUnexpectedDisconnection.Type
}

override func didEnter(from previousState: GKState?) {
Expand All @@ -258,7 +335,7 @@ private class StateSendingFile: GKState, StateEventProcessor {
func process(event: UpdateEvent) {
switch event {
case .fileSent:
self.stateMachine?.enter(StateVerifyingFile.self)
self.stateMachine?.enter(StateApplyingUpdate.self)
case .robotDisconnected:
self.stateMachine?.enter(StateErrorRobotUnexpectedDisconnection.self)
default:
Expand Down Expand Up @@ -291,94 +368,6 @@ private class StateSendingFile: GKState, StateEventProcessor {
}
}

private class StateVerifyingFile: GKState, StateEventProcessor {

private var cancellables: Set<AnyCancellable> = []

private var isFileValid = false
private var lastValue = "0000000000000000000000000000000000000000000000000000000000000000"

private var nextStateIsClearingFile = false

override func isValidNextState(_ stateClass: AnyClass) -> Bool {
stateClass is StateClearingFile.Type || stateClass is StateApplyingUpdate.Type
|| stateClass is StateErrorFailedToVerifyFile.Type
|| stateClass is StateErrorRobotUnexpectedDisconnection.Type
}

override func didEnter(from previousState: GKState?) {
if previousState is StateSettingDestinationPath {
nextStateIsClearingFile = true
} else {
nextStateIsClearingFile = false
}

DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: startFileVerification)
}

override func willExit(to nextState: GKState) {
cancellables.removeAll()
}

func process(event: UpdateEvent) {
switch event {
case .fileVerificationReceived:
if isFileValid {
self.stateMachine?.enter(StateApplyingUpdate.self)
} else if nextStateIsClearingFile {
self.stateMachine?.enter(StateClearingFile.self)
} else {
self.stateMachine?.enter(StateErrorFailedToVerifyFile.self)
}
case .robotDisconnected:
self.stateMachine?.enter(StateErrorRobotUnexpectedDisconnection.self)
default:
return
}
}

private func startFileVerification() {
subscribeActualSHA256Updates()
readRequestSHA256()
}

private func subscribeActualSHA256Updates() {
globalRobotManager.$sha256
.receive(on: DispatchQueue.main)
.sink { value in
guard let value = value else { return }

if value == self.lastValue {
return
}
self.lastValue = value

self.isFileValid = value == globalFirmwareManager.sha256
self.process(event: .fileVerificationReceived)
}
.store(in: &cancellables)
}

private func readRequestSHA256() {
globalRobotManager.robotPeripheral?.peripheral
.readValue(
forCharacteristic: BLESpecs.FileExchange.Characteristics.fileSHA256,
inService: BLESpecs.FileExchange.service
)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { _ in
// nothing to do
},
receiveValue: { data in
// nothing to do
}
)
.store(in: &cancellables)
}

}

private class StateApplyingUpdate: GKState, StateEventProcessor {

private var cancellables: Set<AnyCancellable> = []
Expand Down Expand Up @@ -512,7 +501,6 @@ private class StateFinal: GKState {}
private protocol StateError {}

private class StateErrorFailedToLoadFile: GKState, StateError {}
private class StateErrorFailedToVerifyFile: GKState, StateError {}
private class StateErrorRobotNotUpToDate: GKState, StateError {}
private class StateErrorRobotUnexpectedDisconnection: GKState, StateError {}

Expand Down Expand Up @@ -549,7 +537,6 @@ class UpdateProcessV130: UpdateProcessProtocol {
StateFinal(),

StateErrorFailedToLoadFile(),
StateErrorFailedToVerifyFile(),
StateErrorRobotNotUpToDate(),
StateErrorRobotUnexpectedDisconnection(),
])
Expand Down Expand Up @@ -616,8 +603,6 @@ class UpdateProcessV130: UpdateProcessProtocol {
switch state {
case is StateErrorFailedToLoadFile:
currentStage.send(completion: .failure(.failedToLoadFile))
case is StateErrorFailedToVerifyFile:
currentStage.send(completion: .failure(.failedToVerifyFile))
case is StateErrorRobotNotUpToDate:
currentStage.send(completion: .failure(.robotNotUpToDate))
case is StateErrorRobotUnexpectedDisconnection:
Expand Down
2 changes: 2 additions & 0 deletions Apps/LekaUpdater/Sources/Model/RobotManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class RobotManager: ObservableObject {
self.battery = battery
self.isCharging = isCharging
self.osVersion = osVersion
self.sha256 = nil

}

Expand All @@ -37,6 +38,7 @@ public class RobotManager: ObservableObject {
self.battery = robotDiscovery.battery
self.isCharging = robotDiscovery.isCharging
self.osVersion = robotDiscovery.osVersion
self.sha256 = nil

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,6 @@ class UpdateStatusViewModel: ObservableObject {
Redémarrer le robot à l'aide de la carte \"Arrêt d'urgence\",
reconnectez le robot et relancez le processus
"""
case .failedToVerifyFile:
self.errorDescription = """
Echec de la réception de la mise à jour
(Code erreur #0005)
"""
self.errorInstruction = "Reconnectez le robot et relancez le processus"
default:
self.errorDescription = """
Une erreur inconnue s'est produite
Expand Down

0 comments on commit d558c93

Please sign in to comment.