diff --git a/micropub.go b/micropub.go index d3a1ac2..24bb8d6 100644 --- a/micropub.go +++ b/micropub.go @@ -13,7 +13,6 @@ import ( "github.com/samber/lo" "github.com/spf13/cast" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" "gopkg.in/yaml.v3" ) @@ -76,14 +75,12 @@ func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) { a.serve404(w, r) return } - buf := bufferpool.Get() - defer bufferpool.Put(buf) - if err := json.NewEncoder(buf).Encode(result); err != nil { - a.serveError(w, r, "Failed to encode json", http.StatusInternalServerError) - return - } + pr, pw := io.Pipe() + go func() { + _ = pw.CloseWithError(json.NewEncoder(pw).Encode(result)) + }() w.Header().Set(contentType, contenttype.JSONUTF8) - _ = a.min.Get().Minify(contenttype.JSON, w, buf) + _ = pr.CloseWithError(a.min.Get().Minify(contenttype.JSON, w, pr)) } func (a *goBlog) getMicropubChannelsMap() []map[string]any { diff --git a/nodeinfo.go b/nodeinfo.go index ea2000d..2985918 100644 --- a/nodeinfo.go +++ b/nodeinfo.go @@ -5,29 +5,24 @@ import ( "io" "net/http" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" ) func (a *goBlog) serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) { - buf := bufferpool.Get() - defer bufferpool.Put(buf) - err := json.NewEncoder(buf).Encode(map[string]any{ + result := map[string]any{ "links": []map[string]any{ { "href": a.getFullAddress("/nodeinfo"), "rel": "http://nodeinfo.diaspora.software/ns/schema/2.1", }, }, - }) - if err != nil { - a.serveError(w, r, "", http.StatusInternalServerError) - return } + pr, pw := io.Pipe() + go func() { + _ = pw.CloseWithError(json.NewEncoder(pw).Encode(result)) + }() w.Header().Set(contentType, contenttype.JSONUTF8) - mw := a.min.Get().Writer(contenttype.JSON, w) - _, _ = io.Copy(mw, buf) - _ = mw.Close() + _ = pr.CloseWithError(a.min.Get().Minify(contenttype.JSON, w, pr)) } func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) { @@ -35,9 +30,7 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) { status: []postStatus{statusPublished}, visibility: []postVisibility{visibilityPublic}, }) - buf := bufferpool.Get() - defer bufferpool.Put(buf) - if err := json.NewEncoder(buf).Encode(map[string]any{ + result := map[string]any{ "version": "2.1", "software": map[string]any{ "name": "goblog", @@ -55,10 +48,11 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) { "webmention", }, "metadata": map[string]any{}, - }); err != nil { - a.serveError(w, r, "", http.StatusInternalServerError) - return } + pr, pw := io.Pipe() + go func() { + _ = pw.CloseWithError(json.NewEncoder(pw).Encode(result)) + }() w.Header().Set(contentType, contenttype.JSONUTF8) - _ = a.min.Get().Minify(contenttype.JSON, w, buf) + _ = pr.CloseWithError(a.min.Get().Minify(contenttype.JSON, w, pr)) } diff --git a/opensearch.go b/opensearch.go index 5eedcc5..5bfc1a2 100644 --- a/opensearch.go +++ b/opensearch.go @@ -2,9 +2,9 @@ package main import ( "encoding/xml" + "io" "net/http" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" ) @@ -49,15 +49,13 @@ func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) { }, SearchForm: sURL, } - buf := bufferpool.Get() - defer bufferpool.Put(buf) - _, _ = buf.WriteString(xml.Header) - if err := xml.NewEncoder(buf).Encode(openSearch); err != nil { - a.serveError(w, r, "", http.StatusInternalServerError) - return - } + pr, pw := io.Pipe() + go func() { + _, _ = io.WriteString(pw, xml.Header) + _ = pw.CloseWithError(xml.NewEncoder(pw).Encode(openSearch)) + }() w.Header().Set(contentType, "application/opensearchdescription+xml"+contenttype.CharsetUtf8Suffix) - _ = a.min.Get().Minify(contenttype.XML, w, buf) + _ = pr.CloseWithError(a.min.Get().Minify(contenttype.XML, w, pr)) } func openSearchUrl(b *configBlog) string { diff --git a/pkgs/highlighting/highlighting.go b/pkgs/highlighting/highlighting.go index 47ffd49..fe9728a 100644 --- a/pkgs/highlighting/highlighting.go +++ b/pkgs/highlighting/highlighting.go @@ -2,13 +2,13 @@ package highlighting import ( "io" + "strings" "github.com/yuin/goldmark" "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/renderer" "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/util" - "go.goblog.app/app/pkgs/bufferpool" "github.com/alecthomas/chroma/v2" chromahtml "github.com/alecthomas/chroma/v2/formatters/html" @@ -60,8 +60,7 @@ func (r *htmlRenderer) renderFencedCodeBlock(w util.BufWriter, source []byte, no n := node.(*ast.FencedCodeBlock) // Read code block content. - buf := bufferpool.Get() - defer bufferpool.Put(buf) + var buf strings.Builder for _, line := range n.Lines().Sliced(0, n.Lines().Len()) { buf.Write(line.Value(source)) } @@ -70,7 +69,7 @@ func (r *htmlRenderer) renderFencedCodeBlock(w util.BufWriter, source []byte, no if highlight(w, buf.String(), string(n.Language(source)), r.formatter) != nil { // Highlight failed, fallback to plain text. _, _ = w.WriteString("
")
-		r.Writer.RawWrite(w, buf.Bytes())
+		r.Writer.RawWrite(w, []byte(buf.String()))
 		_, _ = w.WriteString("
\n") } diff --git a/postsDb.go b/postsDb.go index fec172a..e1f2a36 100644 --- a/postsDb.go +++ b/postsDb.go @@ -206,8 +206,7 @@ func (db *database) savePost(p *post, o *postCreationOptions) error { db.pcm.Lock() defer db.pcm.Unlock() // Build SQL - sqlBuilder := bufferpool.Get() - defer bufferpool.Put(sqlBuilder) + var sqlBuilder strings.Builder var sqlArgs = []any{dbNoCache} // Start transaction sqlBuilder.WriteString("begin;") @@ -336,7 +335,7 @@ func (db *database) replacePostParam(path, param string, values []string) error db.pcm.Lock() defer db.pcm.Unlock() // Build SQL - sqlBuilder := bufferpool.Get() + var sqlBuilder strings.Builder var sqlArgs = []any{dbNoCache} // Start transaction sqlBuilder.WriteString("begin;") @@ -352,7 +351,6 @@ func (db *database) replacePostParam(path, param string, values []string) error sqlBuilder.WriteString("commit;") // Execute _, err := db.Exec(sqlBuilder.String(), sqlArgs...) - bufferpool.Put(sqlBuilder) if err != nil { return err } @@ -387,8 +385,7 @@ type postsRequestConfig struct { } func buildPostsQuery(c *postsRequestConfig, selection string) (query string, args []any) { - queryBuilder := bufferpool.Get() - defer bufferpool.Put(queryBuilder) + var queryBuilder strings.Builder // Selection queryBuilder.WriteString("select ") queryBuilder.WriteString(selection) @@ -413,11 +410,11 @@ func buildPostsQuery(c *postsRequestConfig, selection string) (query string, arg queryBuilder.WriteString(", ") } named := "status" + strconv.Itoa(i) - queryBuilder.WriteByte('@') + queryBuilder.WriteString("@") queryBuilder.WriteString(named) args = append(args, sql.Named(named, status)) } - queryBuilder.WriteByte(')') + queryBuilder.WriteString(")") } if c.visibility != nil && len(c.visibility) > 0 { queryBuilder.WriteString(" and visibility in (") @@ -426,11 +423,11 @@ func buildPostsQuery(c *postsRequestConfig, selection string) (query string, arg queryBuilder.WriteString(", ") } named := "visibility" + strconv.Itoa(i) - queryBuilder.WriteByte('@') + queryBuilder.WriteString("@") queryBuilder.WriteString(named) args = append(args, sql.Named(named, visibility)) } - queryBuilder.WriteByte(')') + queryBuilder.WriteString(")") } if c.blog != "" { queryBuilder.WriteString(" and blog = @blog") @@ -451,7 +448,7 @@ func buildPostsQuery(c *postsRequestConfig, selection string) (query string, arg queryBuilder.WriteString(", ") } named := "param" + strconv.Itoa(i) - queryBuilder.WriteByte('@') + queryBuilder.WriteString("@") queryBuilder.WriteString(named) args = append(args, param) } @@ -477,11 +474,11 @@ func buildPostsQuery(c *postsRequestConfig, selection string) (query string, arg queryBuilder.WriteString(", ") } named := "section" + strconv.Itoa(i) - queryBuilder.WriteByte('@') + queryBuilder.WriteString("@") queryBuilder.WriteString(named) args = append(args, sql.Named(named, section)) } - queryBuilder.WriteByte(')') + queryBuilder.WriteString(")") } if c.publishedYear != 0 { queryBuilder.WriteString(" and substr(tolocal(published), 1, 4) = @publishedyear") @@ -522,8 +519,7 @@ func (d *database) loadPostParameters(posts []*post, parameters ...string) (err } // Build query sqlArgs := make([]any, 0) - queryBuilder := bufferpool.Get() - defer bufferpool.Put(queryBuilder) + var queryBuilder strings.Builder queryBuilder.WriteString("select path, parameter, value from post_parameters where") // Paths queryBuilder.WriteString(" path in (") @@ -532,11 +528,11 @@ func (d *database) loadPostParameters(posts []*post, parameters ...string) (err queryBuilder.WriteString(", ") } named := "path" + strconv.Itoa(i) - queryBuilder.WriteByte('@') + queryBuilder.WriteString("@") queryBuilder.WriteString(named) sqlArgs = append(sqlArgs, sql.Named(named, p.Path)) } - queryBuilder.WriteByte(')') + queryBuilder.WriteString(")") // Parameters if len(parameters) > 0 { queryBuilder.WriteString(" and parameter in (") @@ -545,11 +541,11 @@ func (d *database) loadPostParameters(posts []*post, parameters ...string) (err queryBuilder.WriteString(", ") } named := "param" + strconv.Itoa(i) - queryBuilder.WriteByte('@') + queryBuilder.WriteString("@") queryBuilder.WriteString(named) sqlArgs = append(sqlArgs, sql.Named(named, p)) } - queryBuilder.WriteByte(')') + queryBuilder.WriteString(")") } // Order queryBuilder.WriteString(" order by id") @@ -695,7 +691,7 @@ group by name; func (db *database) usesOfMediaFile(names ...string) (counts []int, err error) { sqlArgs := []any{dbNoCache} - nameValues := bufferpool.Get() + var nameValues strings.Builder for i, n := range names { if i > 0 { nameValues.WriteString(", ") @@ -703,11 +699,10 @@ func (db *database) usesOfMediaFile(names ...string) (counts []int, err error) { named := "name" + strconv.Itoa(i) nameValues.WriteString("(@") nameValues.WriteString(named) - nameValues.WriteByte(')') + nameValues.WriteString(")") sqlArgs = append(sqlArgs, sql.Named(named, n)) } rows, err := db.Query(fmt.Sprintf(mediaUseSql, nameValues.String()), sqlArgs...) - bufferpool.Put(nameValues) if err != nil { return nil, err } diff --git a/reactions.go b/reactions.go index 40c5575..fd69e2c 100644 --- a/reactions.go +++ b/reactions.go @@ -5,10 +5,10 @@ import ( "errors" "io" "net/http" + "strings" "github.com/dgraph-io/ristretto" "github.com/samber/lo" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" ) @@ -88,15 +88,12 @@ func (a *goBlog) getReactions(w http.ResponseWriter, r *http.Request) { a.serveError(w, r, "", http.StatusInternalServerError) return } - buf := bufferpool.Get() - defer bufferpool.Put(buf) - err = json.NewEncoder(buf).Encode(reactions) - if err != nil { - a.serveError(w, r, "", http.StatusInternalServerError) - return - } + pr, pw := io.Pipe() + go func() { + _ = pw.CloseWithError(json.NewEncoder(pw).Encode(reactions)) + }() w.Header().Set(contentType, contenttype.JSONUTF8) - _, _ = io.Copy(w, buf) + _ = pr.CloseWithError(a.min.Get().Minify(contenttype.JSON, w, pr)) } func (a *goBlog) getReactionsFromDatabase(path string) (map[string]int, error) { @@ -110,8 +107,7 @@ func (a *goBlog) getReactionsFromDatabase(path string) (map[string]int, error) { // Get reactions res, err, _ := a.reactionsSfg.Do(path, func() (any, error) { // Build query - sqlBuf := bufferpool.Get() - defer bufferpool.Put(sqlBuf) + var sqlBuf strings.Builder sqlArgs := []any{} sqlBuf.WriteString("select reaction, count from reactions where path=? and reaction in (") sqlArgs = append(sqlArgs, path) diff --git a/reactions_test.go b/reactions_test.go index 757cd9d..50e93f8 100644 --- a/reactions_test.go +++ b/reactions_test.go @@ -136,13 +136,13 @@ func Test_reactionsHighLevel(t *testing.T) { rec = httptest.NewRecorder() app.getReactions(rec, req) assert.Equal(t, http.StatusOK, rec.Code) - assert.Equal(t, "{\"❤️\":1}\n", rec.Body.String()) + assert.Equal(t, "{\"❤️\":1}", rec.Body.String()) // Get reactions for a non-existing post req = httptest.NewRequest(http.MethodGet, "/?path=/non-existing-post", nil) rec = httptest.NewRecorder() app.getReactions(rec, req) assert.Equal(t, http.StatusOK, rec.Code) - assert.Equal(t, "{}\n", rec.Body.String()) + assert.Equal(t, "{}", rec.Body.String()) } diff --git a/sitemap.go b/sitemap.go index 75769b8..3580c22 100644 --- a/sitemap.go +++ b/sitemap.go @@ -3,12 +3,12 @@ package main import ( "database/sql" "encoding/xml" + "io" "net/http" "time" "github.com/araddon/dateparse" "github.com/snabb/sitemap" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" ) @@ -174,18 +174,16 @@ func (a *goBlog) serveSitemapBlogPosts(w http.ResponseWriter, r *http.Request) { } func (a *goBlog) writeSitemapXML(w http.ResponseWriter, r *http.Request, sm any) { - buf := bufferpool.Get() - defer bufferpool.Put(buf) - _, _ = buf.WriteString(xml.Header) - _, _ = buf.WriteString(``) - if err := xml.NewEncoder(buf).Encode(sm); err != nil { - a.serveError(w, r, "Failed to encode sitemap", http.StatusInternalServerError) - return - } + pr, pw := io.Pipe() + go func() { + _, _ = io.WriteString(pw, xml.Header) + _, _ = io.WriteString(pw, ``) + _ = pw.CloseWithError(xml.NewEncoder(pw).Encode(sm)) + }() w.Header().Set(contentType, contenttype.XMLUTF8) - _ = a.min.Get().Minify(contenttype.XML, w, buf) + _ = pr.CloseWithError(a.min.Get().Minify(contenttype.XML, w, pr)) } const sitemapDatePathsSql = ` diff --git a/telegram.go b/telegram.go index cce491a..b3a081d 100644 --- a/telegram.go +++ b/telegram.go @@ -5,9 +5,9 @@ import ( "log" "net/url" "strconv" + "strings" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "go.goblog.app/app/pkgs/bufferpool" ) func (a *goBlog) initTelegram() { @@ -135,8 +135,7 @@ func (tg *configTelegram) generateHTML(title, fullURL, shortURL string) (html st if !tg.enabled() { return "" } - message := bufferpool.Get() - defer bufferpool.Put(message) + var message strings.Builder if title != "" { message.WriteString(tgbotapi.EscapeText(tgbotapi.ModeHTML, title)) message.WriteString("\n\n") diff --git a/uiComponents.go b/uiComponents.go index 14acacb..3b2ea1b 100644 --- a/uiComponents.go +++ b/uiComponents.go @@ -6,7 +6,6 @@ import ( "time" "github.com/samber/lo" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/htmlbuilder" ) @@ -65,7 +64,7 @@ func (a *goBlog) renderSummary(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *p } // Show link to full post hb.WriteElementOpen("p") - prefix := bufferpool.Get() + var prefix strings.Builder if len(photos) > 0 { // Contains photos prefix.WriteString("🖼️") @@ -75,10 +74,9 @@ func (a *goBlog) renderSummary(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *p prefix.WriteString("🗺️") } if prefix.Len() > 0 { - prefix.WriteRune(' ') + prefix.WriteString(" ") hb.WriteEscaped(prefix.String()) } - bufferpool.Put(prefix) hb.WriteElementOpen("a", "class", "u-url", "href", p.Path) hb.WriteEscaped(a.ts.GetTemplateStringVariant(bc.Lang, "view")) hb.WriteElementClose("a") diff --git a/webmention.go b/webmention.go index 52adab4..770cd40 100644 --- a/webmention.go +++ b/webmention.go @@ -8,7 +8,6 @@ import ( "strings" "time" - "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" ) @@ -231,8 +230,7 @@ type webmentionsRequestConfig struct { } func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args []any) { - queryBuilder := bufferpool.Get() - defer bufferpool.Put(queryBuilder) + var queryBuilder strings.Builder queryBuilder.WriteString("select id, source, target, url, created, title, content, author, status from webmentions ") if config != nil { queryBuilder.WriteString("where 1")