ETags are now set by /api/phrases and Hyperdrive on the topic list for better caching.

Initialised the fields in hyperspace properly.

Eliminate an unnecessary line in client templates.
Cleaned up some thaw code in the forum store.
Fixed a potential premature thaw in Forums.BypassGet
This commit is contained in:
Azareal 2019-04-28 20:08:05 +10:00
parent 4414957885
commit efe7a0f3f0
7 changed files with 77 additions and 54 deletions

View File

@ -55,7 +55,7 @@ func (list SFileList) JSTmplInit() error {
}
path = strings.TrimPrefix(path, "tmpl_client/")
tmplName := strings.TrimSuffix(path, ".go")
tmplName := strings.TrimSuffix(path, ".jgo")
shortName := strings.TrimPrefix(tmplName, "template_")
var replace = func(data []byte, replaceThis string, withThis string) []byte {
@ -104,10 +104,6 @@ func (list SFileList) JSTmplInit() error {
}
return out + "]"
}*/
data = replace(data, `)
if !ok {
return errors.New("invalid page struct value")
}`, "*/tmpl_"+shortName+"_vars = tmpl_"+shortName+"_i")
// ? Can we just use a regex? I'm thinking of going more efficient, or just outright rolling wasm, this is a temp hack in a place where performance doesn't particularly matter
var each = func(phrase string, handle func(index int)) {

View File

@ -143,6 +143,7 @@ func (mfs *MemoryForumStore) rebuildView() {
})
sort.Sort(SortForum(forumView))
mfs.forumView.Store(forumView)
TopicListThaw.Thaw()
}
func (mfs *MemoryForumStore) DirtyGet(id int) *Forum {
@ -190,7 +191,7 @@ func (mfs *MemoryForumStore) BypassGet(id int) (*Forum, error) {
forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
TopicListThaw.Thaw()
//TopicListThaw.Thaw()
return forum, err
}
@ -219,7 +220,6 @@ func (mfs *MemoryForumStore) Reload(id int) error {
forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
mfs.CacheSet(forum)
TopicListThaw.Thaw()
return nil
}
@ -290,7 +290,6 @@ func (mfs *MemoryForumStore) Delete(id int) error {
}
_, err := mfs.delete.Exec(id)
mfs.CacheDelete(id)
TopicListThaw.Thaw()
return err
}

View File

@ -495,7 +495,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
if tname != "" {
tname = "_" + tname
}
err := writeFile(dirPrefix+"template_"+name+tname+".go", content)
err := writeFile(dirPrefix+"template_"+name+tname+".jgo", content)
if err != nil {
log.Fatal(err)
}

View File

@ -442,13 +442,13 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
fout += "}\n\n"
}
if c.lang == "normal" {
fout += "// nolint\nfunc Template_" + fname + "(tmpl_" + fname + "_i interface{}, w io.Writer) error {\n"
fout += `tmpl_` + fname + `_vars, ok := tmpl_` + fname + `_i.(` + expects + `)
if !ok {
return errors.New("invalid page struct value")
}
`
if c.lang == "normal" {
fout += `var iw http.ResponseWriter
gzw, ok := w.(common.GzipResponseWriter)
if ok {
@ -456,6 +456,8 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
}
_ = iw
`
} else {
fout += "// nolint\nfunc Template_" + fname + "(tmpl_" + fname + "_vars interface{}, w io.Writer) error {\n"
}
if len(c.langIndexToName) > 0 {

View File

@ -5,6 +5,9 @@ import (
//"log"
"bytes"
"errors"
"strings"
"strconv"
"time"
"sync/atomic"
"net/http"
"net/http/httptest"
@ -37,11 +40,14 @@ func deactivateHdrive(plugin *c.Plugin) {
type Hyperspace struct {
topicList atomic.Value
gzipTopicList atomic.Value
lastTopicListUpdate atomic.Value
}
func newHyperspace() *Hyperspace {
pageCache := new(Hyperspace)
pageCache.topicList.Store([]byte(""))
pageCache.gzipTopicList.Store([]byte(""))
pageCache.lastTopicListUpdate.Store(int64(0))
return pageCache
}
@ -86,6 +92,7 @@ func tickHdrive(args ...interface{}) (skip bool, rerr c.RouteError) {
return false, nil
}
hyperspace.gzipTopicList.Store(gbuf)
hyperspace.lastTopicListUpdate.Store(time.Now().Unix())
return false, nil
}
@ -128,12 +135,29 @@ func jumpHdrive(args ...interface{}) (skip bool, rerr c.RouteError) {
//c.DebugLog
c.DebugLog("Successful jump")
var etag string
lastUpdate := hyperspace.lastTopicListUpdate.Load().(int64)
c.DebugLog("lastUpdate:",lastUpdate)
if ok {
iw.Header().Set("X-I","1")
etag = "\""+strconv.FormatInt(lastUpdate, 10)+"-g\""
} else {
etag = "\""+strconv.FormatInt(lastUpdate, 10)+"\""
}
if lastUpdate != 0 {
iw.Header().Set("ETag", etag)
if match := r.Header.Get("If-None-Match"); match != "" {
if strings.Contains(match, etag) {
iw.WriteHeader(http.StatusNotModified)
return true, nil
}
}
}
header := args[3].(*c.Header)
routes.FootHeaders(w, header)
iw.Write(tList)
if ok {
w.Header().Set("X-I","1")
}
return true, nil
}

View File

@ -185,7 +185,7 @@ function initPhrases(loggedIn, panel = false) {
}
function fetchPhrases(plist) {
fetch("/api/phrases/?query="+plist)
fetch("/api/phrases/?query="+plist, {cache: "no-cache"})
.then((resp) => resp.json())
.then((data) => {
console.log("loaded phrase endpoint data");

View File

@ -191,24 +191,32 @@ func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
return c.PreErrorJS("You haven't requested any phrases", w, r)
}
var etag string
_, ok := w.(c.GzipResponseWriter)
if ok {
etag = "\""+strconv.FormatInt(c.StartTime.Unix(), 10)+"-g\""
} else {
etag = "\""+strconv.FormatInt(c.StartTime.Unix(), 10)+"\""
}
var plist map[string]string
// A little optimisation to avoid copying entries from one map to the other, if we don't have to mutate it
// TODO: Reduce the amount of duplication here
if len(positives) > 1 {
plist = make(map[string]string)
for _, positive := range positives {
var posLoop = func(positive string) c.RouteError {
// ! Constrain it to a subset of phrases for now
var ok = false
for _, item := range phraseWhitelist {
if strings.HasPrefix(positive, item) {
// TODO: Break this down into smaller security boundaries based on control panel sections?
if strings.HasPrefix(positive,"panel") {
if user.IsSuperMod {
ok = true
w.Header().Set("Cache-Control", "private")
}
ok = user.IsSuperMod
} else {
ok = true
w.Header().Set("ETag", etag)
if match := r.Header.Get("If-None-Match"); match != "" {
if strings.Contains(match, etag) {
w.WriteHeader(http.StatusNotModified)
return nil
}
}
}
break
}
@ -216,7 +224,17 @@ func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
if !ok {
return c.PreErrorJS("Outside of phrase prefix whitelist", w, r)
}
return nil
}
// A little optimisation to avoid copying entries from one map to the other, if we don't have to mutate it
if len(positives) > 1 {
plist = make(map[string]string)
for _, positive := range positives {
rerr := posLoop(positive)
if rerr != nil {
return rerr
}
pPhrases, ok := phrases.GetTmplPhrasesByPrefix(positive)
if !ok {
return c.PreErrorJS("No such prefix", w, r)
@ -226,26 +244,10 @@ func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user c.User) c.Rout
}
}
} else {
// ! Constrain it to a subset of phrases for now
var ok = false
for _, item := range phraseWhitelist {
if strings.HasPrefix(positives[0], item) {
// TODO: Break this down into smaller security boundaries based on control panel sections?
if strings.HasPrefix(positives[0],"panel") {
if user.IsSuperMod {
ok = true
w.Header().Set("Cache-Control", "private")
rerr := posLoop(positives[0])
if rerr != nil {
return rerr
}
} else {
ok = true
}
break
}
}
if !ok {
return c.PreErrorJS("Outside of phrase prefix whitelist", w, r)
}
pPhrases, ok := phrases.GetTmplPhrasesByPrefix(positives[0])
if !ok {
return c.PreErrorJS("No such prefix", w, r)