diff --git a/common/extend.go b/common/extend.go index 64bc83a2..c9855cfe 100644 --- a/common/extend.go +++ b/common/extend.go @@ -83,6 +83,8 @@ var hookTable = &HookTable{ "simple_forum_check_pre_perms": nil, "forum_check_pre_perms": nil, + "route_topic_list_start": nil, + "action_end_create_topic": nil, "action_end_edit_topic":nil, "action_end_delete_topic":nil, diff --git a/experimental/plugin_geoip.go b/experimental/plugin_geoip.go index 6531df7f..cda437c4 100644 --- a/experimental/plugin_geoip.go +++ b/experimental/plugin_geoip.go @@ -1,19 +1,20 @@ package main +import c "github.com/Azareal/Gosora/common" import "github.com/oschwald/geoip2-golang" -var geoip_db *geoip.DB -var geoip_db_location string = "geoip_db.mmdb" +var geoipDB *geoip.DB +var geoipDBLocation = "geoip_db.mmdb" func init() { - plugins["geoip"] = NewPlugin("geoip","Geoip","Azareal","http://github.com/Azareal","","","",init_geoip,nil,deactivate_geoip,nil,nil) + c.Plugins.Add(&c.Plugin{UName: "geoip", Name: "Geoip", Author: "Azareal", Init: initGeoip, Deactivate: deactivateGeoip}) } -func init_geoip() (err error) { - geoip_db, err = geoip2.Open(geoip_db_location) +func initGeoip(plugin *c.Plugin) (err error) { + geoipDB, err = geoip2.Open(geoipDBLocation) return err } -func deactivate_geoip() { - geoip_db.Close() +func deactivateGeoip(plugin *c.Plugin) { + geoipDB.Close() } diff --git a/experimental/plugin_hyperdrive.go b/experimental/plugin_hyperdrive.go index 07ed50bd..eb770f87 100644 --- a/experimental/plugin_hyperdrive.go +++ b/experimental/plugin_hyperdrive.go @@ -2,33 +2,101 @@ package main import ( + "log" + "bytes" "sync/atomic" + "net/http" + "net/http/httptest" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" + "github.com/Azareal/Gosora/routes" ) -var hyperPageCache *HyperPageCache +var hyperspace *Hyperspace func init() { - common.Plugins.Add(&common.Plugin{UName: "hyperdrive", Name: "Hyperdrive", Author: "Azareal", Init: initHyperdrive, Deactivate: deactivateHyperdrive}) + c.Plugins.Add(&c.Plugin{UName: "hyperdrive", Name: "Hyperdrive", Author: "Azareal", Init: initHdrive, Deactivate: deactivateHdrive}) } -func initHyperdrive(plugin *common.Plugin) error { - hyperPageCache = newHyperPageCache() - plugin.AddHook("somewhere", deactivateHyperdrive) +func initHdrive(plugin *c.Plugin) error { + hyperspace = newHyperspace() + plugin.AddHook("tasks_tick_topic_list",tickHdrive) + plugin.AddHook("route_topic_list_start",jumpHdrive) return nil } -func deactivateHyperdrive(plugin *common.Plugin) { - hyperPageCache = nil +func deactivateHdrive(plugin *c.Plugin) { + plugin.RemoveHook("tasks_tick_topic_list",tickHdrive) + plugin.RemoveHook("route_topic_list_start",jumpHdrive) + hyperspace = nil } -type HyperPageCache struct { +type Hyperspace struct { topicList atomic.Value } -func newHyperPageCache() *HyperPageCache { - pageCache := new(HyperPageCache) +func newHyperspace() *Hyperspace { + pageCache := new(Hyperspace) pageCache.topicList.Store([]byte("")) return pageCache } + +// TODO: Find a better way of doing this +func tickHdrive(args ...interface{}) (skip bool, rerr c.RouteError) { + log.Print("Refueling...") + w := httptest.NewRecorder() + 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) + } + + buf := new(bytes.Buffer) + buf.ReadFrom(w.Result().Body) + hyperspace.topicList.Store(buf.Bytes()) + + return false, nil +} + +func jumpHdrive(args ...interface{}) (skip bool, rerr c.RouteError) { + tList := hyperspace.topicList.Load().([]byte) + if len(tList) == 0 { + log.Print("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 { + log.Print("not guest") + return false, nil + } + + // Avoid intercepting search requests and filters as we don't have those in cache + r := args[1].(*http.Request) + //log.Print("r.URL.Path:",r.URL.Path) + log.Print("r.URL.RawQuery:",r.URL.RawQuery) + if r.URL.RawQuery != "" { + return false, nil + } + log.Print("Successful jump") + + w := args[0].(http.ResponseWriter) + header := args[3].(*c.Header) + routes.FootHeaders(w, header) + w.Write(tList) + + return true, nil +} \ No newline at end of file diff --git a/experimental/plugin_sendmail.go b/experimental/plugin_sendmail.go index 84248744..6538099a 100644 --- a/experimental/plugin_sendmail.go +++ b/experimental/plugin_sendmail.go @@ -6,7 +6,7 @@ import ( "os/exec" "runtime" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" ) /* @@ -18,17 +18,17 @@ func init() { if runtime.GOOS != "linux" { return } - common.Plugins.Add(&common.Plugin{UName: "sendmail", Name: "Sendmail", Author: "Azareal", URL: "http://github.com/Azareal", Tag: "Linux Only", Init: initSendmail, Activate: activateSendmail, Deactivate: deactivateSendmail}) + c.Plugins.Add(&c.Plugin{UName: "sendmail", Name: "Sendmail", Author: "Azareal", URL: "http://github.com/Azareal", Tag: "Linux Only", Init: initSendmail, Activate: activateSendmail, Deactivate: deactivateSendmail}) } -func initSendmail(plugin *common.Plugin) error { +func initSendmail(plugin *c.Plugin) error { plugin.AddHook("email_send_intercept", sendSendmail) return nil } // /usr/sbin/sendmail is only available on Linux -func activateSendmail(plugin *common.Plugin) error { - if !common.Site.EnableEmails { +func activateSendmail(plugin *c.Plugin) error { + if !c.Site.EnableEmails { return errors.New("You have emails disabled in your configuration file") } if runtime.GOOS != "linux" { @@ -37,7 +37,7 @@ func activateSendmail(plugin *common.Plugin) error { return nil } -func deactivateSendmail(plugin *common.Plugin) { +func deactivateSendmail(plugin *c.Plugin) { plugin.RemoveHook("email_send_intercept", sendSendmail) } @@ -46,7 +46,7 @@ func sendSendmail(data ...interface{}) interface{} { subject := data[1].(string) body := data[2].(string) - msg := "From: " + common.Site.Email + "\n" + msg := "From: " + c.Site.Email + "\n" msg += "To: " + to + "\n" msg += "Subject: " + subject + "\n\n" msg += body + "\n" diff --git a/plugin_heythere.go b/plugin_heythere.go index 80c26c7e..c9f75c68 100644 --- a/plugin_heythere.go +++ b/plugin_heythere.go @@ -1,24 +1,24 @@ package main -import "github.com/Azareal/Gosora/common" +import c "github.com/Azareal/Gosora/common" func init() { - common.Plugins.Add(&common.Plugin{UName: "heythere", Name: "Hey There", Author: "Azareal", URL: "https://github.com/Azareal", Init: initHeythere, Deactivate: deactivateHeythere}) + c.Plugins.Add(&c.Plugin{UName: "heythere", Name: "Hey There", Author: "Azareal", URL: "https://github.com/Azareal", Init: initHeythere, Deactivate: deactivateHeythere}) } // init_heythere is separate from init() as we don't want the plugin to run if the plugin is disabled -func initHeythere(plugin *common.Plugin) error { +func initHeythere(plugin *c.Plugin) error { plugin.AddHook("topic_reply_row_assign", heythereReply) return nil } -func deactivateHeythere(plugin *common.Plugin) { +func deactivateHeythere(plugin *c.Plugin) { plugin.RemoveHook("topic_reply_row_assign", heythereReply) } func heythereReply(data ...interface{}) interface{} { - currentUser := data[0].(*common.TopicPage).Header.CurrentUser - reply := data[1].(*common.ReplyUser) + currentUser := data[0].(*c.TopicPage).Header.CurrentUser + reply := data[1].(*c.ReplyUser) reply.Content = "Hey there, " + currentUser.Name + "!" reply.ContentHtml = "Hey there, " + currentUser.Name + "!" reply.Tag = "Auto" diff --git a/plugin_markdown.go b/plugin_markdown.go index fe4c1d84..eef85d6f 100644 --- a/plugin_markdown.go +++ b/plugin_markdown.go @@ -3,7 +3,7 @@ package main import ( "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" ) var markdownMaxDepth = 25 // How deep the parser will go when parsing Markdown strings @@ -23,10 +23,10 @@ var markdownH1TagOpen []byte var markdownH1TagClose []byte func init() { - common.Plugins.Add(&common.Plugin{UName: "markdown", Name: "Markdown", Author: "Azareal", URL: "https://github.com/Azareal", Init: initMarkdown, Deactivate: deactivateMarkdown}) + c.Plugins.Add(&c.Plugin{UName: "markdown", Name: "Markdown", Author: "Azareal", URL: "https://github.com/Azareal", Init: initMarkdown, Deactivate: deactivateMarkdown}) } -func initMarkdown(plugin *common.Plugin) error { +func initMarkdown(plugin *c.Plugin) error { plugin.AddHook("parse_assign", markdownParse) markdownUnclosedElement = []byte("[Unclosed Element]") @@ -46,7 +46,7 @@ func initMarkdown(plugin *common.Plugin) error { return nil } -func deactivateMarkdown(plugin *common.Plugin) { +func deactivateMarkdown(plugin *c.Plugin) { plugin.RemoveHook("parse_assign", markdownParse) } @@ -69,7 +69,7 @@ func _markdownParse(msg string, n int) string { var outbytes []byte var lastElement int var breaking = false - common.DebugLogf("Initial Message: %+v\n", strings.Replace(msg, "\r", "\\r", -1)) + c.DebugLogf("Initial Message: %+v\n", strings.Replace(msg, "\r", "\\r", -1)) for index := 0; index < len(msg); index++ { var simpleMatch = func(char byte, o []byte, c []byte) { diff --git a/plugin_skeleton.go b/plugin_skeleton.go index 88c1560b..191465fc 100644 --- a/plugin_skeleton.go +++ b/plugin_skeleton.go @@ -1,6 +1,6 @@ package main -import "github.com/Azareal/Gosora/common" +import c "github.com/Azareal/Gosora/common" func init() { /* @@ -28,12 +28,12 @@ func init() { That Uninstallation field which is currently unused is for not only deactivating this plugin, but for purging any data associated with it such a new tables or data produced by the end-user. */ - common.Plugins.Add(&common.Plugin{UName: "skeleton", Name: "Skeleton", Author: "Azareal", Init: initSkeleton, Activate: activateSkeleton, Deactivate: deactivateSkeleton}) + c.Plugins.Add(&c.Plugin{UName: "skeleton", Name: "Skeleton", Author: "Azareal", Init: initSkeleton, Activate: activateSkeleton, Deactivate: deactivateSkeleton}) } -func initSkeleton(plugin *common.Plugin) error { return nil } +func initSkeleton(plugin *c.Plugin) error { return nil } // Any errors encountered while trying to activate the plugin are reported back to the admin and the activation is aborted -func activateSkeleton(plugin *common.Plugin) error { return nil } +func activateSkeleton(plugin *c.Plugin) error { return nil } -func deactivateSkeleton(plugin *common.Plugin) {} +func deactivateSkeleton(plugin *c.Plugin) {} diff --git a/routes/common.go b/routes/common.go index 707bf527..b171d3de 100644 --- a/routes/common.go +++ b/routes/common.go @@ -70,6 +70,7 @@ func doPush(w http.ResponseWriter, header *c.Header) { var push = func(in []string) { for _, path := range in { //fmt.Println("pushing /static/" + path) + // TODO: Avoid concatenating here err := pusher.Push("/static/"+path, nil) if err != nil { break @@ -96,20 +97,11 @@ func renderTemplate2(tmplName string, hookName string, w http.ResponseWriter, r return nil } -func renderTemplate3(tmplName string, hookName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) error { - c.PrepResources(&header.CurrentUser, header, header.Theme) - - if header.CurrentUser.Loggedin { - header.MetaDesc = "" - header.OGDesc = "" - } else if header.MetaDesc != "" && header.OGDesc == "" { - header.OGDesc = header.MetaDesc - } +func FootHeaders(w http.ResponseWriter, header *c.Header) { // TODO: Expand this to non-HTTPS requests too if !header.LooseCSP && c.Site.EnableSsl { w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com;upgrade-insecure-requests") } - header.AddScript("global.js") // Server pushes can backfire on certain browsers, so we want to make sure it's only triggered for ones where it'll help lastAgent := header.CurrentUser.LastAgent @@ -117,7 +109,19 @@ func renderTemplate3(tmplName string, hookName string, w http.ResponseWriter, r if lastAgent == "chrome" || lastAgent == "firefox" { doPush(w, header) } +} +func renderTemplate3(tmplName string, hookName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) error { + c.PrepResources(&header.CurrentUser, header, header.Theme) + if header.CurrentUser.Loggedin { + header.MetaDesc = "" + header.OGDesc = "" + } else if header.MetaDesc != "" && header.OGDesc == "" { + header.OGDesc = header.MetaDesc + } + header.AddScript("global.js") + + FootHeaders(w, header) if header.CurrentUser.IsAdmin { header.Elapsed1 = time.Since(header.StartedAt).String() } diff --git a/routes/topic_list.go b/routes/topic_list.go index a934530c..74672769 100644 --- a/routes/topic_list.go +++ b/routes/topic_list.go @@ -20,6 +20,10 @@ func wsTopicList(topicList []*c.TopicsRow, lastPage int) *c.WsTopicList { } func TopicList(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { + skip, rerr := header.Hooks.VhookSkippable("route_topic_list_start", w, r, &user, header) + if skip || rerr != nil { + return rerr + } return TopicListCommon(w, r, user, header, "lastupdated", "") } @@ -106,7 +110,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user c.User, header if err != nil && err != sql.ErrNoRows { return c.InternalError(err, w, r) } - //fmt.Printf("tids %+v\n", tids) + //log.Printf("tids %+v\n", tids) // TODO: Handle the case where there aren't any items... // TODO: Add a BulkGet method which returns a slice? tMap, err := c.Topics.BulkGetMap(tids)