SEBRAUC/src/rauc/rauc.go

133 lines
2.4 KiB
Go

package rauc
import (
"bufio"
"encoding/json"
"fmt"
"os"
"regexp"
"strconv"
"sync"
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
)
var (
expPercentage = regexp.MustCompile(`^ *(\d+)% +(.+)`)
expLastError = regexp.MustCompile(`^LastError: +(.+)`)
)
type Rauc struct {
broadcast chan string
status RaucStatus
runningMtx sync.Mutex
}
type RaucStatus struct {
Installing bool `json:"installing"`
Percent int `json:"percent"`
Message string `json:"message"`
LastError string `json:"last_error"`
Log string `json:"log"`
}
func NewRauc(broadcast chan string) *Rauc {
r := &Rauc{
broadcast: broadcast,
}
r.broadcast <- r.GetStatusJson()
return r
}
func (r *Rauc) completed(updateFile string) {
r.status.Installing = false
r.broadcast <- r.GetStatusJson()
_ = os.Remove(updateFile)
}
func (r *Rauc) RunRauc(updateFile string) error {
// Check file input
if !util.DoesFileExist(updateFile) {
return util.ErrFileDoesNotExist
}
// Only run one instance at a time
r.runningMtx.Lock()
isRunning := r.status.Installing
r.status.Installing = true
r.runningMtx.Unlock()
if isRunning {
return util.ErrAlreadyRunning
}
// Reset installer
r.status = RaucStatus{
Installing: true,
}
r.broadcast <- r.GetStatusJson()
cmd := util.CommandFromString(fmt.Sprintf("%s install %s", util.RaucCmd, updateFile))
readPipe, _ := cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout
scanner := bufio.NewScanner(readPipe)
go func() {
for scanner.Scan() {
line := scanner.Text()
hasUpdate := false
if line != "idle" && line != "installing" {
r.status.Log += line + "\n"
}
match := expPercentage.FindStringSubmatch(line)
if match != nil {
r.status.Percent, _ = strconv.Atoi(match[1])
r.status.Message = match[2]
hasUpdate = true
} else {
match = expLastError.FindStringSubmatch(line)
if match != nil {
r.status.LastError = match[1]
hasUpdate = true
}
}
if hasUpdate {
r.broadcast <- r.GetStatusJson()
}
}
}()
err := cmd.Start()
if err != nil {
r.completed(updateFile)
return err
}
go func() {
err := cmd.Wait()
if err != nil {
fmt.Printf("RAUC failed with %s\n", err)
}
r.completed(updateFile)
}()
return nil
}
func (r *Rauc) GetStatus() RaucStatus {
return r.status
}
func (r *Rauc) GetStatusJson() string {
statusJson, _ := json.Marshal(r.status)
return string(statusJson)
}