gosora/experimental/plugin_hyperdrive.go

138 lines
3.2 KiB
Go
Raw Normal View History

// 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)
}
func dummyReqHdrive() http.ResponseWriter {
req := httptest.NewRequest("get", "/topics/", bytes.NewReader(nil))
user := c.GuestUser
head, err := c.UserCheck(w, req, &user)
if err != nil {
c.LogWarning(err)
return true, rerr
}
rerr = routes.TopicList(w, req, user, head)
if rerr != nil {
c.LogWarning(err)
return true, rerr
}
if w.Code != 200 {
c.LogWarning(err)
return false, nil
}
return w
}
// TODO: Find a better way of doing this
func tickHdrive(args ...interface{}) (skip bool, rerr c.RouteError) {
c.DebugLog("Refueling...")
w := httptest.NewRecorder()
dummyReqHdrive(w)
buf := new(bytes.Buffer)
buf.ReadFrom(w.Result().Body)
hyperspace.topicList.Store(buf.Bytes())
w = httptest.NewRecorder()
w.Header().Set("Content-Encoding", "gzip")
w.Header().Set("Content-Type", "text/html; charset=utf-8")
gz := gzip.NewWriter(w)
w = c.GzipResponseWriter{Writer: gz, ResponseWriter: w}
dummyReqHdrive(w)
buf = new(bytes.Buffer)
buf.ReadFrom(w.Result().Body)
hyperspace.gzipTopicList.Store(buf.Bytes())
if w.Header().Get("Content-Encoding") == "gzip" {
gz.Close()
}
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
}
//c.DebugLog
c.DebugLog("Successful jump")
header := args[3].(*c.Header)
routes.FootHeaders(w, header)
w.Write(tList)
return true, nil
}