Skip to content

Commit e104f12

Browse files
committed
reduce the number of functions iterating on pages
1 parent e1c9b04 commit e104f12

File tree

9 files changed

+54
-68
lines changed

9 files changed

+54
-68
lines changed

build.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package xlog
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"io"
78
"io/fs"
89
"log/slog"
@@ -30,7 +31,7 @@ func RegisterBuildPage(p string, encloseInDir bool) {
3031
}
3132
}
3233

33-
func buildStaticSite(dest string) error {
34+
func build(dest string) error {
3435
srv := server()
3536

3637
// building Index separately
@@ -45,7 +46,7 @@ func buildStaticSite(dest string) error {
4546
slog.Error("Index Page may not exist, make sure your Index Page exists", "index", Config.Index, "error", err)
4647
}
4748

48-
EachPageCon(context.Background(), func(p Page) {
49+
errs := MapPage(context.Background(), func(p Page) error {
4950
err := buildRoute(
5051
srv,
5152
"/"+p.Name(),
@@ -54,10 +55,16 @@ func buildStaticSite(dest string) error {
5455
)
5556

5657
if err != nil {
57-
slog.Error("Failed to process", "page", p.Name(), "error", err)
58+
return fmt.Errorf("Failed to process page: %s, error: %w", p.Name(), err)
5859
}
60+
61+
return nil
5962
})
6063

64+
if err := errors.Join(errs...); err != nil {
65+
slog.Error(err.Error())
66+
}
67+
6168
// If we render 404 page
6269
// Copy 404 page from dest/404/index.html to /dest/404.html
6370
if in, err := os.Open(path.Join(dest, Config.NotFoundPage, "index.html")); err == nil {

each.go

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package xlog
22

33
import (
44
"context"
5+
"reflect"
56
"regexp"
67
"runtime"
78
"sync"
@@ -61,30 +62,9 @@ func EachPage(ctx context.Context, f func(Page)) {
6162

6263
var concurrency = runtime.NumCPU() * 4
6364

64-
// EachPageCon Similar to EachPage but iterates concurrently
65-
func EachPageCon(ctx context.Context, f func(Page)) {
66-
if pages == nil {
67-
populatePagesCache(ctx)
68-
}
69-
70-
grp, ctx := errgroup.WithContext(ctx)
71-
grp.SetLimit(concurrency)
72-
73-
currentPages := pages
74-
for _, p := range currentPages {
75-
select {
76-
case <-ctx.Done():
77-
break
78-
default:
79-
grp.Go(func() (err error) { f(p); return })
80-
}
81-
}
82-
83-
grp.Wait()
84-
}
85-
86-
// MapPageCon Similar to EachPage but iterates concurrently
87-
func MapPageCon[T any](ctx context.Context, f func(Page) T) []T {
65+
// MapPage Similar to EachPage but iterates concurrently and accumulates
66+
// returns in a slice
67+
func MapPage[T any](ctx context.Context, f func(Page) T) []T {
8868
if pages == nil {
8969
populatePagesCache(ctx)
9070
}
@@ -103,7 +83,7 @@ func MapPageCon[T any](ctx context.Context, f func(Page) T) []T {
10383
default:
10484
grp.Go(func() (err error) {
10585
val := f(p)
106-
if any(val) == nil {
86+
if isNil(val) {
10787
return
10888
}
10989

@@ -121,6 +101,20 @@ func MapPageCon[T any](ctx context.Context, f func(Page) T) []T {
121101
return output
122102
}
123103

104+
// From https://stackoverflow.com/a/77341451/22401486
105+
func isNil[T any](t T) bool {
106+
v := reflect.ValueOf(t)
107+
kind := v.Kind()
108+
// Must be one of these types to be nillable
109+
return (kind == reflect.Ptr ||
110+
kind == reflect.Interface ||
111+
kind == reflect.Slice ||
112+
kind == reflect.Map ||
113+
kind == reflect.Chan ||
114+
kind == reflect.Func) &&
115+
v.IsNil()
116+
}
117+
124118
func clearPagesCache(p Page) (err error) {
125119
pages = nil
126120
return nil

extensions/autolink_pages/autolink_pages.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func backlinksSection(p Page) template.HTML {
5656
return ""
5757
}
5858

59-
pages := MapPageCon(context.Background(), func(a Page) Page {
59+
pages := MapPage(context.Background(), func(a Page) Page {
6060
_, tree := a.AST()
6161
if a.Name() == p.Name() || !containLinkTo(tree, p) {
6262
return nil

extensions/date/handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func dateHandler(r Request) Output {
1717
return BadRequest(err.Error())
1818
}
1919

20-
pages := MapPageCon(r.Context(), func(p Page) Page {
20+
pages := MapPage(r.Context(), func(p Page) Page {
2121
_, tree := p.AST()
2222
allDates := FindAllInAST[*DateNode](tree)
2323
for _, d := range allDates {

extensions/hashtags/hashtags.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ func tagsHandler(r Request) Output {
120120
tags := map[string][]Page{}
121121
var lck sync.Mutex
122122

123-
EachPageCon(context.Background(), func(a Page) {
124-
123+
MapPage(context.Background(), func(a Page) bool {
125124
set := map[string]bool{}
126125
_, tree := a.AST()
127126
hashes := FindAllInAST[*HashTag](tree)
@@ -143,6 +142,8 @@ func tagsHandler(r Request) Output {
143142
}
144143
lck.Unlock()
145144
}
145+
146+
return true
146147
})
147148

148149
return Render("tags", Locals{
@@ -161,7 +162,7 @@ func tagHandler(r Request) Output {
161162
}
162163

163164
func tagPages(ctx context.Context, keyword string) []Page {
164-
return MapPageCon(ctx, func(p Page) Page {
165+
return MapPage(ctx, func(p Page) Page {
165166
if p.Name() == Config.Index {
166167
return nil
167168
}
@@ -190,7 +191,7 @@ func relatedPages(p Page) template.HTML {
190191
hashtags[strings.ToLower(string(v.value))] = true
191192
}
192193

193-
pages := MapPageCon(context.Background(), func(rp Page) Page {
194+
pages := MapPage(context.Background(), func(rp Page) Page {
194195
if rp.Name() == p.Name() {
195196
return nil
196197
}

extensions/search/search.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,32 +48,31 @@ type searchResult struct {
4848
Line string
4949
}
5050

51-
func search(ctx context.Context, keyword string) []searchResult {
52-
results := []searchResult{}
51+
func search(ctx context.Context, keyword string) []*searchResult {
52+
results := []*searchResult{}
5353
if len(keyword) < MIN_SEARCH_KEYWORD {
5454
return results
5555
}
5656

5757
reg := regexp.MustCompile(`(?imU)^(.*` + regexp.QuoteMeta(keyword) + `.*)$`)
5858

59-
EachPage(ctx, func(p Page) {
59+
return MapPage(ctx, func(p Page) *searchResult {
6060
match := reg.FindString(p.Name())
6161
if len(match) > 0 {
62-
results = append(results, searchResult{
62+
return &searchResult{
6363
Page: p.Name(),
6464
Line: "Matches the file name",
65-
})
66-
return
65+
}
6766
}
6867

6968
match = reg.FindString(string(p.Content()))
7069
if len(match) > 0 {
71-
results = append(results, searchResult{
70+
return &searchResult{
7271
Page: p.Name(),
7372
Line: match,
74-
})
73+
}
7574
}
76-
})
7775

78-
return results
76+
return nil
77+
})
7978
}

extensions/sitemap/sitemap.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"flag"
55
"fmt"
66
"net/url"
7+
"strings"
78

89
. "github.com/emad-elsaid/xlog"
910
)
@@ -24,13 +25,13 @@ func (Sitemap) Init() {
2425
}
2526

2627
func handler(r Request) Output {
27-
output := `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`
28+
output := []string{`<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`}
2829

29-
EachPage(r.Context(), func(p Page) {
30-
output += fmt.Sprintf("<url><loc>https://%s/%s</loc></url>", SITEMAP_DOMAIN, url.PathEscape(p.Name()))
31-
})
30+
output = append(output, MapPage(r.Context(), func(p Page) string {
31+
return fmt.Sprintf("<url><loc>https://%s/%s</loc></url>", SITEMAP_DOMAIN, url.PathEscape(p.Name()))
32+
})...)
3233

33-
output += `</urlset>`
34+
output = append(output, `</urlset>`)
3435

35-
return PlainText(output)
36+
return PlainText(strings.Join(output, "\n"))
3637
}

handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func Start(ctx context.Context) {
4747
}
4848

4949
if len(Config.Build) > 0 {
50-
if err := buildStaticSite(Config.Build); err != nil {
50+
if err := build(Config.Build); err != nil {
5151
slog.Error("Failed to build static pages", "error", err)
5252
os.Exit(1)
5353
}

server.go

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ func defaultMiddlewares() (middlewares []func(http.Handler) http.Handler) {
4848
}
4949

5050
middlewares = append(middlewares,
51-
methodOverrideHandler,
5251
csrf.Protect(sessionSecret, crsfOpts...))
5352
}
5453

@@ -164,19 +163,6 @@ func Render(path string, data Locals) Output {
164163
}
165164
}
166165

167-
// Derived from Gorilla middleware https://github.com/gorilla/handlers/blob/v1.5.1/handlers.go#L134
168-
func methodOverrideHandler(h http.Handler) http.Handler {
169-
return http.HandlerFunc(func(w Response, r Request) {
170-
if r.Method == "POST" {
171-
om := r.FormValue("_method")
172-
if om == "PUT" || om == "PATCH" || om == "DELETE" {
173-
r.Method = om
174-
}
175-
}
176-
h.ServeHTTP(w, r)
177-
})
178-
}
179-
180166
func requestLoggerHandler(h http.Handler) http.Handler {
181167
return http.HandlerFunc(func(w Response, r Request) {
182168
start := time.Now()
@@ -193,9 +179,7 @@ func Cache(out Output) Output {
193179
}
194180
}
195181

196-
type funcStringer struct {
197-
any
198-
}
182+
type funcStringer struct{ any }
199183

200184
func (f funcStringer) String() string {
201185
const xlogPrefix = "emad-elsaid/xlog/"

0 commit comments

Comments
 (0)