package update import ( "context" "errors" "io" "time" "tera-clone/services/tera-api/internal/storage/capacity" ) const ( ApplyCapabilityValidationOnly = "validation-only" ApplyCapabilityRecoveryV1 = "recovery-v1" RecoveryCapabilityOfflineV1 = "offline-resumable-v1" StateIdle = "idle" StateReceiving = "receiving" StateStaged = "staged" StateValidating = "validating" StateValidated = "validated" StateApplyPending = "apply_pending" StateRebootPending = "reboot_pending" StateApplying = "applying" StateVerifying = "verifying" StateSucceeded = "succeeded" StateFailed = "failed" ) type Payload struct { Name string `json:"name"` Path string `json:"path"` Class string `json:"class"` Size int64 `json:"size"` SHA256 string `json:"sha256"` TargetPartition string `json:"target_partition,omitempty"` Encoding string `json:"encoding,omitempty"` ExpandedSize int64 `json:"expanded_size,omitempty"` ExpandedSHA256 string `json:"expanded_sha256,omitempty"` } type Manifest struct { FormatVersion int `json:"format_version"` PackageID string `json:"package_id"` Product string `json:"product"` HardwareProfile string `json:"hardware_profile"` Version string `json:"version"` MinimumCurrentVersion string `json:"minimum_current_version,omitempty"` AllowDowngrade bool `json:"allow_downgrade"` CreatedAt time.Time `json:"created_at"` SigningKeyID string `json:"signing_key_id"` Payloads []Payload `json:"payloads"` Apply struct { Capability string `json:"capability"` RebootRequired bool `json:"reboot_required"` } `json:"apply"` Recovery struct { Capability string `json:"capability"` Instructions string `json:"instructions"` } `json:"recovery"` } type Status struct { FormatVersion int `json:"format_version"` OperationID string `json:"operation_id,omitempty"` State string `json:"state"` Message string `json:"message"` Filename string `json:"filename,omitempty"` DeviceVersion string `json:"device_version,omitempty"` BytesReceived int64 `json:"bytes_received"` BytesTotal int64 `json:"bytes_total"` ProgressPercent int `json:"progress_percent"` PackagePath string `json:"-"` Manifest *Manifest `json:"manifest,omitempty"` SignerKeyID string `json:"signer_key_id,omitempty"` // ApplyPolicy is persisted by field firmware; retain it across upgrades. ApplyPolicy string `json:"apply_policy,omitempty"` ApplyEnabled bool `json:"apply_enabled"` ApplyDisabledReason string `json:"apply_disabled_reason,omitempty"` RecoveryInstructions string `json:"recovery_instructions,omitempty"` FailureCode string `json:"failure_code,omitempty"` FailureReason string `json:"failure_reason,omitempty"` RecoveryStep string `json:"recovery_step,omitempty"` RecoveryAttempt int `json:"recovery_attempt,omitempty"` Capacity capacity.Snapshot `json:"capacity"` CreatedAt time.Time `json:"created_at,omitempty"` UpdatedAt time.Time `json:"updated_at"` } type UploadRequest struct { Filename string ContentLength int64 Actor string Body io.Reader } type ApplyRequest struct { Actor string OperationID string } type Controller interface { Status(context.Context) (Status, error) Upload(context.Context, UploadRequest) (Status, error) Apply(context.Context, ApplyRequest) (Status, error) } type Error struct { Code string Message string } func (e *Error) Error() string { return e.Message } func Code(err error) string { var updateErr *Error if errors.As(err, &updateErr) { return updateErr.Code } return "" } type UnavailableController struct{ Reason string } func (u UnavailableController) unavailable() error { reason := u.Reason if reason == "" { reason = "tera-updated is unavailable" } return &Error{Code: "update_unavailable", Message: reason} } func (u UnavailableController) Status(context.Context) (Status, error) { return Status{}, u.unavailable() } func (u UnavailableController) Upload(context.Context, UploadRequest) (Status, error) { return Status{}, u.unavailable() } func (u UnavailableController) Apply(context.Context, ApplyRequest) (Status, error) { return Status{}, u.unavailable() } type FactoryResetter interface{ FactoryReset(context.Context) error }