Compare commits
No commits in common. "71764dd6fa43541b946dbd662878a780064e0185" and "8714ad966b0a8beef1ece028db22a7501d017578" have entirely different histories.
71764dd6fa
...
8714ad966b
26 changed files with 283 additions and 442 deletions
|
@ -9,6 +9,14 @@ repos:
|
||||||
|
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
|
- id: check-swagger
|
||||||
|
name: check-swagger
|
||||||
|
language: system
|
||||||
|
files: swagger.yaml
|
||||||
|
entry: swagger
|
||||||
|
args: ["validate", "swagger.yaml"]
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
- id: tsc
|
- id: tsc
|
||||||
name: tsc
|
name: tsc
|
||||||
entry: tsc
|
entry: tsc
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -1,8 +1,6 @@
|
||||||
SRC_DIR=./src
|
SRC_DIR=./src
|
||||||
UI_DIR=./ui
|
UI_DIR=./ui
|
||||||
|
|
||||||
APIDOC_FILE=./src/server/swagger/swagger.yaml
|
|
||||||
|
|
||||||
VERSION=$(shell git tag --sort=-version:refname | head -n 1)
|
VERSION=$(shell git tag --sort=-version:refname | head -n 1)
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
|
@ -24,10 +22,10 @@ build-server:
|
||||||
build: build-ui build-server
|
build: build-ui build-server
|
||||||
|
|
||||||
generate-apidoc:
|
generate-apidoc:
|
||||||
SWAGGER_GENERATE_EXTENSION=false swagger generate spec --scan-models -o ${APIDOC_FILE}
|
SWAGGER_GENERATE_EXTENSION=false swagger generate spec --scan-models -o swagger.yaml
|
||||||
|
|
||||||
generate-apiclient:
|
generate-apiclient:
|
||||||
openapi-generator generate -i ${APIDOC_FILE} -g typescript-axios -o ${UI_DIR}/src/sebrauc-client -p "supportsES6=true"
|
openapi-generator generate -i swagger.yaml -g typescript-axios -o ${UI_DIR}/src/sebrauc-client -p "supportsES6=true"
|
||||||
cd ${UI_DIR} && npm run format
|
cd ${UI_DIR} && npm run format
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -4,11 +4,9 @@ go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.thetadev.de/TSGRain/ginzip v0.1.1
|
code.thetadev.de/TSGRain/ginzip v0.1.1
|
||||||
github.com/ekyoung/gin-nice-recovery v0.0.0-20160510022553-1654dca486db
|
|
||||||
github.com/fortytw2/leaktest v1.3.0
|
github.com/fortytw2/leaktest v1.3.0
|
||||||
github.com/gin-contrib/cors v1.3.1
|
github.com/gin-contrib/cors v1.3.1
|
||||||
github.com/gin-gonic/gin v1.7.7
|
github.com/gin-gonic/gin v1.7.7
|
||||||
github.com/go-errors/errors v1.4.1 // indirect
|
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -5,8 +5,6 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/ekyoung/gin-nice-recovery v0.0.0-20160510022553-1654dca486db h1:oZ4U9IqO8NS+61OmGTBi8vopzqTRxwQeogyBHdrhjbc=
|
|
||||||
github.com/ekyoung/gin-nice-recovery v0.0.0-20160510022553-1654dca486db/go.mod h1:Pk7/9x6tyChFTkahDvLBQMlvdsWvfC+yU8HTT5VD314=
|
|
||||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
|
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
|
||||||
|
@ -16,8 +14,6 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||||
github.com/go-errors/errors v1.4.1 h1:IvVlgbzSsaUNudsw5dcXSzF3EWyXTi5XrAdngnuhRyg=
|
|
||||||
github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||||
|
|
8
src/assets/assets.go
Normal file
8
src/assets/assets.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package assets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed files/**
|
||||||
|
var Assets embed.FS
|
88
src/assets/files/index.html
Normal file
88
src/assets/files/index.html
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<!-- See https://github.com/gorilla/websocket/blob/master/examples/chat/home.html -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Chat Example</title>
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.onload = function () {
|
||||||
|
var conn
|
||||||
|
var msg = document.getElementById("msg")
|
||||||
|
var log = document.getElementById("log")
|
||||||
|
|
||||||
|
function appendLog(item) {
|
||||||
|
var doScroll =
|
||||||
|
log.scrollTop > log.scrollHeight - log.clientHeight - 1
|
||||||
|
log.appendChild(item)
|
||||||
|
if (doScroll) {
|
||||||
|
log.scrollTop = log.scrollHeight - log.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window["WebSocket"]) {
|
||||||
|
conn = new WebSocket("ws://" + document.location.host + "/api/ws")
|
||||||
|
conn.onclose = function (evt) {
|
||||||
|
var item = document.createElement("div")
|
||||||
|
item.innerHTML = "<b>Connection closed.</b>"
|
||||||
|
appendLog(item)
|
||||||
|
}
|
||||||
|
conn.onmessage = function (evt) {
|
||||||
|
var messages = evt.data.split("\n")
|
||||||
|
for (var i = 0; i < messages.length; i++) {
|
||||||
|
var item = document.createElement("div")
|
||||||
|
item.innerText = messages[i]
|
||||||
|
appendLog(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var item = document.createElement("div")
|
||||||
|
item.innerHTML = "<b>Your browser does not support WebSockets.</b>"
|
||||||
|
appendLog(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style type="text/css">
|
||||||
|
html {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log {
|
||||||
|
background: white;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||||
|
position: absolute;
|
||||||
|
top: 4em;
|
||||||
|
left: 0.5em;
|
||||||
|
right: 0.5em;
|
||||||
|
bottom: 3em;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form {
|
||||||
|
padding: 0 0.5em 0 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1em;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<input type="file" name="updateFile" id="file" />
|
||||||
|
<input type="submit" name="submit" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
src/main.go
12
src/main.go
|
@ -3,28 +3,20 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/rauc"
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/server"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/mode"
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/stream"
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("SEBRAUC " + util.Version())
|
fmt.Println("SEBRAUC " + util.Version())
|
||||||
mode.Set(util.Mode)
|
|
||||||
|
|
||||||
if mode.IsDev() {
|
if util.TestMode {
|
||||||
fmt.Println("Test mode active - no update operations are executed.")
|
fmt.Println("Test mode active - no update operations are executed.")
|
||||||
fmt.Println("Build with -tags prod to enable live mode.")
|
fmt.Println("Build with -tags prod to enable live mode.")
|
||||||
}
|
}
|
||||||
|
|
||||||
streamer := stream.New(10*time.Second, 1*time.Second, []string{})
|
srv := server.NewServer(":8080")
|
||||||
raucUpdater := &rauc.Rauc{}
|
|
||||||
|
|
||||||
srv := server.NewServer(":8080", streamer, raucUpdater)
|
|
||||||
err := srv.Run()
|
err := srv.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
// Error model
|
|
||||||
//
|
|
||||||
// The Error contains error relevant information.
|
|
||||||
//
|
|
||||||
//swagger:model Error
|
|
||||||
type Error struct {
|
|
||||||
// The general error message according to HTTP specification.
|
|
||||||
//
|
|
||||||
// required: true
|
|
||||||
// example: Unauthorized
|
|
||||||
Error string `json:"error"`
|
|
||||||
// The http error code.
|
|
||||||
//
|
|
||||||
// required: true
|
|
||||||
// example: 500
|
|
||||||
StatusCode int `json:"status_code"`
|
|
||||||
// Concrete error message.
|
|
||||||
//
|
|
||||||
// required: true
|
|
||||||
// example: already running
|
|
||||||
Message string `json:"msg"`
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
// RaucStatus model
|
|
||||||
//
|
|
||||||
// RaucStatus contains information about the current RAUC updater status.
|
|
||||||
//
|
|
||||||
//swagger:model RaucStatus
|
//swagger:model RaucStatus
|
||||||
type RaucStatus struct {
|
type RaucStatus struct {
|
||||||
// True if the installer is running
|
// True if the installer is running
|
||||||
|
@ -23,11 +19,13 @@ type RaucStatus struct {
|
||||||
|
|
||||||
// Installation error message
|
// Installation error message
|
||||||
// required: true
|
// required: true
|
||||||
// example: Failed to check bundle identifier: Invalid identifier.
|
//nolint:lll
|
||||||
|
// example: Failed to check bundle identifier: Invalid identifier. Did you pass a valid RAUC bundle?
|
||||||
LastError string `json:"last_error"`
|
LastError string `json:"last_error"`
|
||||||
|
|
||||||
// Full command line output of the current installation
|
// Full command line output of the current installation
|
||||||
// required: true
|
// required: true
|
||||||
// example: 0% Installing 0% Determining slot states 20% Determining slot states done
|
//nolint:lll
|
||||||
|
// example: 0% Installing\n0% Determining slot states\n20% Determining slot states done\n
|
||||||
Log string `json:"log"`
|
Log string `json:"log"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
// StatusMessage model
|
|
||||||
//
|
|
||||||
// StatusMessage contains the status of an operation.
|
|
||||||
//
|
|
||||||
//swagger:model StatusMessage
|
//swagger:model StatusMessage
|
||||||
type StatusMessage struct {
|
type StatusMessage struct {
|
||||||
// Is operation successful?
|
// Is operation successful?
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
// SystemInfo model
|
|
||||||
//
|
|
||||||
// SystemInfo contains information about the running system.
|
|
||||||
//
|
|
||||||
//swagger:model SystemInfo
|
//swagger:model SystemInfo
|
||||||
type SystemInfo struct {
|
type SystemInfo struct {
|
||||||
// Hostname of the system
|
// Hostname of the system
|
||||||
|
|
|
@ -19,14 +19,23 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Rauc struct {
|
type Rauc struct {
|
||||||
bc util.Broadcaster
|
bc broadcaster
|
||||||
status model.RaucStatus
|
status model.RaucStatus
|
||||||
runningMtx sync.Mutex
|
runningMtx sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rauc) SetBroadcaster(bc util.Broadcaster) {
|
type broadcaster interface {
|
||||||
r.bc = bc
|
Broadcast(msg []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRauc(bc broadcaster) *Rauc {
|
||||||
|
r := &Rauc{
|
||||||
|
bc: bc,
|
||||||
|
}
|
||||||
|
|
||||||
r.bc.Broadcast(r.GetStatusJson())
|
r.bc.Broadcast(r.GetStatusJson())
|
||||||
|
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rauc) completed(updateFile string) {
|
func (r *Rauc) completed(updateFile string) {
|
||||||
|
|
17
src/server/docs.go
Normal file
17
src/server/docs.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// SEBRAUC
|
||||||
|
//
|
||||||
|
// REST API for the SEBRAUC firmware updater
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// Schemes: http, https
|
||||||
|
// Version: 0.2.0
|
||||||
|
// License: MIT
|
||||||
|
//
|
||||||
|
// Consumes:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// Produces:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// swagger:meta
|
||||||
|
package server
|
|
@ -1,7 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
|
||||||
|
|
||||||
func Cache(c *gin.Context) {
|
|
||||||
c.Writer.Header().Set("Cache-Control", "public, max-age=604800, immutable")
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/model"
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
|
||||||
nice "github.com/ekyoung/gin-nice-recovery"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrorHandler creates a gin middleware for handling errors.
|
|
||||||
func ErrorHandler(isApi bool) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
c.Next()
|
|
||||||
|
|
||||||
if len(c.Errors) > 0 {
|
|
||||||
for _, e := range c.Errors {
|
|
||||||
writeError(c, e.Err, isApi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PanicHandler(isApi bool) gin.HandlerFunc {
|
|
||||||
return nice.Recovery(func(c *gin.Context, err interface{}) {
|
|
||||||
writeError(c, fmt.Errorf("panic: %s", err), isApi)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeError(c *gin.Context, err error, isApi bool) {
|
|
||||||
status := http.StatusInternalServerError
|
|
||||||
|
|
||||||
var httpErr util.HttpError
|
|
||||||
if errors.As(err, &httpErr) {
|
|
||||||
status = httpErr.StatusCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
// only write error message if there is no content
|
|
||||||
if c.Writer.Size() != -1 {
|
|
||||||
c.Status(status)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if isApi {
|
|
||||||
// Machine-readable JSON error message
|
|
||||||
c.JSON(status, &model.Error{
|
|
||||||
Error: http.StatusText(status),
|
|
||||||
StatusCode: status,
|
|
||||||
Message: err.Error(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// Human-readable error message
|
|
||||||
c.String(status, "%d %s: %s", status, http.StatusText(status), err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +1,15 @@
|
||||||
// SEBRAUC
|
|
||||||
//
|
|
||||||
// REST API for the SEBRAUC firmware updater
|
|
||||||
//
|
|
||||||
// ---
|
|
||||||
// Schemes: http, https
|
|
||||||
// Version: 0.2.0
|
|
||||||
// License: MIT
|
|
||||||
//
|
|
||||||
// swagger:meta
|
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/model"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/model"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/middleware"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/rauc"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/mode"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/server/mode"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/swagger"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/server/stream"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/sysinfo"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/sysinfo"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/ui"
|
"code.thetadev.de/TSGRain/SEBRAUC/ui"
|
||||||
|
@ -28,28 +18,17 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type serverStreamer interface {
|
|
||||||
util.Broadcaster
|
|
||||||
Handle(ctx *gin.Context)
|
|
||||||
Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
type serverUpdater interface {
|
|
||||||
GetStatus() model.RaucStatus
|
|
||||||
RunRauc(updateFile string) error
|
|
||||||
SetBroadcaster(bc util.Broadcaster)
|
|
||||||
}
|
|
||||||
|
|
||||||
type SEBRAUCServer struct {
|
type SEBRAUCServer struct {
|
||||||
address string
|
address string
|
||||||
streamer serverStreamer
|
raucUpdater *rauc.Rauc
|
||||||
udater serverUpdater
|
streamer *stream.API
|
||||||
tmpdir string
|
tmpdir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(address string, streamer serverStreamer,
|
func NewServer(address string) *SEBRAUCServer {
|
||||||
updater serverUpdater) *SEBRAUCServer {
|
streamer := stream.New(10*time.Second, 1*time.Second, []string{})
|
||||||
updater.SetBroadcaster(streamer)
|
|
||||||
|
raucUpdater := rauc.NewRauc(streamer)
|
||||||
|
|
||||||
tmpdir, err := util.GetTmpdir()
|
tmpdir, err := util.GetTmpdir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,79 +37,67 @@ func NewServer(address string, streamer serverStreamer,
|
||||||
|
|
||||||
return &SEBRAUCServer{
|
return &SEBRAUCServer{
|
||||||
address: address,
|
address: address,
|
||||||
udater: updater,
|
raucUpdater: raucUpdater,
|
||||||
streamer: streamer,
|
streamer: streamer,
|
||||||
tmpdir: tmpdir,
|
tmpdir: tmpdir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *SEBRAUCServer) Run() error {
|
func (srv *SEBRAUCServer) Run() error {
|
||||||
router := gin.New()
|
router := gin.Default()
|
||||||
router.Use(gin.Logger())
|
|
||||||
_ = router.SetTrustedProxies(nil)
|
|
||||||
|
|
||||||
if mode.IsDev() {
|
if mode.IsDev() {
|
||||||
router.Use(cors.Default())
|
router.Use(cors.Default())
|
||||||
}
|
}
|
||||||
|
|
||||||
router.Use(middleware.ErrorHandler(false), middleware.PanicHandler(false))
|
|
||||||
router.NoRoute(func(c *gin.Context) { c.Error(util.ErrPageNotFound) })
|
|
||||||
|
|
||||||
api := router.Group("/api",
|
|
||||||
middleware.ErrorHandler(true), middleware.PanicHandler(true))
|
|
||||||
|
|
||||||
// ROUTES
|
// ROUTES
|
||||||
api.GET("/ws", srv.streamer.Handle)
|
router.GET("/api/ws", srv.streamer.Handle)
|
||||||
api.GET("/status", srv.controllerStatus)
|
router.GET("/api/status", srv.controllerStatus)
|
||||||
api.GET("/info", srv.controllerInfo)
|
router.GET("/api/info", srv.controllerInfo)
|
||||||
|
|
||||||
api.POST("/update", srv.controllerUpdate)
|
router.POST("/api/update", srv.controllerUpdate)
|
||||||
api.POST("/reboot", srv.controllerReboot)
|
router.POST("/api/reboot", srv.controllerReboot)
|
||||||
|
|
||||||
// Error routes for testing
|
|
||||||
if mode.IsDev() {
|
|
||||||
router.GET("/error", srv.controllerError)
|
|
||||||
router.GET("/panic", srv.controllerPanic)
|
|
||||||
|
|
||||||
api.GET("/error", srv.controllerError)
|
|
||||||
api.GET("/panic", srv.controllerPanic)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// router.StaticFS("/", ui.GetFS())
|
||||||
ui.Register(router)
|
ui.Register(router)
|
||||||
|
|
||||||
swagger.Register(router)
|
|
||||||
|
|
||||||
return router.Run(srv.address)
|
return router.Run(srv.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:operation POST /update startUpdate
|
// @Description Start the update process
|
||||||
|
// @Route /update
|
||||||
//
|
//
|
||||||
// Start the update process
|
// _Param {name} {in} {goType} {required} {description}
|
||||||
|
// @Param updateFile form file true "Rauc firmware image file (*.raucb)"
|
||||||
//
|
//
|
||||||
// ---
|
// _Success {status} {jsonType} {goType} {description}
|
||||||
// consumes:
|
// @Success 200 object statusMessage
|
||||||
// - multipart/form-data
|
// @Failure 500 object statusMessage "Server error"
|
||||||
// produces: [application/json]
|
|
||||||
// parameters:
|
|
||||||
// - name: updateFile
|
|
||||||
// in: formData
|
|
||||||
// description: RAUC firmware image file (*.raucb)
|
|
||||||
// required: true
|
|
||||||
// type: file
|
|
||||||
// responses:
|
|
||||||
// 200:
|
|
||||||
// description: Ok
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/StatusMessage"
|
|
||||||
// 409:
|
|
||||||
// description: already running
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/Error"
|
|
||||||
// 500:
|
|
||||||
// description: Server Error
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/Error"
|
|
||||||
func (srv *SEBRAUCServer) controllerUpdate(c *gin.Context) {
|
func (srv *SEBRAUCServer) controllerUpdate(c *gin.Context) {
|
||||||
|
// swagger:operation POST /update startUpdate
|
||||||
|
//
|
||||||
|
// Start the update process
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// consumes:
|
||||||
|
// - multipart/form-data
|
||||||
|
// produces: [application/json]
|
||||||
|
// parameters:
|
||||||
|
// - name: updateFile
|
||||||
|
// in: formData
|
||||||
|
// description: Rauc firmware image file (*.raucb)
|
||||||
|
// required: true
|
||||||
|
// type: file
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/StatusMessage"
|
||||||
|
// 500:
|
||||||
|
// description: Server Error
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/StatusMessage"
|
||||||
|
|
||||||
file, err := c.FormFile("updateFile")
|
file, err := c.FormFile("updateFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
|
@ -151,93 +118,100 @@ func (srv *SEBRAUCServer) controllerUpdate(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = srv.udater.RunRauc(updateFile)
|
err = srv.raucUpdater.RunRauc(updateFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
writeStatus(c, true, "Update started")
|
writeStatus(c, true, "Update started")
|
||||||
} else if errors.Is(err, util.ErrAlreadyRunning) {
|
} else if errors.Is(err, util.ErrAlreadyRunning) {
|
||||||
writeStatus(c, false, "Updater already running")
|
c.AbortWithError(409, errors.New("already running"))
|
||||||
} else {
|
} else {
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:operation GET /status getStatus
|
|
||||||
//
|
|
||||||
// Get the current status of the RAUC updater
|
|
||||||
//
|
|
||||||
// ---
|
|
||||||
// produces: [application/json]
|
|
||||||
// responses:
|
|
||||||
// 200:
|
|
||||||
// description: Ok
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/RaucStatus"
|
|
||||||
// 500:
|
|
||||||
// description: Server Error
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/Error"
|
|
||||||
func (srv *SEBRAUCServer) controllerStatus(c *gin.Context) {
|
func (srv *SEBRAUCServer) controllerStatus(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, srv.udater.GetStatus())
|
// swagger:operation GET /status getStatus
|
||||||
|
//
|
||||||
|
// Get the current status of the RAUC updater
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces: [application/json]
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/RaucStatus"
|
||||||
|
// 500:
|
||||||
|
// description: Server Error
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/StatusMessage"
|
||||||
|
|
||||||
|
c.JSON(200, srv.raucUpdater.GetStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:operation GET /info getInfo
|
|
||||||
//
|
|
||||||
// Get the current system info
|
|
||||||
//
|
|
||||||
// ---
|
|
||||||
// produces: [application/json]
|
|
||||||
// responses:
|
|
||||||
// 200:
|
|
||||||
// description: Ok
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/SystemInfo"
|
|
||||||
// 500:
|
|
||||||
// description: Server Error
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/Error"
|
|
||||||
func (srv *SEBRAUCServer) controllerInfo(c *gin.Context) {
|
func (srv *SEBRAUCServer) controllerInfo(c *gin.Context) {
|
||||||
|
// swagger:operation GET /info getInfo
|
||||||
|
//
|
||||||
|
// Get the current system info
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces: [application/json]
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/SystemInfo"
|
||||||
|
// 500:
|
||||||
|
// description: Server Error
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/StatusMessage"
|
||||||
|
|
||||||
info, err := sysinfo.GetSysinfo()
|
info, err := sysinfo.GetSysinfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, info)
|
c.JSON(200, info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:operation GET /reboot startReboot
|
|
||||||
//
|
|
||||||
// Reboot the system
|
|
||||||
//
|
|
||||||
// ---
|
|
||||||
// produces: [application/json]
|
|
||||||
// responses:
|
|
||||||
// 200:
|
|
||||||
// description: Ok
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/StatusMessage"
|
|
||||||
// 500:
|
|
||||||
// description: Server Error
|
|
||||||
// schema:
|
|
||||||
// $ref: "#/definitions/Error"
|
|
||||||
func (srv *SEBRAUCServer) controllerReboot(c *gin.Context) {
|
func (srv *SEBRAUCServer) controllerReboot(c *gin.Context) {
|
||||||
|
// swagger:operation GET /reboot startReboot
|
||||||
|
//
|
||||||
|
// Reboot the system
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces: [application/json]
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/StatusMessage"
|
||||||
|
// 500:
|
||||||
|
// description: Server Error
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/StatusMessage"
|
||||||
|
|
||||||
go util.Reboot(5 * time.Second)
|
go util.Reboot(5 * time.Second)
|
||||||
|
|
||||||
writeStatus(c, true, "System is rebooting")
|
writeStatus(c, true, "System is rebooting")
|
||||||
}
|
}
|
||||||
|
|
||||||
// controllerError throws an error for testing
|
func errorHandler(c *gin.Context, err error) error {
|
||||||
func (srv *SEBRAUCServer) controllerError(c *gin.Context) {
|
// API error handling
|
||||||
c.Error(util.HttpErrNew("error test", http.StatusBadRequest))
|
if strings.HasPrefix(c.FullPath(), "/api") {
|
||||||
}
|
writeStatus(c, false, err.Error())
|
||||||
|
}
|
||||||
// controllerPanic panics for testing
|
return err
|
||||||
func (srv *SEBRAUCServer) controllerPanic(c *gin.Context) {
|
|
||||||
panic(errors.New("panic message"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeStatus(c *gin.Context, success bool, msg string) {
|
func writeStatus(c *gin.Context, success bool, msg string) {
|
||||||
c.JSON(http.StatusOK, model.StatusMessage{
|
status := 200
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
status = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(status, model.StatusMessage{
|
||||||
Success: success,
|
Success: success,
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package swagger
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/middleware"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed swagger.html
|
|
||||||
var swaggerHtml []byte
|
|
||||||
|
|
||||||
//go:embed swagger.yaml
|
|
||||||
var swaggerYaml []byte
|
|
||||||
|
|
||||||
func Register(r *gin.Engine) {
|
|
||||||
swg := r.Group("/api/swagger", middleware.Cache)
|
|
||||||
|
|
||||||
swg.GET("/", func(c *gin.Context) {
|
|
||||||
c.Data(200, "text/html", swaggerHtml)
|
|
||||||
})
|
|
||||||
swg.GET("/swagger.yaml", func(c *gin.Context) {
|
|
||||||
c.Data(200, "text/yaml", swaggerYaml)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>SEBRAUC API documentation</title>
|
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<redoc spec-url="swagger.yaml"></redoc>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -3,11 +3,9 @@
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import "code.thetadev.de/TSGRain/SEBRAUC/src/server/mode"
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RebootCmd = "shutdown -r 0"
|
RebootCmd = "shutdown -r 0"
|
||||||
RaucCmd = "rauc"
|
RaucCmd = "rauc"
|
||||||
|
|
||||||
Mode = mode.Prod
|
TestMode = false
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import "code.thetadev.de/TSGRain/SEBRAUC/src/server/mode"
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RebootCmd = "touch /tmp/sebrauc_reboot_test"
|
RebootCmd = "touch /tmp/sebrauc_reboot_test"
|
||||||
RaucCmd = "go run code.thetadev.de/TSGRain/SEBRAUC/src/fixtures/rauc_mock"
|
RaucCmd = "go run code.thetadev.de/TSGRain/SEBRAUC/src/fixtures/rauc_mock"
|
||||||
|
|
||||||
Mode = mode.Dev
|
TestMode = true
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import "errors"
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrAlreadyRunning = errors.New("rauc already running")
|
ErrAlreadyRunning = errors.New("rauc already running")
|
||||||
ErrFileDoesNotExist = errors.New("file does not exist")
|
ErrFileDoesNotExist = errors.New("file does not exist")
|
||||||
ErrPageNotFound = HttpErrNew("page not found", http.StatusNotFound)
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
type HttpError interface {
|
|
||||||
error
|
|
||||||
StatusCode() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpErr struct {
|
|
||||||
err error
|
|
||||||
statusCode int
|
|
||||||
}
|
|
||||||
|
|
||||||
func HttpErrWrap(e error, statusCode int) HttpError {
|
|
||||||
return &httpErr{
|
|
||||||
err: e,
|
|
||||||
statusCode: statusCode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HttpErrNew(msg string, statusCode int) HttpError {
|
|
||||||
return HttpErrWrap(errors.New(msg), statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *httpErr) Error() string {
|
|
||||||
if e.err == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return e.err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *httpErr) Unwrap() error {
|
|
||||||
return e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *httpErr) StatusCode() int {
|
|
||||||
return e.statusCode
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
type Broadcaster interface {
|
|
||||||
Broadcast(msg []byte)
|
|
||||||
}
|
|
|
@ -1,40 +1,20 @@
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
definitions:
|
definitions:
|
||||||
Error:
|
|
||||||
description: The Error contains error relevant information.
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
description: The general error message according to HTTP specification.
|
|
||||||
example: Unauthorized
|
|
||||||
type: string
|
|
||||||
msg:
|
|
||||||
description: Concrete error message.
|
|
||||||
example: already running
|
|
||||||
type: string
|
|
||||||
status_code:
|
|
||||||
description: The http error code.
|
|
||||||
example: 500
|
|
||||||
format: int64
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- error
|
|
||||||
- status_code
|
|
||||||
- msg
|
|
||||||
title: Error model
|
|
||||||
type: object
|
|
||||||
RaucStatus:
|
RaucStatus:
|
||||||
description: RaucStatus contains information about the current RAUC updater status.
|
|
||||||
properties:
|
properties:
|
||||||
installing:
|
installing:
|
||||||
description: True if the installer is running
|
description: True if the installer is running
|
||||||
type: boolean
|
type: boolean
|
||||||
last_error:
|
last_error:
|
||||||
description: Installation error message
|
description: Installation error message
|
||||||
example: "Failed to check bundle identifier: Invalid identifier."
|
example: "Failed to check bundle identifier: Invalid identifier. Did you pass
|
||||||
|
a valid RAUC bundle?"
|
||||||
type: string
|
type: string
|
||||||
log:
|
log:
|
||||||
description: Full command line output of the current installation
|
description: Full command line output of the current installation
|
||||||
example: 0% Installing 0% Determining slot states 20% Determining slot states
|
example: 0% Installing\n0% Determining slot states\n20% Determining slot states
|
||||||
done
|
done\n
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Current installation step
|
description: Current installation step
|
||||||
|
@ -52,7 +32,6 @@ definitions:
|
||||||
- message
|
- message
|
||||||
- last_error
|
- last_error
|
||||||
- log
|
- log
|
||||||
title: RaucStatus model
|
|
||||||
type: object
|
type: object
|
||||||
Rootfs:
|
Rootfs:
|
||||||
properties:
|
properties:
|
||||||
|
@ -86,7 +65,6 @@ definitions:
|
||||||
- primary
|
- primary
|
||||||
type: object
|
type: object
|
||||||
StatusMessage:
|
StatusMessage:
|
||||||
description: StatusMessage contains the status of an operation.
|
|
||||||
properties:
|
properties:
|
||||||
msg:
|
msg:
|
||||||
description: Status message text
|
description: Status message text
|
||||||
|
@ -98,10 +76,8 @@ definitions:
|
||||||
required:
|
required:
|
||||||
- success
|
- success
|
||||||
- msg
|
- msg
|
||||||
title: StatusMessage model
|
|
||||||
type: object
|
type: object
|
||||||
SystemInfo:
|
SystemInfo:
|
||||||
description: SystemInfo contains information about the running system.
|
|
||||||
properties:
|
properties:
|
||||||
hostname:
|
hostname:
|
||||||
description: Hostname of the system
|
description: Hostname of the system
|
||||||
|
@ -141,7 +117,6 @@ definitions:
|
||||||
- rauc_compatible
|
- rauc_compatible
|
||||||
- rauc_variant
|
- rauc_variant
|
||||||
- rauc_rootfs
|
- rauc_rootfs
|
||||||
title: SystemInfo model
|
|
||||||
type: object
|
type: object
|
||||||
info:
|
info:
|
||||||
description: REST API for the SEBRAUC firmware updater
|
description: REST API for the SEBRAUC firmware updater
|
||||||
|
@ -164,7 +139,7 @@ paths:
|
||||||
"500":
|
"500":
|
||||||
description: Server Error
|
description: Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Error"
|
$ref: "#/definitions/StatusMessage"
|
||||||
/reboot:
|
/reboot:
|
||||||
get:
|
get:
|
||||||
description: Reboot the system
|
description: Reboot the system
|
||||||
|
@ -179,7 +154,7 @@ paths:
|
||||||
"500":
|
"500":
|
||||||
description: Server Error
|
description: Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Error"
|
$ref: "#/definitions/StatusMessage"
|
||||||
/status:
|
/status:
|
||||||
get:
|
get:
|
||||||
description: Get the current status of the RAUC updater
|
description: Get the current status of the RAUC updater
|
||||||
|
@ -194,7 +169,7 @@ paths:
|
||||||
"500":
|
"500":
|
||||||
description: Server Error
|
description: Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Error"
|
$ref: "#/definitions/StatusMessage"
|
||||||
/update:
|
/update:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
@ -202,7 +177,7 @@ paths:
|
||||||
description: Start the update process
|
description: Start the update process
|
||||||
operationId: startUpdate
|
operationId: startUpdate
|
||||||
parameters:
|
parameters:
|
||||||
- description: RAUC firmware image file (*.raucb)
|
- description: Rauc firmware image file (*.raucb)
|
||||||
in: formData
|
in: formData
|
||||||
name: updateFile
|
name: updateFile
|
||||||
required: true
|
required: true
|
||||||
|
@ -214,12 +189,12 @@ paths:
|
||||||
description: Ok
|
description: Ok
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/StatusMessage"
|
$ref: "#/definitions/StatusMessage"
|
||||||
"409":
|
|
||||||
description: already running
|
|
||||||
"500":
|
"500":
|
||||||
description: Server Error
|
description: Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Error"
|
$ref: "#/definitions/StatusMessage"
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
schemes:
|
schemes:
|
||||||
- http
|
- http
|
||||||
- https
|
- https
|
|
@ -38,32 +38,7 @@ import {
|
||||||
} from "./base"
|
} from "./base"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Error contains error relevant information.
|
*
|
||||||
* @export
|
|
||||||
* @interface ModelError
|
|
||||||
*/
|
|
||||||
export interface ModelError {
|
|
||||||
/**
|
|
||||||
* The general error message according to HTTP specification.
|
|
||||||
* @type {string}
|
|
||||||
* @memberof ModelError
|
|
||||||
*/
|
|
||||||
error: string
|
|
||||||
/**
|
|
||||||
* Concrete error message.
|
|
||||||
* @type {string}
|
|
||||||
* @memberof ModelError
|
|
||||||
*/
|
|
||||||
msg: string
|
|
||||||
/**
|
|
||||||
* The http error code.
|
|
||||||
* @type {number}
|
|
||||||
* @memberof ModelError
|
|
||||||
*/
|
|
||||||
status_code: number
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* RaucStatus contains information about the current RAUC updater status.
|
|
||||||
* @export
|
* @export
|
||||||
* @interface RaucStatus
|
* @interface RaucStatus
|
||||||
*/
|
*/
|
||||||
|
@ -143,7 +118,7 @@ export interface Rootfs {
|
||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* StatusMessage contains the status of an operation.
|
*
|
||||||
* @export
|
* @export
|
||||||
* @interface StatusMessage
|
* @interface StatusMessage
|
||||||
*/
|
*/
|
||||||
|
@ -162,7 +137,7 @@ export interface StatusMessage {
|
||||||
success: boolean
|
success: boolean
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* SystemInfo contains information about the running system.
|
*
|
||||||
* @export
|
* @export
|
||||||
* @interface SystemInfo
|
* @interface SystemInfo
|
||||||
*/
|
*/
|
||||||
|
@ -315,7 +290,7 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Start the update process
|
* Start the update process
|
||||||
* @param {any} updateFile RAUC firmware image file (*.raucb)
|
* @param {any} updateFile Rauc firmware image file (*.raucb)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
|
@ -429,7 +404,7 @@ export const DefaultApiFp = function (configuration?: Configuration) {
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Start the update process
|
* Start the update process
|
||||||
* @param {any} updateFile RAUC firmware image file (*.raucb)
|
* @param {any} updateFile Rauc firmware image file (*.raucb)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
|
@ -496,7 +471,7 @@ export const DefaultApiFactory = function (
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Start the update process
|
* Start the update process
|
||||||
* @param {any} updateFile RAUC firmware image file (*.raucb)
|
* @param {any} updateFile Rauc firmware image file (*.raucb)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
|
@ -553,7 +528,7 @@ export class DefaultApi extends BaseAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the update process
|
* Start the update process
|
||||||
* @param {any} updateFile RAUC firmware image file (*.raucb)
|
* @param {any} updateFile Rauc firmware image file (*.raucb)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof DefaultApi
|
* @memberof DefaultApi
|
||||||
|
|
3
ui/ui.go
3
ui/ui.go
|
@ -7,7 +7,6 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/server/middleware"
|
|
||||||
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
||||||
"code.thetadev.de/TSGRain/ginzip"
|
"code.thetadev.de/TSGRain/ginzip"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -37,7 +36,7 @@ func distFS() fs.FS {
|
||||||
func Register(r *gin.Engine) {
|
func Register(r *gin.Engine) {
|
||||||
indexHandler := getIndexHandler()
|
indexHandler := getIndexHandler()
|
||||||
|
|
||||||
ui := r.Group("/", ginzip.New(ginzip.DefaultOptions()), middleware.Cache)
|
ui := r.Group("/", ginzip.New(ginzip.DefaultOptions()))
|
||||||
|
|
||||||
ui.GET("/", indexHandler)
|
ui.GET("/", indexHandler)
|
||||||
ui.GET("/index.html", indexHandler)
|
ui.GET("/index.html", indexHandler)
|
||||||
|
|
Loading…
Reference in a new issue