diff options
Diffstat (limited to 'gemini.go')
| -rw-r--r-- | gemini.go | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/gemini.go b/gemini.go new file mode 100644 index 0000000..fd5dec5 --- /dev/null +++ b/gemini.go @@ -0,0 +1,151 @@ +package main + +import ( + "context" + "errors" + "fmt" + + sr "tildegit.org/tjp/sliderule" + "tildegit.org/tjp/sliderule/contrib/cgi" + "tildegit.org/tjp/sliderule/contrib/fs" + "tildegit.org/tjp/sliderule/gemini" + "tildegit.org/tjp/sliderule/gemini/gemtext/atomconv" + "tildegit.org/tjp/sliderule/logging" + "tildegit.org/tjp/syw" +) + +func buildGeminiServers(servers []Server, config *Configuration) ([]sr.Server, error) { + _, info, _, errlog := Loggers(config) + _ = info.Log("msg", "building gemini servers", "count", len(servers)) + + groups := map[string][]*Server{} + for i := range servers { + addr := fmt.Sprintf("%s:%d", servers[i].IP.String(), servers[i].Port) + grp, ok := groups[addr] + if !ok { + groups[addr] = []*Server{&servers[i]} + } else { + groups[addr] = append(grp, &servers[i]) + } + } + + result := []sr.Server{} + for addr, configs := range groups { + _ = info.Log("msg", "building gemini server", "addr", addr) + var handler sr.Handler + if len(configs) == 1 { + handler = routes(*configs[0]) + } else { + mapping := map[string]sr.Handler{} + for _, config := range configs { + router := routes(*config) + for _, hostname := range config.Hostnames { + mapping[hostname] = router + } + } + + var catchall sr.Handler + if len(configs[0].Hostnames) > 0 { + catchall = mapping[configs[0].Hostnames[0]] + } + + handler = sr.VirtualHosts(mapping, catchall) + } + + var hostname string + for _, conf := range configs { + if len(conf.Hostnames) > 0 { + hostname = conf.Hostnames[0] + break + } + } + + if configs[0].TLS == nil { + return nil, errors.New("gemini server must have a servertls directive") + } + + gemsrv, err := gemini.NewServer( + context.Background(), + hostname, + "tcp", + addr, + logging.LogRequests(info)(handler), + errlog, + configs[0].TLS, + ) + if err != nil { + return nil, err + } + + result = append(result, gemsrv) + } + + return result, nil +} + +func addGeminiRoute(router *sr.Router, route RouteDirective) { + switch route.Type { + case "static": + addGeminiStaticRoute(router, route) + case "cgi": + buildAndAddRoute(router, route, func(route RouteDirective) sr.Handler { + handler := cgi.GeminiCGIDirectory(route.FsPath, route.URLPath) + if route.Modifiers.AutoAtom { + handler = atomconv.Auto(handler) + } + return GeminiAuthMiddleware(route.Auth)(handler) + }) + case "git": + buildAndAddRoute(router, route, func(route RouteDirective) sr.Handler { + var handler sr.Handler = syw.GeminiRouter(route.FsPath, nil) + if route.Modifiers.AutoAtom { + handler = atomconv.Auto(handler) + } + return GeminiAuthMiddleware(route.Auth)(handler) + }) + } +} + +func addGeminiStaticRoute(router *sr.Router, route RouteDirective) { + buildAndAddRoute(router, route, func(route RouteDirective) sr.Handler { + handlers := []sr.Handler{} + + if route.Modifiers.Exec { + handlers = append(handlers, cgi.GeminiCGIDirectory(route.FsPath, route.URLPath)) + } + + handlers = append(handlers, fs.GeminiFileHandler(route.FsPath, route.URLPath)) + + if route.Modifiers.DirDefault != "" { + handlers = append( + handlers, + fs.GeminiDirectoryDefault(route.FsPath, route.URLPath, route.Modifiers.DirDefault), + ) + } + + if route.Modifiers.DirList { + handlers = append(handlers, fs.GeminiDirectoryListing(route.FsPath, route.URLPath, nil)) + } + + var handler sr.Handler + if len(handlers) == 1 { + handler = handlers[0] + } + handler = sr.FallthroughHandler(handlers...) + + if route.Modifiers.AutoAtom { + handler = atomconv.Auto(handler) + } + + handler = GeminiAuthMiddleware(route.Auth)(handler) + + if route.Modifiers.Titan != nil { + titan := fs.TitanUpload(route.FsPath, route.URLPath, route.Modifiers.Titan.Strategy.Approve)(handler) + handler = sr.Filter(func(ctx context.Context, request *sr.Request) bool { + return request.Scheme == "titan" + }, handler)(titan) + } + + return handler + }) +} |
