gemini.go (view raw)
1package main
2
3import (
4 "bytes"
5 "crypto/tls"
6 "crypto/x509/pkix"
7 gmi "git.sr.ht/~adnano/go-gemini"
8 "io/ioutil"
9 "log"
10 "path"
11 "path/filepath"
12 "strings"
13 "text/template"
14 "time"
15)
16
17var gt *template.Template
18
19func generateGemfeedPage(user string) string {
20 feedItems := generateFeedFromUser(user)
21 data := struct {
22 Host string
23 Title string
24 FeedEntries []FeedEntry
25 }{c.Host, user + "'s Gemlog", feedItems}
26 var buff bytes.Buffer
27 gt.ExecuteTemplate(&buff, "gemfeed.gmi", data)
28 return buff.String()
29}
30
31func generateFolderPage(fullpath string) string {
32 files, _ := ioutil.ReadDir(fullpath)
33 var renderedFiles = []File{}
34 for _, file := range files {
35 // Very awkward
36 res := fileFromPath(path.Join(fullpath, file.Name()))
37 renderedFiles = append(renderedFiles, res)
38 }
39 var buff bytes.Buffer
40 data := struct {
41 Host string
42 Folder string
43 Files []File
44 }{c.Host, getLocalPath(fullpath), renderedFiles}
45 err := gt.ExecuteTemplate(&buff, "folder.gmi", data)
46 if err != nil {
47 log.Println(err)
48 return ""
49 }
50 return buff.String()
51}
52
53func gmiIndex(w *gmi.ResponseWriter, r *gmi.Request) {
54 log.Println("Index request")
55 t, err := template.ParseFiles("templates/index.gmi")
56 if err != nil {
57 log.Fatal(err)
58 }
59 files, err := getIndexFiles(false)
60 users, err := getActiveUserNames()
61 if err != nil {
62 log.Println(err)
63 w.WriteHeader(40, "Internal server error")
64 }
65 data := struct {
66 Host string
67 SiteTitle string
68 Files []*File
69 Users []string
70 }{
71 Host: c.Host,
72 SiteTitle: c.SiteTitle,
73 Files: files,
74 Users: users,
75 }
76 t.Execute(w, data)
77}
78
79func gmiPage(w *gmi.ResponseWriter, r *gmi.Request) {
80 userName := filepath.Clean(strings.Split(r.URL.Host, ".")[0]) // clean probably unnecessary
81 fileName := filepath.Clean(r.URL.Path)
82 if fileName == "/" {
83 fileName = "index.gmi"
84 } else if strings.HasPrefix(fileName, "/.hidden") {
85 w.WriteStatus(gmi.StatusNotFound)
86 return
87 }
88 log.Println("Request for gemini file", fileName, "for user", userName)
89
90 gmi.ServeFile(w, gmi.Dir(path.Join(c.FilesDirectory, userName)), fileName)
91}
92
93func runGeminiServer() {
94 log.Println("Starting gemini server")
95 var err error
96 gt, err = template.ParseGlob(path.Join(c.TemplatesDirectory, "*.gmi"))
97 if err != nil {
98 log.Fatal(err)
99 }
100 var server gmi.Server
101 server.ReadTimeout = 1 * time.Minute
102 server.WriteTimeout = 2 * time.Minute
103
104 hostname := strings.SplitN(c.Host, ":", 2)[0]
105 // is this necc?
106 err = server.Certificates.Load(c.GeminiCertStore)
107 if err != nil {
108 }
109 server.CreateCertificate = func(h string) (tls.Certificate, error) {
110 log.Println("Generating certificate for", h)
111 return gmi.CreateCertificate(gmi.CertificateOptions{
112 Subject: pkix.Name{
113 CommonName: hostname,
114 },
115 DNSNames: []string{h},
116 Duration: time.Hour * 760, // one month
117 })
118 }
119
120 var mux gmi.ServeMux
121 // replace with wildcard cert
122 mux.HandleFunc("/", gmiIndex)
123
124 var wildcardMux gmi.ServeMux
125 wildcardMux.HandleFunc("/", gmiPage)
126 server.Register(hostname, &mux)
127 server.Register("*."+hostname, &wildcardMux)
128
129 err = server.ListenAndServe()
130 if err != nil {
131 log.Fatal(err)
132 }
133}