package main import ( "embed" "flag" "fmt" "html/template" "io" "log" "net/http" "os" "time" "kumoly.io/tools/configui/configui" "kumoly.io/tools/configui/public" ) //go:embed templates var tmplFS embed.FS var tmpl *template.Template var ( flagPath string flagAction string flagAlias string flagConfigPath string flagBind string flagNoReconfig bool flagLogFile string flagAllow string flagVer bool ) var Version = "0.0.0" var Build = "alpha" var files = map[string]*configui.File{} func init() { // log.SetFlags(0) flag.StringVar(&flagConfigPath, "f", "", "path to config file") flag.StringVar(&flagPath, "p", "", "path to file, precedence over config") flag.StringVar(&flagAlias, "n", "", "alias of file") flag.StringVar(&flagAction, "c", "", "cmd to apply") flag.StringVar(&flagLogFile, "log", "", "log to file") flag.StringVar(&flagAllow, "allow", "", "IPs to allow, blank to allow all") flag.StringVar(&flagBind, "bind", "localhost:8000", "address to bind") flag.BoolVar(&flagNoReconfig, "static", false, "disable config api") flag.BoolVar(&flagVer, "v", false, "show version") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: configui [options]\n") flag.PrintDefaults() } } func main() { flag.Parse() if flagVer { fmt.Printf("%v - %v\n", Version, Build) } // setup logging if flagLogFile != "" { f, err := os.OpenFile(flagLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatalf("Error opening file: %v", err) } defer f.Close() mwriter := io.MultiWriter(f, os.Stderr) log.SetOutput(mwriter) } // setup values if flagPath != "" { if flagAlias == "" { flagAlias = flagPath } files[flagAlias] = &configui.File{ Path: flagPath, Alias: flagAlias, Action: flagAction, } } else if flagConfigPath == "" { log.Println("no config found") } else { conf, err := os.ReadFile(flagConfigPath) if err != nil { log.Fatalln(err) } ftmp, err := configui.ReadConfig(string(conf)) if err != nil { log.Fatalln(err) } files = configui.GetFileMap(ftmp) } // setup routes mux := http.NewServeMux() mux.HandleFunc("/api/conf", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { getConfigHandler(w, r) } else if r.Method == "POST" { LoadConfig(w, r) } else { w.WriteHeader(404) } }) mux.HandleFunc("/api/files", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { ListFiles(w, r) } else { w.WriteHeader(404) } }) mux.HandleFunc("/api/file", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { GetFile(w, r) } else if r.Method == "POST" { PostFile(w, r) } else { w.WriteHeader(404) } }) mux.HandleFunc("/api/apply", func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { Apply(w, r) } else { w.WriteHeader(404) } }) mux.HandleFunc("/api/export", func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { Download(w, r) } else { w.WriteHeader(404) } }) mux.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.FS(public.FS)))) tmpl = template.Must(template.New("").ParseFS(tmplFS, "templates/*.tmpl", "templates/**/*.tmpl")) setRoutes(mux) server := &http.Server{ Addr: flagBind, WriteTimeout: time.Second * 3, ReadTimeout: time.Second * 30, Handler: Middleware(mux), } // start server log.Println("Listening on", flagBind) log.Fatal(server.ListenAndServe()) }