/
cache.go
143 lines (127 loc) · 3.34 KB
/
cache.go
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package server
import (
"net/http"
"strconv"
"github.com/cutechan/cutechan/go/cache"
"github.com/cutechan/cutechan/go/common"
"github.com/cutechan/cutechan/go/db"
"github.com/cutechan/cutechan/go/lang"
"github.com/cutechan/cutechan/go/templates"
)
var threadCache = cache.FrontEnd{
GetCounter: func(k cache.Key) (uint64, error) {
return db.ThreadCounter(k.ID)
},
GetFresh: func(k cache.Key) (interface{}, error) {
return db.GetThread(k.ID, k.LastN)
},
RenderHTML: func(data interface{}, json []byte, k cache.Key) []byte {
last100 := k.LastN == common.NumPostsOnRequest
return []byte(templates.ThreadPosts(k.Lang, data.(common.Thread), json, last100))
},
}
var catalogCache = cache.FrontEnd{
GetCounter: func(k cache.Key) (uint64, error) {
if k.Board == "all" {
return db.AllBoardCounter()
}
return db.BoardCounter(k.Board)
},
GetFresh: func(k cache.Key) (interface{}, error) {
if k.Board == "all" {
return db.GetAllBoardCatalog()
}
return db.GetBoardCatalog(k.Board)
},
RenderHTML: func(data interface{}, json []byte, k cache.Key) []byte {
all := k.Board == "all"
return []byte(templates.CatalogThreads(data.(common.Board), json, all))
},
}
type boardPage struct {
pageN int
pageTotal int
json []byte
data common.Board
}
var boardPageCache = cache.FrontEnd{
GetCounter: func(k cache.Key) (uint64, error) {
if k.Board == "all" {
return db.AllBoardCounter()
}
return db.BoardCounter(k.Board)
},
GetFresh: func(k cache.Key) (data interface{}, err error) {
var ids []uint64
if k.Board == "all" {
ids, err = db.GetAllThreadsIDs()
} else {
ids, err = db.GetThreadIDs(k.Board)
}
if err != nil {
return
}
totalPages := (len(ids)-1)/common.ThreadsPerPage + 1
atLastPage := k.Page+1 == totalPages
if totalPages == 0 {
data = boardPage{json: []byte("[]")}
return
}
if k.Page+1 > totalPages {
err = errPageOverflow
return
}
page := boardPage{
pageN: k.Page,
pageTotal: totalPages,
json: []byte("["),
}
lowIdx := k.Page * common.ThreadsPerPage
highIdx := (k.Page + 1) * common.ThreadsPerPage
if atLastPage {
highIdx = len(ids)
}
pageIDs := ids[lowIdx:highIdx]
for i, id := range pageIDs {
k := cache.ThreadKey(k.Lang, id, common.NumPostsAtIndex)
tjson, tdata, _, terr := cache.GetJSONAndData(k, threadCache)
if terr != nil {
return nil, terr
}
if i > 0 {
page.json = append(page.json, ',')
}
page.json = append(page.json, tjson...)
page.data = append(page.data, tdata.(common.Thread))
}
page.json = append(page.json, ']')
return page, nil
},
EncodeJSON: func(data interface{}) ([]byte, error) {
return data.(boardPage).json, nil
},
RenderHTML: func(data interface{}, json []byte, k cache.Key) []byte {
all := k.Board == "all"
return []byte(templates.IndexThreads(k.Lang, data.(boardPage).data, json, all))
},
}
// Returns arguments for accessing the board page JSON/HTML cache
func boardCacheArgs(r *http.Request, board string, catalog bool) (
k cache.Key, f cache.FrontEnd,
) {
page := 0
// TODO(Kagami): Make catalogs paginated too.
if !catalog {
pStr := r.URL.Query().Get("page")
if p, err := strconv.ParseUint(pStr, 10, 64); err == nil {
page = int(p)
}
}
k = cache.BoardKey(lang.FromReq(r), board, page, catalog)
if catalog {
f = catalogCache
} else {
f = boardPageCache
}
return
}