package repo import ( "bytes" _ "embed" "fmt" "html/template" "net/http" "strings" ) //go:embed meta.html var tmplStr string type Repo struct { VCS string `toml:"vcs"` Repository string `toml:"repo"` Home string `toml:"source,omitempty"` Directory string `toml:"directory"` File string `toml:"file"` } type RepoHandler struct { Pages map[string][]byte } func New(repo map[string]Repo) (*RepoHandler, error) { m, err := NewMeta() if err != nil { return nil, err } h := &RepoHandler{Pages: map[string][]byte{}} for k, v := range repo { if v.Home == "" { v.Home = "_" } b, err := m.Exec(k, v) if err != nil { return nil, err } h.Pages[k] = b } return h, nil } func (h *RepoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { key := fmt.Sprintf("%s%s", r.Host, r.URL.Path) key = strings.TrimSuffix(key, "/") page, ok := h.Pages[key] if !ok { http.NotFound(w, r) return } if r.FormValue("go-get") == "1" { w.Header().Set("Cache-Control", "public, max-age=86400, immutable") w.Header().Set("Vary", "Host") w.Header().Set("Content-Type", "text/html") w.Write(page) } else { url := fmt.Sprintf("https://pkg.go.dev/%s", key) http.Redirect(w, r, url, http.StatusFound) } } type Meta struct { tmpl *template.Template } func NewMeta() (*Meta, error) { tmpl, err := template.New("meta").Parse(tmplStr) if err != nil { return nil, err } return &Meta{tmpl: tmpl}, nil } func (m *Meta) Exec(pkg string, repo Repo) ([]byte, error) { var buf bytes.Buffer data := struct { Package string Repo }{ Package: pkg, Repo: repo, } if err := m.tmpl.Execute(&buf, data); err != nil { return nil, fmt.Errorf("exec template for %v: %w", pkg, err) } return buf.Bytes(), nil }