Files
NanoKVM-MIRROR/server/service/application/update.go
2025-12-26 15:38:05 +08:00

134 lines
2.5 KiB
Go

package application
import (
"crypto/sha512"
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"time"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"NanoKVM-Server/proto"
"NanoKVM-Server/utils"
)
const (
maxTries = 3
)
func (s *Service) Update(c *gin.Context) {
var rsp proto.Response
if !acquireUpdateLock() {
rsp.ErrRsp(c, -1, "update already in progress")
return
}
defer releaseUpdateLock()
if err := update(); err != nil {
rsp.ErrRsp(c, -1, fmt.Sprintf("update failed: %s", err))
return
}
rsp.OkRsp(c)
log.Debugf("update application success")
// Sleep for a second before restarting the device
time.Sleep(1 * time.Second)
_ = exec.Command("sh", "-c", "/etc/init.d/S95nanokvm restart").Run()
}
func update() error {
_ = os.RemoveAll(CacheDir)
_ = os.MkdirAll(CacheDir, 0o755)
defer func() {
_ = os.RemoveAll(CacheDir)
}()
// get latest information
latest, err := getLatest()
if err != nil {
return err
}
// download
target := fmt.Sprintf("%s/%s", CacheDir, latest.Name)
if err := download(latest.Url, target); err != nil {
log.Errorf("download app failed: %s", err)
return err
}
// check sha512
if err := checksum(target, latest.Sha512); err != nil {
log.Errorf("check sha512 failed: %s", err)
return err
}
// install
if err := installPackage(target); err != nil {
log.Errorf("failed to install package: %v", err)
return err
}
return nil
}
func download(url string, target string) (err error) {
for i := range maxTries {
log.Debugf("attempt #%d/%d", i+1, maxTries)
if i > 0 {
time.Sleep(time.Second * 3)
}
var req *http.Request
req, err = http.NewRequest("GET", url, nil)
if err != nil {
log.Errorf("new request err: %s", err)
continue
}
log.Debugf("update will be saved to: %s", target)
err = utils.Download(req, target)
if err != nil {
log.Errorf("downloading latest application failed, try again...")
continue
}
return nil
}
return err
}
func checksum(filePath string, expectedHash string) error {
file, err := os.Open(filePath)
if err != nil {
log.Errorf("failed to open file %s: %v", filePath, err)
return err
}
defer func() {
_ = file.Close()
}()
hasher := sha512.New()
_, err = io.Copy(hasher, file)
if err != nil {
log.Errorf("failed to copy file contents to hasher: %v", err)
return err
}
hash := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
if hash != expectedHash {
log.Errorf("invalid sha512 %s", hash)
return fmt.Errorf("invalid sha512 %s", hash)
}
return nil
}