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) }