summaryrefslogtreecommitdiffstats
path: root/repo/repo.go
blob: 2c052d6a1a02599a0d6c803915f82b8dcc906e7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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
}