http.go 6.72 KB
package main

import (
	"html/template"
	"net/http"
	"sync"

	"github.com/gin-contrib/multitemplate"
	"github.com/gin-gonic/gin"
)

var mu sync.Mutex

var indexPage = template.Must(template.New("index.html").Parse(`
<html>
<head>
  <title>System Configuration</title>
  <style type="text/css">
    div { margin-left: 20px; }
  </style>
</head>
<body>
  <h1>{{.Device}} Configuration</h1>
  <div>
    <p>System Version: {{.falinux_version}}</p>
  </div>
  <hr>
  <h1>Updating System</h1>
  <div>
    <form action="/system" method="post" enctype="multipart/form-data">
      <input type="file" name="image" />
      <input type="submit" value="Update" />
    </form>
  </div>
  <h1>Updating Application</h1>
  <div>
    <form action="/application" method="post" enctype="multipart/form-data">
      <input type="file" name="image" />
      <input type="submit" value="Update" />
    </form>
  </div>
  <h1>Restore System Image</h1>
  <div>
    <form action="/restore">
      <input type="submit" value="Restore" />
    </form>
  </div>
</body>
</html>
`))

var networkPage = template.Must(template.New("network.html").Parse(`
<html>
<head>
  <title>Network Configuration</title>
  <style type="text/css">
    div { margin-left: 20px; }
  </style>
</head>
<body>
  <form action="/network" method="post">
    <h1>Setting Network</h1>
    <div>
      <p>
        <label for="ethaddr">Ethernet Address</label><br />
        <input type="text" id="ethaddr" name="ethaddr" value="{{.ethaddr}}" required />
      </p>
      <p>
        <label for="ipaddr">IP Address</label><br />
        <input type="text" id="ipaddr" name="ipaddr" value="{{.ipaddr}}" required />
      </p>
      <p>
        <label for="netmask">Netmask</label><br />
        <input type="text" id="netmask" name="netmask" value="{{.netmask}}" required />
      </p>
      <p>
        <label for="gateway">Gateway</label><br />
        <input type="text" id="gateway" name="gateway" value="{{.gateway}}" required />
      </p>
    </div>
    <label for="submit"><h1>Click to Apply</h1></label>
    <div>
      <p><input id="submit" type="submit" value="Set" /></p>
    </div>
  </form>
</body>
</html>
`))

var networkPageDual = template.Must(template.New("network.html").Parse(`
<html>
<head>
  <title>Network Configuration</title>
  <style type="text/css">
    div { margin-left: 20px; }
  </style>
</head>
<body>
  <form action="/network" method="post">
    <h1>Setting Network</h1>
    <div>
      <p>
        <label for="ethaddr">Ethernet Address</label><br />
        <input type="text" id="ethaddr" name="ethaddr" value="{{.ethaddr}}" required />
      </p>
      <p>
        <label for="ipaddr">IP Address</label><br />
        <input type="text" id="ipaddr" name="ipaddr" value="{{.ipaddr}}" required />
      </p>
      <p>
        <label for="netmask">Netmask</label><br />
        <input type="text" id="netmask" name="netmask" value="{{.netmask}}" required />
      </p>
      <p>
        <label for="gateway">Gateway</label><br />
        <input type="text" id="gateway" name="gateway" value="{{.gateway}}" required />
      </p>
    </div>
    <h1>Setting Network 2</h1>
    <div>
      <p>
        <label for="ethaddr2">Ethernet Address</label><br />
        <input type="text" id="ethaddr2" name="ethaddr2" value="{{.ethaddr2}}" required />
      </p>
      <p>
        <label for="ipaddr2">IP Address</label><br />
        <input type="text" id="ipaddr2" name="ipaddr2" value="{{.ipaddr2}}" required />
      </p>
      <p>
        <label for="netmask2">Netmask</label><br />
        <input type="text" id="netmask2" name="netmask2" value="{{.netmask2}}" required />
      </p>
      <p>
        <label for="gateway2">Gateway</label><br />
        <input type="text" id="gateway2" name="gateway2" value="{{.gateway2}}" required />
      </p>
    </div>
    <label for="submit"><h1>Click to Apply</h1></label>
    <div>
      <p><input id="submit" type="submit" value="Set" /></p>
    </div>
  </form>
</body>
</html>
`))

var rebootPage = template.Must(template.New("reboot.html").Parse(`
<html>
<head>
  <title>OK</title>
</head>
<body>
  <p>{{.Message}}</p>
  <form action="/reboot/">
    <input type="submit" value="Reboot" />
  </form>
</body>
</html>
`))

func runHttp() {
	gin.SetMode(gin.ReleaseMode)

	g := gin.Default()

	r := multitemplate.NewRenderer()
	r.Add("index.html", indexPage)
	r.Add("reboot.html", rebootPage)

	if hasDualNetwork {
		r.Add("network.html", networkPageDual)
	} else {
		r.Add("network.html", networkPage)
	}

	g.HTMLRender = r

	g.GET("/", renderIndex)
	g.GET("/network", renderNetwork)

	g.POST("/network", handleNetwork)
	g.POST("/system", handleSystem)
	g.POST("/application", handleApplication)

	g.GET("/reboot", handleReboot)
	g.GET("/restore", handleRestore)

	g.Run(":8988")
}

func handleNetwork(c *gin.Context) {
	mu.Lock()
	defer mu.Unlock()

	keyList := []string{"ethaddr", "ipaddr", "netmask", "gateway"}
	if hasDualNetwork {
		keyList = append(keyList, "ethaddr2", "ipaddr2", "netmask2", "gateway2")
	}

	env := map[string]string{}
	for _, key := range keyList {
		env[key] = c.PostForm(key)
	}

	if err := setNetwork(env); err != nil {
		c.String(http.StatusBadRequest, "network: setNetwork: %s", err.Error())
		return
	}

	c.HTML(http.StatusOK, "reboot.html", gin.H{"Message": "Network is configured."})
}

func handleSystem(c *gin.Context) {
	mu.Lock()
	defer mu.Unlock()

	if err := saveFormFile(c, "image", "/tmp/system.zip"); err != nil {
		c.String(http.StatusBadRequest, "system: saveFormFile: %s", err.Error())
		return
	}

	if err := updateSystem(); err != nil {
		c.String(http.StatusBadRequest, "system: updateSystem: %s", err.Error())
		return
	}

	c.HTML(http.StatusOK, "reboot.html", gin.H{"Message": "System is updated."})
}

func handleApplication(c *gin.Context) {
	mu.Lock()
	defer mu.Unlock()

	if err := saveFormFile(c, "image", "/tmp/application.zip"); err != nil {
		c.String(http.StatusBadRequest, "application: saveFormFile: %s", err.Error())
		return
	}

	if err := updateApp(); err != nil {
		c.String(http.StatusBadRequest, "application: updateApplication: %s", err.Error())
		return
	}

	c.HTML(http.StatusOK, "reboot.html", gin.H{"Message": "Application is updated."})
}

func handleReboot(c *gin.Context) {
	reboot()

	c.String(http.StatusOK, "OK")
}

func handleRestore(c *gin.Context) {
	mu.Lock()
	defer mu.Unlock()

	restore()

	c.HTML(http.StatusOK, "reboot.html", gin.H{"Message": "Restoration is done."})
}

func renderIndex(c *gin.Context) {
	env, _ := getEnv(1)
	env["Device"] = deviceName

	c.HTML(http.StatusOK, "index.html", env)
}

func renderNetwork(c *gin.Context) {
	env, _ := getEnv(0)

	c.HTML(http.StatusOK, "network.html", env)
}

func saveFormFile(c *gin.Context, name string, dst string) error {
	file, err := c.FormFile(name)
	if err != nil {
		return err
	}

	return c.SaveUploadedFile(file, dst)
}