package main import ( "bytes" "embed" "flag" "fmt" "html/template" "io/ioutil" "log" "net/http" "strings" "gopkg.in/yaml.v3" ) //go:embed templates var tpls embed.FS type repository struct { Name string `yaml:"name"` Repo string `yaml:"repo"` } type config struct { BaseUrl string `yaml:"baseUrl"` VCS string `yaml:"vcs"` Repositories []repository `yaml:"repositories"` } type moduleTmpl struct { Name string Repo string VCS string BaseUrl string } func main() { flag.Parse() cfg, err := loadConfig() if err != nil { log.Fatal(err) } http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Write([]byte("ok")) }) http.HandleFunc("/", goGet(cfg)) log.Printf("starting web server on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } func loadConfig() (*config, error) { configPath := "./vanity.yaml" configYaml, err := ioutil.ReadFile(configPath) if err != nil { return nil, fmt.Errorf("failed to read configuration file %s: %v", configPath, err) } var cfg config err = yaml.Unmarshal(configYaml, &cfg) if err != nil { return nil, fmt.Errorf("failed to unmarshall configuration: %v", err) } return &cfg, nil } func goGet(cfg *config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { status := http.StatusMethodNotAllowed http.Error(w, http.StatusText(status), status) return } if r.FormValue("go-get") == "1" { pathParts := strings.Split(r.URL.Path, "/") for _, m := range cfg.Repositories { if pathParts[1] == m.Name { goGetModule(w, r, m, cfg) return } } status := http.StatusNotFound http.Error(w, http.StatusText(status), status) return } browserURL(w, r, cfg) } } func goGetModule(w http.ResponseWriter, r *http.Request, m repository, cfg *config) { tmpl, err := template.ParseFS(tpls, "templates/module.html.tpl") if err != nil { log.Fatal(err) } mod := moduleTmpl{ VCS: cfg.VCS, BaseUrl: cfg.BaseUrl, Name: m.Name, Repo: m.Repo, } var buf bytes.Buffer if err := tmpl.Execute(&buf, mod); err != nil { log.Printf("error: %+v", err) status := http.StatusInternalServerError http.Error(w, http.StatusText(status), status) } else { w.Header().Set("Cache-Control", "no-store") w.Write(buf.Bytes()) } } func browserURL(w http.ResponseWriter, r *http.Request, cfg *config) { tmpl, err := template.ParseFS(tpls, "templates/index.html.tpl") if err != nil { log.Fatal(err) } var buf bytes.Buffer if err := tmpl.Execute(&buf, cfg); err != nil { log.Printf("error: %+v", err) status := http.StatusInternalServerError http.Error(w, http.StatusText(status), status) } else { w.Header().Set("Cache-Control", "no-store") w.Write(buf.Bytes()) } }