diff options
| -rw-r--r-- | cmd/server/app.go | 19 | ||||
| -rw-r--r-- | cmd/server/handlers.go | 9 | ||||
| -rw-r--r-- | cmd/server/main.go | 11 | ||||
| -rw-r--r-- | example-site/reIndex.md | 2 | ||||
| -rw-r--r-- | page/checkup.go | 7 | ||||
| -rw-r--r-- | page/index.go | 7 | ||||
| -rw-r--r-- | page/page.go | 29 | ||||
| -rw-r--r-- | rediscache/main.go | 23 |
8 files changed, 88 insertions, 19 deletions
diff --git a/cmd/server/app.go b/cmd/server/app.go index c4992ae..4f62a09 100644 --- a/cmd/server/app.go +++ b/cmd/server/app.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "os" "github.com/gomodule/redigo/redis" @@ -72,3 +73,21 @@ func loadConf(fn string) (*App, error) { return app, nil } + +// ClearRedis is a little helper function that allows us to easily clear +// the redis cache at runtime. +func (a *App) ClearRedis() error { + if a.redisPool == nil { + return nil + } + + client := a.redisPool.Get() + defer client.Close() + + _, err := client.Do("DEL", a.RedisKey) + if err != nil { + log.Println("Encountered error clearing redis cache: ", err) + } + + return fmt.Errorf("clearing redis: %w", err) +} diff --git a/cmd/server/handlers.go b/cmd/server/handlers.go index 61bb623..205d462 100644 --- a/cmd/server/handlers.go +++ b/cmd/server/handlers.go @@ -14,13 +14,18 @@ func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) { rtr := mux.NewRouter() rtr.HandleFunc(a.ReIndexPath, a.RebuildIndexHandler) rtr.PathPrefix("/static/").Handler(a.StaticHandler()) - rtr.PathPrefix(fmt.Sprintf("/%s/{tag}", a.FeedPrefix)).HandlerFunc( - a.FeedHandler) if a.redisPool != nil { + rtr.PathPrefix(fmt.Sprintf("/%s/{tag}", a.FeedPrefix)).Handler( + rediscache.HandleWithParams(a.redisPool, a.RedisKey, + http.HandlerFunc(a.FeedHandler))) + rtr.PathPrefix("/").Handler(rediscache.Handle( a.redisPool, a.RedisKey, http.HandlerFunc(a.PageHandler))) } else { + rtr.PathPrefix(fmt.Sprintf("/%s/{tag}", a.FeedPrefix)).HandlerFunc( + a.FeedHandler) + rtr.PathPrefix("/").Handler(http.HandlerFunc(a.PageHandler)) } diff --git a/cmd/server/main.go b/cmd/server/main.go index 21f7031..912cba0 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -6,6 +6,8 @@ import ( "log" "net/http" "os" + "strings" + "text/template" "time" "github.com/gomodule/redigo/redis" @@ -73,6 +75,11 @@ func main() { //nolint:funlen MaxActive: 12000, //nolint:gomnd Dial: func() (redis.Conn, error) { c, err := redis.Dial("tcp", *redisAddr) + + if strings.HasPrefix(*redisAddr, "unix:") { + c, err = redis.Dial("unix", strings.TrimPrefix(*redisAddr, "unix:")) + } + if err != nil { log.Println("Redis dial error: ", err) } @@ -87,6 +94,10 @@ func main() { //nolint:funlen os.Stderr.Write(b) } + page.Funcs = template.FuncMap{ + "ClearRedis": app.ClearRedis, + } + srv := &http.Server{ Handler: app, Addr: *listen, diff --git a/example-site/reIndex.md b/example-site/reIndex.md index 4519dc5..12c608a 100644 --- a/example-site/reIndex.md +++ b/example-site/reIndex.md @@ -6,6 +6,8 @@ description: > # {{.Title}} +{{.ClearRedis}} + this is the reindex page {{if .Vars.IndexError}} diff --git a/page/checkup.go b/page/checkup.go index 9f721b7..6c3664f 100644 --- a/page/checkup.go +++ b/page/checkup.go @@ -2,8 +2,7 @@ package page import ( "fmt" - "os" - "path/filepath" + "io/fs" "reflect" "strings" ) @@ -15,8 +14,8 @@ func (p *Page) Checkup() (map[string]PageList, error) { out := make(map[string]PageList) - _ = filepath.Walk(filepath.Dir("."), - func(path string, info os.FileInfo, err error) error { + _ = fs.WalkDir(FileSystem, ".", + func(path string, info fs.DirEntry, err error) error { if err != nil { return err } diff --git a/page/index.go b/page/index.go index 425bf04..00cab4b 100644 --- a/page/index.go +++ b/page/index.go @@ -1,8 +1,7 @@ package page import ( - "os" - "path/filepath" + "io/fs" "strings" "sync" "time" @@ -41,8 +40,8 @@ func (p *Page) Index() (map[string]PageList, error) { out := make(map[string]PageList) - _ = filepath.Walk(filepath.Dir("."), - func(path string, info os.FileInfo, err error) error { + _ = fs.WalkDir(FileSystem, ".", + func(path string, info fs.DirEntry, err error) error { if err != nil { return err } diff --git a/page/page.go b/page/page.go index fa4ce6c..b2cc3e1 100644 --- a/page/page.go +++ b/page/page.go @@ -6,6 +6,8 @@ // markdown, first executed as part of the text/template then rendered by // blackfriday. // +// This package is designed to only be run with ***TRUSTED INPUT*** +// // Usage: // // import ( @@ -28,6 +30,7 @@ import ( "errors" "fmt" "io" + "io/fs" "log" "os" "path/filepath" @@ -61,10 +64,18 @@ type Page struct { // .Global care must be taken when utilizing this functionality. var Global interface{} +// Funcs accessible to the templates. +var Funcs template.FuncMap + // CacheIndex determines whether or not the index will be cached in memory // or rebuilt on each call. var CacheIndex = true +// FileSystem can be replaced with anything that implements the fs.FS interface +// and the website should be able to continue working with a different +// backend. +var FileSystem = os.DirFS(".") + // BaseTemplate can be adjusted to change the base template used in rendering. var BaseTemplate = "inc/base.html" @@ -108,11 +119,18 @@ func (p *Page) Render(wr io.Writer) error { return err } - t, err := template.ParseFiles(BaseTemplate) + templateContent, err := fs.ReadFile(FileSystem, BaseTemplate) if err != nil { - return fmt.Errorf("rendering: %w", err) + return fmt.Errorf("reading base template: %w", err) } + t, err := template.New("baseTemplate").Funcs(Funcs).Parse(string(templateContent)) + if err != nil { + return fmt.Errorf("parsing: %w", err) + } + + t = t.Funcs(Funcs) + return t.Execute(wr, p) } @@ -121,7 +139,7 @@ func (p *Page) Read() error { yamlBuf := bytes.NewBuffer(nil) markdownBuf := bytes.NewBuffer(nil) - fh, err := os.Open(p.path + Suffix) + fh, err := FileSystem.Open(p.path + Suffix) if err != nil { return fmt.Errorf("opening markdown: %w", err) } @@ -171,11 +189,12 @@ func (p *Page) Read() error { } // RenderBody renders and executes a template from the body of the -// markdown file, then runs it through the markdown parser. +// markdown file, then runs it through the markdown parser. Typically +// this is called in the base template. func (p *Page) RenderBody() (string, error) { buf := &bytes.Buffer{} - t, err := template.New("Body").Parse(string(p.markdown)) + t, err := template.New("Body").Funcs(Funcs).Parse(string(p.markdown)) if err != nil { return "", fmt.Errorf("render body: %w", err) } diff --git a/rediscache/main.go b/rediscache/main.go index 7ae3d4d..04ca622 100644 --- a/rediscache/main.go +++ b/rediscache/main.go @@ -54,16 +54,31 @@ func (rw *redisHTTPResponseWriter) WriteData() { rw.Data = rw.buf.Bytes() } -// Simple function that will cache the response for given handler in redis -// and instead of responding with the result from the handler it will +// HandleWithParams is the same as Handle but caches for the GET params +// rather than discarding them. +func HandleWithParams(pool *redis.Pool, key string, next http.Handler) http.Handler { + return handle(pool, key, true, next) +} + +// Handle is a Simple function that will cache the response for given handler in +// redis and instead of responding with the result from the handler it will // simply dump the contents of the redis key if it exists. func Handle(pool *redis.Pool, key string, next http.Handler) http.Handler { + return handle(pool, key, false, next) +} + +func handle(pool *redis.Pool, key string, params bool, next http.Handler) http.Handler { //nolint:funlen return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { client := pool.Get() defer client.Close() + subkey := r.URL.Path + if params { + subkey = r.URL.Path + "?" + r.URL.RawQuery + } + content: - data, err := client.Do("HGET", key, r.URL.Path) + data, err := client.Do("HGET", key, subkey) if err != nil { // Assume something bad has happened with redis, we're // just going to log this and then pass through the @@ -83,7 +98,7 @@ func Handle(pool *redis.Pool, key string, next http.Handler) http.Handler { return } - _, err = client.Do("HSET", key, r.URL.Path, b) + _, err = client.Do("HSET", key, subkey, b) if err != nil { Logger.Println("ERROR: during set: ", err) |
