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 /: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}