aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/site/fs.go
blob: c9bbe2189c6f3b79f31482772758724e4597de5e (plain)
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
84
85
86
87
88
89
90
91
92
93
94
95
package site

import (
	"log/slog"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/LMBishop/scrapbook/pkg/config"
	"github.com/LMBishop/scrapbook/pkg/html"
)

type SiteFileServer struct {
	root       http.FileSystem
	siteConfig *config.SiteConfig
}

func NewSiteFileServer(root http.FileSystem, siteConfig *config.SiteConfig) *SiteFileServer {
	return &SiteFileServer{root: root, siteConfig: siteConfig}
}

func (fs *SiteFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := filepath.Clean(r.URL.Path)

	file, err := fs.root.Open(path)
	if err != nil {
		if strings.HasSuffix(path, ".html") {
			html.NotFoundUrlPage(path, fs.siteConfig.Host).Render(w)
			return
		}

		htmlPath := path + ".html"
		file, err = fs.root.Open(htmlPath)
		if err != nil {
			html.NotFoundUrlPage(path, fs.siteConfig.Host).Render(w)
			return
		}
	}
	defer file.Close()

	info, err := file.Stat()
	if err != nil {
		html.NotFoundUrlPage(path, fs.siteConfig.Host).Render(w)
		return
	}

	if info.IsDir() {
		indexPath := filepath.Join(path, "index.html")
		if _, err := fs.root.Open(indexPath); os.IsNotExist(err) {
			if fs.siteConfig.Flags&config.FlagIndex == 0 {
				html.NotFoundUrlPage(path, fs.siteConfig.Host).Render(w)
				return
			}
			files, err := fs.listFiles(path)
			if path != "/" {
				files = append([]html.File{{Name: "..", IsDir: true, Size: 0}}, files...)
			}
			if err != nil {
				html.IndexPage(path, true, files).Render(w)
				slog.Error("could not list directory for index page generation", "host", fs.siteConfig.Host, "path", path, "error", err)
			} else {
				html.IndexPage(path, false, files).Render(w)
			}
			return
		}
		http.ServeFile(w, r, indexPath)
	} else {
		http.ServeFile(w, r, path)
	}
}

func (fs *SiteFileServer) listFiles(dir string) ([]html.File, error) {
	file, err := fs.root.Open(dir)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	entries, err := file.Readdir(-1)
	if err != nil {
		return nil, err
	}

	var files []html.File
	for _, entry := range entries {
		if !entry.IsDir() {
			files = append(files, html.File{Name: entry.Name(), IsDir: false, Size: entry.Size()})
		} else {
			files = append(files, html.File{Name: entry.Name(), IsDir: true, Size: 0})
		}
	}

	return files, nil
}