cleanup: ota state

This commit is contained in:
Siyuan 2025-10-31 16:15:42 +00:00
parent 2447e8fff2
commit 9e8ada32b3
6 changed files with 84 additions and 56 deletions

View File

@ -27,14 +27,14 @@ func (s *State) updateApp(ctx context.Context, appUpdate *componentUpdateStatus)
l := s.l.With().Str("path", appUpdatePath).Logger()
if err := s.downloadFile(ctx, appUpdatePath, appUpdate.url, &appUpdate.downloadProgress); err != nil {
if err := s.downloadFile(ctx, appUpdatePath, appUpdate.url, "app"); err != nil {
return s.componentUpdateError("Error downloading app update", err, &l)
}
downloadFinished := time.Now()
appUpdate.downloadFinishedAt = downloadFinished
appUpdate.downloadProgress = 1
s.triggerStateUpdate()
s.triggerComponentUpdateState("app", appUpdate)
if err := s.verifyFile(
appUpdatePath,
@ -48,7 +48,7 @@ func (s *State) updateApp(ctx context.Context, appUpdate *componentUpdateStatus)
appUpdate.verificationProgress = 1
appUpdate.updatedAt = verifyFinished
appUpdate.updateProgress = 1
s.triggerStateUpdate()
s.triggerComponentUpdateState("app", appUpdate)
l.Info().Msg("App update downloaded")

View File

@ -92,6 +92,11 @@ func (s *State) triggerStateUpdate() {
s.onStateUpdate(s.ToRPCState())
}
func (s *State) triggerComponentUpdateState(component string, update *componentUpdateStatus) {
s.componentUpdateStatuses[component] = *update
s.triggerStateUpdate()
}
func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
scopedLogger := s.l.With().
Interface("params", params).
@ -102,32 +107,35 @@ func (s *State) doUpdate(ctx context.Context, params UpdateParams) error {
return fmt.Errorf("update already in progress")
}
s.updating = true
s.triggerStateUpdate()
defer func() {
s.updating = false
if !params.CheckOnly {
s.updating = true
s.triggerStateUpdate()
}()
defer func() {
s.updating = false
s.triggerStateUpdate()
}()
}
appUpdate, systemUpdate, err := s.getUpdateStatus(ctx, params)
if err != nil {
return s.componentUpdateError("Error checking for updates", err, &scopedLogger)
}
s.metadataFetchedAt = time.Now()
s.triggerStateUpdate()
if params.CheckOnly {
return nil
}
s.metadataFetchedAt = time.Now()
s.triggerStateUpdate()
if appUpdate.available || appUpdate.downgradeAvailable {
appUpdate.pending = true
s.triggerComponentUpdateState("app", appUpdate)
}
if systemUpdate.available || systemUpdate.downgradeAvailable {
systemUpdate.pending = true
s.triggerComponentUpdateState("system", systemUpdate)
}
if appUpdate.pending {

View File

@ -67,25 +67,25 @@ type componentUpdateStatus struct {
// RPCState represents the current OTA state for the RPC API
type RPCState struct {
Updating bool `json:"updating"`
Error string `json:"error,omitempty"`
MetadataFetchedAt time.Time `json:"metadataFetchedAt,omitempty"`
AppUpdatePending bool `json:"appUpdatePending"`
SystemUpdatePending bool `json:"systemUpdatePending"`
AppDownloadProgress float32 `json:"appDownloadProgress,omitempty"` //TODO: implement for progress bar
AppDownloadFinishedAt time.Time `json:"appDownloadFinishedAt,omitempty"`
SystemDownloadProgress float32 `json:"systemDownloadProgress,omitempty"` //TODO: implement for progress bar
SystemDownloadFinishedAt time.Time `json:"systemDownloadFinishedAt,omitempty"`
AppVerificationProgress float32 `json:"appVerificationProgress,omitempty"`
AppVerifiedAt time.Time `json:"appVerifiedAt,omitempty"`
SystemVerificationProgress float32 `json:"systemVerificationProgress,omitempty"`
SystemVerifiedAt time.Time `json:"systemVerifiedAt,omitempty"`
AppUpdateProgress float32 `json:"appUpdateProgress,omitempty"` //TODO: implement for progress bar
AppUpdatedAt time.Time `json:"appUpdatedAt,omitempty"`
SystemUpdateProgress float32 `json:"systemUpdateProgress,omitempty"` //TODO: port rk_ota, then implement
SystemUpdatedAt time.Time `json:"systemUpdatedAt,omitempty"`
SystemTargetVersion string `json:"systemTargetVersion,omitempty"`
AppTargetVersion string `json:"appTargetVersion,omitempty"`
Updating bool `json:"updating"`
Error string `json:"error,omitempty"`
MetadataFetchedAt *time.Time `json:"metadataFetchedAt,omitempty"`
AppUpdatePending bool `json:"appUpdatePending"`
SystemUpdatePending bool `json:"systemUpdatePending"`
AppDownloadProgress *float32 `json:"appDownloadProgress,omitempty"` //TODO: implement for progress bar
AppDownloadFinishedAt *time.Time `json:"appDownloadFinishedAt,omitempty"`
SystemDownloadProgress *float32 `json:"systemDownloadProgress,omitempty"` //TODO: implement for progress bar
SystemDownloadFinishedAt *time.Time `json:"systemDownloadFinishedAt,omitempty"`
AppVerificationProgress *float32 `json:"appVerificationProgress,omitempty"`
AppVerifiedAt *time.Time `json:"appVerifiedAt,omitempty"`
SystemVerificationProgress *float32 `json:"systemVerificationProgress,omitempty"`
SystemVerifiedAt *time.Time `json:"systemVerifiedAt,omitempty"`
AppUpdateProgress *float32 `json:"appUpdateProgress,omitempty"` //TODO: implement for progress bar
AppUpdatedAt *time.Time `json:"appUpdatedAt,omitempty"`
SystemUpdateProgress *float32 `json:"systemUpdateProgress,omitempty"` //TODO: port rk_ota, then implement
SystemUpdatedAt *time.Time `json:"systemUpdatedAt,omitempty"`
SystemTargetVersion *string `json:"systemTargetVersion,omitempty"`
AppTargetVersion *string `json:"appTargetVersion,omitempty"`
}
// HwRebootFunc is a function that reboots the hardware
@ -221,35 +221,48 @@ func NewState(opts Options) *State {
}
// ToRPCState converts the State to the RPCState
// probably we need a generator for this ...
func (s *State) ToRPCState() *RPCState {
r := &RPCState{
Updating: s.updating,
Error: s.error,
MetadataFetchedAt: s.metadataFetchedAt,
MetadataFetchedAt: &s.metadataFetchedAt,
}
app, ok := s.componentUpdateStatuses["app"]
if ok {
r.AppUpdatePending = app.pending
r.AppDownloadProgress = app.downloadProgress
r.AppDownloadFinishedAt = app.downloadFinishedAt
r.AppVerificationProgress = app.verificationProgress
r.AppVerifiedAt = app.verifiedAt
r.AppUpdateProgress = app.updateProgress
r.AppUpdatedAt = app.updatedAt
r.AppTargetVersion = app.targetVersion
r.AppDownloadProgress = &app.downloadProgress
if !app.downloadFinishedAt.IsZero() {
r.AppDownloadFinishedAt = &app.downloadFinishedAt
}
r.AppVerificationProgress = &app.verificationProgress
if !app.verifiedAt.IsZero() {
r.AppVerifiedAt = &app.verifiedAt
}
r.AppUpdateProgress = &app.updateProgress
if !app.updatedAt.IsZero() {
r.AppUpdatedAt = &app.updatedAt
}
r.AppTargetVersion = &app.targetVersion
}
system, ok := s.componentUpdateStatuses["system"]
if ok {
r.SystemUpdatePending = system.pending
r.SystemDownloadProgress = system.downloadProgress
r.SystemDownloadFinishedAt = system.downloadFinishedAt
r.SystemVerificationProgress = system.verificationProgress
r.SystemVerifiedAt = system.verifiedAt
r.SystemUpdateProgress = system.updateProgress
r.SystemUpdatedAt = system.updatedAt
r.SystemTargetVersion = system.targetVersion
r.SystemDownloadProgress = &system.downloadProgress
if !system.downloadFinishedAt.IsZero() {
r.SystemDownloadFinishedAt = &system.downloadFinishedAt
}
r.SystemVerificationProgress = &system.verificationProgress
if !system.verifiedAt.IsZero() {
r.SystemVerifiedAt = &system.verifiedAt
}
r.SystemUpdateProgress = &system.updateProgress
if !system.updatedAt.IsZero() {
r.SystemUpdatedAt = &system.updatedAt
}
r.SystemTargetVersion = &system.targetVersion
}
return r

View File

@ -17,14 +17,14 @@ func (s *State) updateSystem(ctx context.Context, systemUpdate *componentUpdateS
l := s.l.With().Str("path", systemUpdatePath).Logger()
if err := s.downloadFile(ctx, systemUpdatePath, systemUpdate.url, &systemUpdate.downloadProgress); err != nil {
if err := s.downloadFile(ctx, systemUpdatePath, systemUpdate.url, "system"); err != nil {
return s.componentUpdateError("Error downloading system update", err, &l)
}
downloadFinished := time.Now()
systemUpdate.downloadFinishedAt = downloadFinished
systemUpdate.downloadProgress = 1
s.triggerStateUpdate()
s.triggerComponentUpdateState("system", systemUpdate)
if err := s.verifyFile(
systemUpdatePath,
@ -38,7 +38,7 @@ func (s *State) updateSystem(ctx context.Context, systemUpdate *componentUpdateS
systemUpdate.verificationProgress = 1
systemUpdate.updatedAt = verifyFinished
systemUpdate.updateProgress = 1
s.triggerStateUpdate()
s.triggerComponentUpdateState("system", systemUpdate)
l.Info().Msg("System update downloaded")
@ -68,7 +68,7 @@ func (s *State) updateSystem(ctx context.Context, systemUpdate *componentUpdateS
if systemUpdate.updateProgress > 0.99 {
systemUpdate.updateProgress = 0.99
}
s.triggerStateUpdate()
s.triggerComponentUpdateState("system", systemUpdate)
case <-ctx.Done():
return
}
@ -86,7 +86,7 @@ func (s *State) updateSystem(ctx context.Context, systemUpdate *componentUpdateS
rkLogger.Info().Msg("rk_ota success")
systemUpdate.updateProgress = 1
systemUpdate.updatedAt = verifyFinished
s.triggerStateUpdate()
s.triggerComponentUpdateState("system", systemUpdate)
return nil
}

View File

@ -25,7 +25,14 @@ func syncFilesystem() error {
return nil
}
func (s *State) downloadFile(ctx context.Context, path string, url string, downloadProgress *float32) error {
func (s *State) downloadFile(ctx context.Context, path string, url string, component string) error {
componentUpdate, ok := s.componentUpdateStatuses[component]
if !ok {
return fmt.Errorf("component %s not found", component)
}
downloadProgress := componentUpdate.downloadProgress
if _, err := os.Stat(path); err == nil {
if err := os.Remove(path); err != nil {
return fmt.Errorf("error removing existing file: %w", err)
@ -80,9 +87,9 @@ func (s *State) downloadFile(ctx context.Context, path string, url string, downl
return fmt.Errorf("error writing to file: %w", ew)
}
progress := float32(written) / float32(totalSize)
if progress-*downloadProgress >= 0.01 {
*downloadProgress = progress
s.triggerStateUpdate()
if progress-downloadProgress >= 0.01 {
componentUpdate.downloadProgress = progress
s.triggerComponentUpdateState(component, &componentUpdate)
}
}
if er != nil {

View File

@ -199,7 +199,7 @@ export default function SettingsAdvancedRoute() {
// Navigate to update page
navigateTo("/settings/general/update");
});
}, [updateTarget, appVersion, systemVersion, devChannel, send, navigateTo]);
}, [appVersion, systemVersion, devChannel, send, navigateTo]);
return (
<div className="space-y-4">