datagraph/webserver.go
2025-07-03 13:25:08 +02:00

175 lines
3.2 KiB
Go

package main
import (
// External
"git.ahall.se/go/html_template"
// Standard
"encoding/json"
"fmt"
"io"
"io/fs"
"net/http"
"strconv"
)
var (
engine HTMLTemplate.Engine
)
func initWebserver() (err error) {
address := fmt.Sprintf("%s:%d", config.Network.Address, config.Network.Port)
logger.Info("webserver", "listen", address)
subViewFS, _ := fs.Sub(viewFS, "views")
subStaticFS, _ := fs.Sub(staticFS, "static")
engine, err = HTMLTemplate.NewEngine(subViewFS, subStaticFS, flagDev)
if err != nil {
return
}
http.HandleFunc("/", pageIndex)
http.HandleFunc("/app", pageApp)
http.HandleFunc("/nodes/tree/{startNode}", actionNodesTree)
http.HandleFunc("/nodes/{nodeID}", actionNode)
http.HandleFunc("/nodes/update/{nodeID}", actionNodeUpdate)
http.HandleFunc("/types/{typeID}", actionType)
http.HandleFunc("/types/", actionTypesAll)
err = http.ListenAndServe(address, nil)
return
}
func httpError(w http.ResponseWriter, err error) { // {{{
out := struct {
OK bool
Error string
}{
false,
err.Error(),
}
j, _ := json.Marshal(out)
w.Write(j)
} // }}}
func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
if r.URL.Path == "/" {
http.Redirect(w, r, "/app", http.StatusSeeOther)
} else {
engine.StaticResource(w, r)
}
} // }}}
func pageApp(w http.ResponseWriter, r *http.Request) { // {{{
page := NewPage("app")
err := engine.Render(page, w, r)
if err != nil {
w.Write([]byte(err.Error()))
}
} // }}}
func actionNodesTree(w http.ResponseWriter, r *http.Request) { // {{{
var err error
startNode := 0
startNodeStr := r.PathValue("startNode")
startNode, _ = strconv.Atoi(startNodeStr)
var maxDepth int
if maxDepth, err = strconv.Atoi(r.URL.Query().Get("depth")); err != nil {
maxDepth = 3
}
topNode, err := GetNodeTree(startNode, maxDepth)
if err != nil {
httpError(w, err)
return
}
out := struct {
OK bool
Nodes *Node
}{
true,
topNode,
}
j, _ := json.Marshal(out)
w.Write(j)
} // }}}
func actionNode(w http.ResponseWriter, r *http.Request) { // {{{
nodeID := 0
nodeIDStr := r.PathValue("nodeID")
nodeID, _ = strconv.Atoi(nodeIDStr)
node, err := GetNode(nodeID)
if err != nil {
httpError(w, err)
return
}
out := struct {
OK bool
Node Node
}{
true,
node,
}
j, _ := json.Marshal(out)
w.Write(j)
} // }}}
func actionNodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
nodeID := 0
nodeIDStr := r.PathValue("nodeID")
nodeID, _ = strconv.Atoi(nodeIDStr)
data, _ := io.ReadAll(r.Body)
err := UpdateNode(nodeID, data)
if err != nil {
httpError(w, err)
return
}
out := struct {
OK bool
}{
true,
}
j, _ := json.Marshal(out)
w.Write(j)
} // }}}
func actionType(w http.ResponseWriter, r *http.Request) { // {{{
typeID := 0
typeIDStr := r.PathValue("typeID")
typeID, _ = strconv.Atoi(typeIDStr)
typ, err := GetType(typeID)
if err != nil {
httpError(w, err)
return
}
j, _ := json.Marshal(typ)
w.Write(j)
} // }}}
func actionTypesAll(w http.ResponseWriter, r *http.Request) { // {{{
types, err := GetTypes()
if err != nil {
httpError(w, err)
return
}
out := struct {
OK bool
Types []NodeType
}{
true,
types,
}
j, _ := json.Marshal(out)
w.Write(j)
} // }}}
// vim: foldmethod=marker