all repos

mugit @ a41a1ac

🐮 git server that your cow will love

mugit/internal/handlers/handlers.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
ui: add line numbers to diffs, 2 months ago
1
package handlers
2
3
import (
4
	"html/template"
5
	"net/http"
6
	"net/url"
7
	"path/filepath"
8
	"strings"
9
	"time"
10
11
	"olexsmir.xyz/mugit/internal/cache"
12
	"olexsmir.xyz/mugit/internal/config"
13
	"olexsmir.xyz/mugit/internal/git"
14
	"olexsmir.xyz/mugit/internal/humanize"
15
	"olexsmir.xyz/mugit/web"
16
)
17
18
type handlers struct {
19
	c *config.Config
20
	t *template.Template
21
22
	repoListCache cache.Cacher[[]repoList]
23
	readmeCache   cache.Cacher[template.HTML]
24
	diffCache     cache.Cacher[*git.NiceDiff]
25
}
26
27
func InitRoutes(cfg *config.Config) http.Handler {
28
	tmpls := template.Must(template.New("").
29
		Funcs(templateFuncs).
30
		ParseFS(web.TemplatesFS, "*"))
31
	h := handlers{
32
		cfg, tmpls,
33
		cache.NewInMemory[[]repoList](cfg.Cache.HomePage),
34
		cache.NewInMemory[template.HTML](cfg.Cache.Readme),
35
		cache.NewInMemory[*git.NiceDiff](cfg.Cache.Diff),
36
	}
37
38
	mux := http.NewServeMux()
39
	mux.HandleFunc("GET /", h.indexHandler)
40
	mux.HandleFunc("GET /index.xml", h.indexFeedHandler)
41
	mux.HandleFunc("GET /static/{file}", h.serveStaticHandler)
42
	mux.HandleFunc("GET /{name}/{$}", h.repoIndexHandler)
43
	mux.HandleFunc("GET /{name}/info/refs", h.infoRefsHandler)
44
	mux.HandleFunc("POST /{name}/git-upload-pack", h.uploadPackHandler)
45
	mux.HandleFunc("POST /{name}/git-receive-pack", h.receivePackHandler)
46
	mux.HandleFunc("GET /{name}/feed/{$}", h.repoFeedHandler)
47
	mux.HandleFunc("GET /{name}/tree/{ref}/{rest...}", h.repoTreeHandler)
48
	mux.HandleFunc("GET /{name}/blob/{ref}/{rest...}", h.fileContentsHandler)
49
	mux.HandleFunc("GET /{name}/raw/{ref}/{rest...}", h.rawFileContentsHandler)
50
	mux.HandleFunc("GET /{name}/log/{ref}", h.logHandler)
51
	mux.HandleFunc("GET /{name}/commit/{ref}", h.commitHandler)
52
	mux.HandleFunc("GET /{name}/refs/{$}", h.refsHandler)
53
	mux.HandleFunc("GET /{name}/archive/{ref}", h.archiveHandler)
54
55
	handler := h.recoverMiddleware(mux)
56
	return h.loggingMiddleware(handler)
57
}
58
59
func (h *handlers) serveStaticHandler(w http.ResponseWriter, r *http.Request) {
60
	f := filepath.Clean(r.PathValue("file"))
61
	http.ServeFileFS(w, r, web.StaticFS, f)
62
}
63
64
// parseRef parses url encoded ref name.
65
// If it fails it falls back to raw provided value.
66
func (h handlers) parseRef(name string) string {
67
	ref, err := url.PathUnescape(name)
68
	if err != nil {
69
		return name
70
	}
71
	return ref
72
}
73
74
var templateFuncs = template.FuncMap{
75
	"inc":             func(n int) int { return n + 1 },
76
	"inc64":           func(n int64) int64 { return n + 1 },
77
	"humanizeRelTime": func(t time.Time) string { return humanize.Time(t) },
78
	"humanizeTime":    func(t time.Time) string { return t.Format("2006-01-02 15:04:05 MST") },
79
	"urlencode":       func(s string) string { return url.PathEscape(s) },
80
	"commitSummary": func(s string) string {
81
		before, after, found := strings.Cut(s, "\n")
82
		first := strings.TrimSuffix(before, "\r")
83
		if !found {
84
			return first
85
		}
86
87
		if strings.Contains(after, "\n") {
88
			return first + "..."
89
		}
90
91
		return first
92
	},
93
}