diff --git a/activitystreams.go b/activitystreams.go index f187484..ee86784 100644 --- a/activitystreams.go +++ b/activitystreams.go @@ -43,7 +43,7 @@ func servePostActivityStreams(w http.ResponseWriter, r *http.Request) { // Remove ".as" from path again r.URL.Path = strings.TrimSuffix(r.URL.Path, ".as") // Fetch post from db - p, err := getPost(r.Context(), slashTrimmedPath(r)) + p, err := getPost(slashTrimmedPath(r)) if err == errPostNotFound { serve404(w, r) return diff --git a/cache.go b/cache.go index 6949b70..6146d7b 100644 --- a/cache.go +++ b/cache.go @@ -1,7 +1,6 @@ package main import ( - "context" "database/sql" "net/http" "net/http/httptest" @@ -61,7 +60,7 @@ func cacheMiddleware(next http.Handler) http.Handler { // Get cache cm := cacheMutexes[path] cm.Lock() - cacheTime, header, body := getCache(r.Context(), path) + cacheTime, header, body := getCache(path) cm.Unlock() if cacheTime == 0 { cm.Lock() @@ -122,10 +121,10 @@ func renderCache(path string, next http.Handler, w http.ResponseWriter, r *http. } } -func getCache(context context.Context, path string) (creationTime int64, header map[string][]string, body []byte) { +func getCache(path string) (creationTime int64, header map[string][]string, body []byte) { var headerBytes []byte allowedTime := time.Now().Unix() - appConfig.Cache.Expiration - row := cacheDb.QueryRowContext(context, "select COALESCE(time, 0), header, body from cache where path=? and time>=?", path, allowedTime) + row := cacheDb.QueryRow("select COALESCE(time, 0), header, body from cache where path=? and time>=?", path, allowedTime) _ = row.Scan(&creationTime, &headerBytes, &body) header = make(map[string][]string) _ = json.Unmarshal(headerBytes, &header) diff --git a/config.go b/config.go index 9dae141..9083838 100644 --- a/config.go +++ b/config.go @@ -108,6 +108,9 @@ type configHooks struct { Shell string `mapstructure:"shell"` Hourly []string `mapstructure:"hourly"` PreStart []string `mapstructure:"prestart"` + // Can use template + PostPost []string `mapstructure:"postpost"` + PostDelete []string `mapstructure:"postdelete"` } type configHugo struct { diff --git a/hooks.go b/hooks.go index d798e7e..c1b071d 100644 --- a/hooks.go +++ b/hooks.go @@ -1,6 +1,8 @@ package main import ( + "bytes" + "html/template" "log" "os/exec" "time" @@ -8,11 +10,50 @@ import ( func preStartHooks() { for _, cmd := range appConfig.Hooks.PreStart { - log.Println("Executing pre-start hook:", cmd) - executeCommand(cmd) + go func(cmd string) { + log.Println("Executing pre-start hook:", cmd) + executeCommand(cmd) + }(cmd) } } +func postPostHooks(path string) { + for _, cmdTmplString := range appConfig.Hooks.PostPost { + go func(path, cmdTmplString string) { + executeTemplateCommand("post-post", cmdTmplString, &hookTemplateData{ + URL: appConfig.Server.PublicAddress + path, + }) + }(path, cmdTmplString) + } +} + +func postDeleteHooks(path string) { + for _, cmdTmplString := range appConfig.Hooks.PostDelete { + go func(path, cmdTmplString string) { + executeTemplateCommand("post-delete", cmdTmplString, &hookTemplateData{ + URL: appConfig.Server.PublicAddress + path, + }) + }(path, cmdTmplString) + } +} + +type hookTemplateData struct { + URL string +} + +func executeTemplateCommand(hookType string, tmpl string, data *hookTemplateData) { + cmdTmpl, err := template.New("cmd").Parse(tmpl) + if err != nil { + log.Println("Failed to parse cmd template:", err.Error()) + return + } + var cmdBuf bytes.Buffer + cmdTmpl.Execute(&cmdBuf, data) + cmd := cmdBuf.String() + log.Println("Executing "+hookType+" hook:", cmd) + executeCommand(cmd) +} + func startHourlyHooks() { for _, cmd := range appConfig.Hooks.Hourly { go func(cmd string) { @@ -21,11 +62,11 @@ func startHourlyHooks() { executeCommand(cmd) } // Execute once - run() + go run() // Start ticker and execute regularly ticker := time.NewTicker(1 * time.Hour) for range ticker.C { - run() + go run() } }(cmd) } diff --git a/micropub.go b/micropub.go index 24a8df5..75054a2 100644 --- a/micropub.go +++ b/micropub.go @@ -38,14 +38,14 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - p, err := getPost(r.Context(), u.Path) + p, err := getPost(u.Path) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } mf = p.toMfItem() } else { - posts, err := getPosts(r.Context(), &postsRequestConfig{}) + posts, err := getPosts(&postsRequestConfig{}) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -391,7 +391,7 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr if !strings.Contains(r.Context().Value("scope").(string), "update") { http.Error(w, "update scope missing", http.StatusForbidden) } - p, err := getPost(r.Context(), u.Path) + p, err := getPost(u.Path) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/posts.go b/posts.go index 2e563f0..14573be 100644 --- a/posts.go +++ b/posts.go @@ -1,7 +1,6 @@ package main import ( - "context" "errors" "fmt" "html/template" @@ -35,7 +34,7 @@ func servePost(w http.ResponseWriter, r *http.Request) { return } path := slashTrimmedPath(r) - p, err := getPost(r.Context(), path) + p, err := getPost(path) if err == errPostNotFound { serve404(w, r) return @@ -62,14 +61,13 @@ type indexTemplateData struct { } type postPaginationAdapter struct { - context context.Context - config *postsRequestConfig - nums int + config *postsRequestConfig + nums int } func (p *postPaginationAdapter) Nums() int { if p.nums == 0 { - p.nums, _ = countPosts(p.context, p.config) + p.nums, _ = countPosts(p.config) } return p.nums } @@ -83,7 +81,7 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro modifiedConfig.offset = offset modifiedConfig.limit = length - posts, err := getPosts(p.context, &modifiedConfig) + posts, err := getPosts(&modifiedConfig) reflect.ValueOf(data).Elem().Set(reflect.ValueOf(&posts).Elem()) return err } @@ -163,7 +161,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) { sections = append(sections, sectionKey) } } - p := paginator.New(&postPaginationAdapter{context: r.Context(), config: &postsRequestConfig{ + p := paginator.New(&postPaginationAdapter{config: &postsRequestConfig{ blog: ic.blog, sections: sections, taxonomy: ic.tax, @@ -219,8 +217,8 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) { } } -func getPost(context context.Context, path string) (*post, error) { - posts, err := getPosts(context, &postsRequestConfig{path: path}) +func getPost(path string) (*post, error) { + posts, err := getPosts(&postsRequestConfig{path: path}) if err != nil { return nil, err } else if len(posts) == 0 { @@ -281,9 +279,9 @@ func buildQuery(config *postsRequestConfig) (query string, params []interface{}) return } -func getPosts(context context.Context, config *postsRequestConfig) (posts []*post, err error) { +func getPosts(config *postsRequestConfig) (posts []*post, err error) { query, queryParams := buildQuery(config) - rows, err := appDb.QueryContext(context, query, queryParams...) + rows, err := appDb.Query(query, queryParams...) if err != nil { return nil, err } @@ -311,10 +309,10 @@ func getPosts(context context.Context, config *postsRequestConfig) (posts []*pos return posts, nil } -func countPosts(context context.Context, config *postsRequestConfig) (count int, err error) { +func countPosts(config *postsRequestConfig) (count int, err error) { query, params := buildQuery(config) query = "select count(distinct path) from (" + query + ")" - row := appDb.QueryRowContext(context, query, params...) + row := appDb.QueryRow(query, params...) err = row.Scan(&count) return } diff --git a/postsDb.go b/postsDb.go index a7b29e3..74a4ae6 100644 --- a/postsDb.go +++ b/postsDb.go @@ -156,6 +156,7 @@ func (p *post) createOrReplace(new bool) error { } finishWritingToDb() go purgeCache() + defer postPostHooks(p.Path) return reloadRouter() } @@ -188,5 +189,6 @@ func deletePost(path string) error { } finishWritingToDb() go purgeCache() + defer postDeleteHooks(path) return reloadRouter() } diff --git a/postsFuncs.go b/postsFuncs.go index abf3268..68f28b0 100644 --- a/postsFuncs.go +++ b/postsFuncs.go @@ -1,7 +1,6 @@ package main import ( - "context" "html/template" "log" "strings" @@ -56,7 +55,7 @@ func (p *post) translations() []*post { if translationkey == "" { return nil } - posts, err := getPosts(context.Background(), &postsRequestConfig{ + posts, err := getPosts(&postsRequestConfig{ parameter: "translationkey", parameterValue: translationkey, }) diff --git a/redirects.go b/redirects.go index e828026..c2855c2 100644 --- a/redirects.go +++ b/redirects.go @@ -1,7 +1,6 @@ package main import ( - "context" "database/sql" "errors" "net/http" @@ -11,7 +10,7 @@ import ( var errRedirectNotFound = errors.New("redirect not found") func serveRedirect(w http.ResponseWriter, r *http.Request) { - redirect, err := getRedirect(r.Context(), slashTrimmedPath(r)) + redirect, err := getRedirect(slashTrimmedPath(r)) if err == errRedirectNotFound { serve404(w, r) return @@ -27,9 +26,9 @@ func serveRedirect(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusFound) } -func getRedirect(context context.Context, fromPath string) (string, error) { +func getRedirect(fromPath string) (string, error) { var toPath string - row := appDb.QueryRowContext(context, "with recursive f (i, fp, tp) as (select 1, fromPath, toPath from redirects where fromPath = ? union all select f.i + 1, r.fromPath, r.toPath from redirects as r join f on f.tp = r.fromPath) select tp from f order by i desc limit 1", fromPath) + row := appDb.QueryRow("with recursive f (i, fp, tp) as (select 1, fromPath, toPath from redirects where fromPath = ? union all select f.i + 1, r.fromPath, r.toPath from redirects as r join f on f.tp = r.fromPath) select tp from f order by i desc limit 1", fromPath) err := row.Scan(&toPath) if err == sql.ErrNoRows { return "", errRedirectNotFound diff --git a/sitemap.go b/sitemap.go index 4e53b57..f4e5c0e 100644 --- a/sitemap.go +++ b/sitemap.go @@ -11,7 +11,7 @@ import ( const sitemapPath = "/sitemap.xml" func serveSitemap(w http.ResponseWriter, r *http.Request) { - posts, err := getPosts(r.Context(), &postsRequestConfig{}) + posts, err := getPosts(&postsRequestConfig{}) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) }