Initial work on Plugin Hyperdrive.

Reduced the amount of boilerplate in Plugin Markdown.
Reduced the amount of boilerplate in Plugin Sendmail.
Reduced the amount of boilerplate in sample plugins Heythere and Skeleton.
Fixed up Plugin GeoIP. It's not ready for use though.

Added the routes.FootHeaders function.

Added the route_topic_list_start plugin hook.
This commit is contained in:
Azareal 2019-04-20 14:55:22 +10:00
parent 114afe0b13
commit b4ffaa2cd6
9 changed files with 131 additions and 52 deletions

View File

@ -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,

View File

@ -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()
}

View File

@ -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
}

View File

@ -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"

View File

@ -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"

View File

@ -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("<red>[Unclosed Element]</red>")
@ -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) {

View File

@ -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) {}

View File

@ -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()
}

View File

@ -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)