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
|
package syw
import (
"context"
"text/template"
"tildegit.org/tjp/sliderule"
"tildegit.org/tjp/sliderule/gemini"
)
// GeminiRouter builds a router that will handle requests into a directory of git repositories.
//
// The routes it defines are:
//
// / gemtext listing of the repositories in the directory
// /:repository/ gemtext overview of the repository
// /:repository/branches gemtext list of branches/heads
// /:repository/tags gemtext listing of tags
// /:repository/refs/:ref/ gemtext overview of a ref
// /:repository/refs/:ref/tree/*path gemtext listing of directories, raw files
// /:repository/diffstat/:fromref/:toref text/plain diffstat between two refs
// /:repository/diff/:fromref/:toref text/x-diff between two refs
//
// The overrides argument can provide templates to define the behavior of nearly all of the above
// routes. All of them have default implementations so the argument can even be nil, but otherwise
// the template names used are:
//
// repo_root.gmi gemtext at /
// repo_home.gmi gemtext at /:repository/
// branch_list.gmi gemtext at /:repository/branches
// tag_list.gmi gemtext at /:repository/tags
// ref.gmi gemtext at /:repository/refs/:ref/
// tree.gmi gemtext for directories requested under /:repository/refs/:ref/tree/*path
// (file paths return the raw files without any template involved)
// diffstat.gmi.txt the plaintext diffstat at /:repository/diffstat/:fromref/:toref
// diff.gmi.txt the text/x-diff at /:repository/diff/:fromref/:toref
//
// Most of the templates above are rendered with an object with 3 fields:
//
// Ctx: the context.Context from the request
// Repo: a *syw.Repository object corresponding to <repodir>/:repository
// Params: a map[string]string of the route parameters
//
// The only exception is repo_root.gmi, which is rendered with an object containing a single name
// "Repos", which is a slice of the repository names.
func GeminiRouter(repodir string, overrides *template.Template) *sliderule.Router {
tmpl, err := addTemplates(geminiTemplate, overrides)
if err != nil {
panic(err)
}
repoRouter := &sliderule.Router{}
repoRouter.Use(assignRepo(repodir))
repoRouter.Route("/", repoRouteHandler(geminiProto, tmpl, "repo_home.gmi"))
repoRouter.Route("/branches", repoRouteHandler(geminiProto, tmpl, "branch_list.gmi"))
repoRouter.Route("/tags", repoRouteHandler(geminiProto, tmpl, "tag_list.gmi"))
repoRouter.Route("/refs/:ref/", repoRouteHandler(geminiProto, tmpl, "ref.gmi"))
repoRouter.Route("/refs/:ref/tree/*path", treePathHandler(geminiProto, tmpl, "tree.gmi"))
repoRouter.Route("/diffstat/:fromref/:toref", repoRouteHandler(geminiProto, tmpl, "diffstat.gmi.txt"))
repoRouter.Route("/diff/:fromref/:toref", repoRouteHandler(geminiProto, tmpl, "diff.gmi.txt"))
router := &sliderule.Router{}
router.Route("/", rootDirHandler(geminiProto, repodir, tmpl, "repo_root.gmi"))
router.Mount("/:"+reponamekey, repoRouter)
return router
}
type geminiProtocol struct{ sliderule.ServerProtocol }
func (geminiProtocol) TemplateBaseData(_ context.Context, _ *sliderule.Request) map[string]any {
return map[string]any{}
}
func (geminiProtocol) TemplateRepoData(ctx context.Context, request *sliderule.Request) map[string]any {
return map[string]any{
"Ctx": ctx,
"Repo": ctx.Value(repokey),
"Params": sliderule.RouteParams(ctx),
}
}
var geminiProto = geminiProtocol{gemini.ServerProtocol}
|