e50366ce60
Fixed a potential bug where Hyperdrive might cache already cached content. Skip jumpHdrive if requested via JavaScript for now. Export CompressBytesGzip so Hyperdrive can use it.
134 lines
3.1 KiB
Go
134 lines
3.1 KiB
Go
// Highly experimental plugin for caching rendered pages for guests
|
|
package main
|
|
|
|
import (
|
|
//"log"
|
|
"bytes"
|
|
"sync/atomic"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
|
|
c "github.com/Azareal/Gosora/common"
|
|
"github.com/Azareal/Gosora/routes"
|
|
)
|
|
|
|
var hyperspace *Hyperspace
|
|
|
|
func init() {
|
|
c.Plugins.Add(&c.Plugin{UName: "hyperdrive", Name: "Hyperdrive", Author: "Azareal", Init: initHdrive, Deactivate: deactivateHdrive})
|
|
}
|
|
|
|
func initHdrive(plugin *c.Plugin) error {
|
|
hyperspace = newHyperspace()
|
|
plugin.AddHook("tasks_tick_topic_list",tickHdrive)
|
|
plugin.AddHook("tasks_tick_widget_wol",tickHdriveWol)
|
|
plugin.AddHook("route_topic_list_start",jumpHdrive)
|
|
return nil
|
|
}
|
|
|
|
func deactivateHdrive(plugin *c.Plugin) {
|
|
plugin.RemoveHook("tasks_tick_topic_list",tickHdrive)
|
|
plugin.RemoveHook("tasks_tick_widget_wol",tickHdriveWol)
|
|
plugin.RemoveHook("route_topic_list_start",jumpHdrive)
|
|
hyperspace = nil
|
|
}
|
|
|
|
type Hyperspace struct {
|
|
topicList atomic.Value
|
|
gzipTopicList atomic.Value
|
|
}
|
|
|
|
func newHyperspace() *Hyperspace {
|
|
pageCache := new(Hyperspace)
|
|
pageCache.topicList.Store([]byte(""))
|
|
return pageCache
|
|
}
|
|
|
|
func tickHdriveWol(args ...interface{}) (skip bool, rerr c.RouteError) {
|
|
c.DebugLog("docking at wol")
|
|
return tickHdrive(args)
|
|
}
|
|
|
|
// TODO: Find a better way of doing this
|
|
func tickHdrive(args ...interface{}) (skip bool, rerr c.RouteError) {
|
|
c.DebugLog("Refueling...")
|
|
|
|
// Avoid accidentally caching already cached content
|
|
hyperspace.topicList.Store([]byte(""))
|
|
hyperspace.gzipTopicList.Store([]byte(""))
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("get", "/topics/", bytes.NewReader(nil))
|
|
user := c.GuestUser
|
|
|
|
head, rerr := c.UserCheck(w, req, &user)
|
|
if rerr != nil {
|
|
return true, rerr
|
|
}
|
|
|
|
rerr = routes.TopicList(w, req, user, head)
|
|
if rerr != nil {
|
|
return true, rerr
|
|
}
|
|
if w.Code != 200 {
|
|
c.LogWarning(errors.New("not 200 for topic list in hyperdrive"))
|
|
return false, nil
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
buf.ReadFrom(w.Result().Body)
|
|
hyperspace.topicList.Store(buf.Bytes())
|
|
|
|
gbuf, err := c.CompressBytesGzip(buf.Bytes())
|
|
if err != nil {
|
|
c.LogWarning(err)
|
|
return false, nil
|
|
}
|
|
hyperspace.gzipTopicList.Store(gbuf)
|
|
|
|
return false, nil
|
|
}
|
|
|
|
func jumpHdrive(args ...interface{}) (skip bool, rerr c.RouteError) {
|
|
var tList []byte
|
|
w := args[0].(http.ResponseWriter)
|
|
_, ok := w.(c.GzipResponseWriter)
|
|
if ok {
|
|
tList = hyperspace.gzipTopicList.Load().([]byte)
|
|
} else {
|
|
tList = hyperspace.topicList.Load().([]byte)
|
|
}
|
|
if len(tList) == 0 {
|
|
c.DebugLog("no topiclist in hyperspace")
|
|
return false, nil
|
|
}
|
|
|
|
// Avoid intercepting user requests as we only have guests in cache right now
|
|
user := args[2].(*c.User)
|
|
if user.ID != 0 {
|
|
c.DebugLog("not guest")
|
|
return false, nil
|
|
}
|
|
|
|
// Avoid intercepting search requests and filters as we don't have those in cache
|
|
r := args[1].(*http.Request)
|
|
//c.DebugLog("r.URL.Path:",r.URL.Path)
|
|
//c.DebugLog("r.URL.RawQuery:",r.URL.RawQuery)
|
|
if r.URL.RawQuery != "" {
|
|
return false, nil
|
|
}
|
|
if r.FormValue("js") == "1" {
|
|
return false, nil
|
|
}
|
|
//c.DebugLog
|
|
c.DebugLog("Successful jump")
|
|
|
|
header := args[3].(*c.Header)
|
|
routes.FootHeaders(w, header)
|
|
w.Write(tList)
|
|
if ok {
|
|
w.Header().Set("X-I","1")
|
|
}
|
|
|
|
return true, nil
|
|
} |