package main import ( // External "git.gibonuddevalla.se/go/html_template" // Standard "embed" "encoding/json" "errors" "fmt" "io" "net/http" "os" ) var ( htmlEngine HTMLTemplate.Engine //go:embed static staticFS embed.FS //go:embed views viewFS embed.FS ) func registerWebserverHandlers() { // {{{ var err error htmlEngine, err = HTMLTemplate.NewEngine(viewFS, staticFS, flagDev) if err != nil { logger.Error("webserver", "error", err) os.Exit(1) } http.HandleFunc("/", rootHandler) http.HandleFunc("/devices", actionDevices) http.HandleFunc("GET /device/{dev}/dns_records", actionDNSRecords) http.HandleFunc("POST /device/{dev}/record", actionRecordSave) http.HandleFunc("DELETE /device/{dev}/record/{id}", actionRecordDelete) } // }}} func startWebserver() { // {{{ listen := fmt.Sprintf("%s:%d", config.Network.Address, config.Network.Port) logger.Info("webserver", "listen", listen) http.ListenAndServe(listen, nil) } // }}} func httpError(w http.ResponseWriter, err error) { // {{{ resp := struct { OK bool Error string }{ false, err.Error(), } j, _ := json.Marshal(resp) w.Write(j) } // }}} func rootHandler(w http.ResponseWriter, r *http.Request) { // {{{ if r.URL.Path == "/" { page := HTMLTemplate.SimplePage{} page.Layout = "main" page.Page = "index" var err error data := make(map[string]any) data["VERSION"] = VERSION page.Data = data err = htmlEngine.Render(page, w, r) if err != nil { w.Write([]byte(err.Error())) return } return } htmlEngine.StaticResource(w, r) } // }}} func actionDevices(w http.ResponseWriter, r *http.Request) { // {{{ var devs []Device for _, dev := range config.Devices { dev.Password = "" devs = append(devs, dev) } j, _ := json.Marshal(struct { OK bool Devices []Device }{ true, devs, }) w.Write(j) } // }}} func actionDNSRecords(w http.ResponseWriter, r *http.Request) { // {{{ devname := r.PathValue("dev") device, err := routerosDevice(devname) if err != nil { httpError(w, err) return } var records []DNSRecord records, err = device.StaticDNSEntries() if err != nil { httpError(w, err) return } j, _ := json.Marshal(struct { OK bool Records []DNSRecord }{ true, records, }) w.Write(j) } // }}} func actionRecordSave(w http.ResponseWriter, r *http.Request) { // {{{ devName := r.PathValue("dev") device, err := routerosDevice(devName) if err != nil { httpError(w, err) return } body, _ := io.ReadAll(r.Body) var record DNSRecord err = json.Unmarshal(body, &record) if err != nil { httpError(w, err) return } entry, err := device.UpdateDNSEntry(record.toDNSEntry()) if err != nil { httpError(w, err) logger.Error("webserver", "op", "record_save", "error", err) return } record = NewDNSRecord(entry) j, _ := json.Marshal(struct { OK bool Record DNSRecord }{true, record}) w.Write(j) } // }}} func actionRecordDelete(w http.ResponseWriter, r *http.Request) { // {{{ devName := r.PathValue("dev") device, err := routerosDevice(devName) if err != nil { httpError(w, err) return } id := r.PathValue("id") if id == "" { httpError(w, errors.New("No ID provided")) return } err = device.DeleteDNSEntry(id) if err != nil { httpError(w, err) logger.Error("webserver", "op", "record_delete", "error", err) return } j, _ := json.Marshal(struct { OK bool }{true}) w.Write(j) } // }}}