sub/main.go

183 lines
4.1 KiB
Go

package main
import (
"embed"
"fmt"
"html/template"
"io"
"log"
"net/http"
"net/netip"
"strconv"
"strings"
"git.freifunk-franken.de/jkimmel/sub/ipalloc"
)
type server struct {
mux *http.ServeMux
ipdb *ipalloc.DB
tmpl *template.Template
}
func (s *server) setup() {
s.mux = http.NewServeMux()
s.mux.HandleFunc("/js/", s.static())
s.mux.HandleFunc("/css/", s.static())
s.mux.HandleFunc("/", s.template)
s.mux.HandleFunc("/api/prefix/", s.apiPrefix)
s.mux.HandleFunc("/api/alloc/", s.apiAlloc)
s.mux.HandleFunc("/api/dealloc/", s.apiDealloc)
s.mux.HandleFunc("/api/used/", s.apiUsed)
s.mux.HandleFunc("/api/print/", s.apiPrint)
s.mux.HandleFunc("/api/treemap.dot", s.apiDot)
//s.mux.HandleFunc("/api/provision/", s.apiProvision)
s.ipdb = ipalloc.NewDB("10.83.46.0/23", 32, 29, 28, 27, 26)
//s.ipdb = ipalloc.NewDB("fd43:5602:29bd:fffe::/64", 128, 127, 126)
//s.ipdb = ipalloc.NewDB("fd43:5602:29bd:ffff:ffff:ffff:0:0/96", 128, 127, 126)
//s.ipdb = ipalloc.NewDB("fd43:5602:29bd:ffff:ffff:ffff:ffff:0/112", 128)
s.tmpl = template.Must(template.ParseFS(webcontent, "index.html"))
}
func (s *server) apiPrefix(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
switch r.Method {
case "GET":
prefixString := strings.TrimPrefix(r.URL.Path, "/api/prefix/")
prefix, err := netip.ParsePrefix(prefixString)
fmt.Fprintln(w, prefix, err)
case "POST":
}
}
type PageContent struct {
Api *ipalloc.DB
Update UpdateMessage
Treemap ipalloc.Treemap
}
type UpdateMessage struct {
Type string
Content any
}
func (s *server) template(w http.ResponseWriter, r *http.Request) {
err := s.tmpl.Execute(w,
PageContent{
Api: s.ipdb,
Update: UpdateMessage{
Type: "hint",
Content: template.HTML(" "),
},
Treemap: s.ipdb.Treemap(),
},
)
if err != nil {
log.Println(err)
}
}
func (s *server) apiDot(w http.ResponseWriter, r *http.Request) {
_, err := io.WriteString(w, s.ipdb.Dot())
if err != nil {
log.Println(err)
}
}
func (s *server) apiUsed(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
for _, used := range s.ipdb.Used() {
fmt.Fprintln(w, used)
}
}
func (s *server) apiPrint(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
for _, p := range s.ipdb.All() {
fmt.Fprintln(w, p.Prefix(), p.Leaf())
}
}
func (s *server) apiAlloc(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
var updmsg UpdateMessage
bitsString := strings.TrimPrefix(r.URL.Path, "/api/alloc/")
bits, err := strconv.Atoi(bitsString)
if err != nil {
updmsg.Type = "warn"
updmsg.Content = err
if err := s.tmpl.ExecuteTemplate(w, "update", updmsg); err != nil {
log.Println(err)
}
return
}
alloc, err := s.ipdb.Alloc(bits)
if err != nil {
updmsg.Type = "warn"
updmsg.Content = err
} else {
updmsg.Type = "hint"
updmsg.Content = fmt.Sprintf("Added %s", alloc.Prefix())
}
s.tmpl.ExecuteTemplate(w, "treemap", s.ipdb.Treemap())
if err := s.tmpl.ExecuteTemplate(w, "update", updmsg); err != nil {
log.Println(err)
}
if err := s.tmpl.ExecuteTemplate(w, "used", s.ipdb); err != nil {
log.Println(err)
}
}
func (s *server) apiDealloc(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
var updmsg UpdateMessage
prefixString := strings.TrimPrefix(r.URL.Path, "/api/dealloc/")
prefix, err := netip.ParsePrefix(prefixString)
if err != nil {
updmsg.Type = "warn"
updmsg.Content = err
s.tmpl.ExecuteTemplate(w, "update", updmsg)
return
}
err = s.ipdb.Dealloc(prefix)
if err != nil {
updmsg.Type = "warn"
updmsg.Content = err
} else {
updmsg.Type = "hint"
updmsg.Content = fmt.Sprintf("Removed %s", prefix)
}
s.tmpl.ExecuteTemplate(w, "treemap", s.ipdb.Treemap())
s.tmpl.ExecuteTemplate(w, "update", updmsg)
s.tmpl.ExecuteTemplate(w, "used", s.ipdb)
}
//go:embed js css *.html
var webcontent embed.FS
func (s *server) static() http.HandlerFunc {
fs := http.FS(webcontent)
fileserver := http.FileServer(fs)
return fileserver.ServeHTTP
}
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL)
s.mux.ServeHTTP(w, r)
}
func main() {
var s server
s.setup()
http.ListenAndServe("[::1]:8080", &s)
}