Skip to content

Commit

Permalink
Experimenting with Nox's Control Panel.
Browse files Browse the repository at this point in the history
Experimenting with better cache busting for static resources.
HTTPSRedirect requests are now counted in the route analytics.
More scripts are loaded asynchronously now.
Upped the default ReadTimeout to eight seconds.
Reduce the number of unneccesary NewAcc calls.
Added panel_before_head as an injection point for themes.
Themes can now declare scripts to be loaded asynchronously.
Tweaked the WS resumption algorithm to mae the backoffs a little less aggressive.
Fixed an ordering issue in the WS resumption algorithm where backoffs weren't expiring as fast as they should have.
Fixed a bug where template logs weren't being written due to a panic.
You can now use byte slices in more places in the transpiled templates.
Fixed a bug where Cosora's misc.js seemed to be erroring out.
Fixed a bug where YT embeds were getting blocked by the CSP.

Added the panel_back_to_site phrase.
Added the panel_welcome phrase.
  • Loading branch information
Azareal committed Mar 21, 2019
1 parent 3320cb4 commit 660f24a
Show file tree
Hide file tree
Showing 74 changed files with 369 additions and 195 deletions.
7 changes: 3 additions & 4 deletions common/counters/langs.go
Expand Up @@ -96,12 +96,11 @@ var langCodes = []string{
type DefaultLangViewCounter struct {
buckets []*RWMutexCounterBucket //[OSID]count
codesToIndices map[string]int
insert *sql.Stmt
}

func NewDefaultLangViewCounter() (*DefaultLangViewCounter, error) {
acc := qgen.NewAcc()
insert *sql.Stmt
}

func NewDefaultLangViewCounter(acc *qgen.Accumulator) (*DefaultLangViewCounter, error) {
var langBuckets = make([]*RWMutexCounterBucket, len(langCodes))
for bucketID, _ := range langBuckets {
langBuckets[bucketID] = &RWMutexCounterBucket{counter: 0}
Expand Down
3 changes: 1 addition & 2 deletions common/counters/routes.go
Expand Up @@ -12,8 +12,7 @@ type DefaultRouteViewCounter struct {
insert *sql.Stmt
}

func NewDefaultRouteViewCounter() (*DefaultRouteViewCounter, error) {
acc := qgen.NewAcc()
func NewDefaultRouteViewCounter(acc *qgen.Accumulator) (*DefaultRouteViewCounter, error) {
var routeBuckets = make([]*RWMutexCounterBucket, len(routeMapEnum))
for bucketID, _ := range routeBuckets {
routeBuckets[bucketID] = &RWMutexCounterBucket{counter: 0}
Expand Down
3 changes: 1 addition & 2 deletions common/counters/systems.go
Expand Up @@ -14,8 +14,7 @@ type DefaultOSViewCounter struct {
insert *sql.Stmt
}

func NewDefaultOSViewCounter() (*DefaultOSViewCounter, error) {
acc := qgen.NewAcc()
func NewDefaultOSViewCounter(acc *qgen.Accumulator) (*DefaultOSViewCounter, error) {
var osBuckets = make([]*RWMutexCounterBucket, len(osMapEnum))
for bucketID, _ := range osBuckets {
osBuckets[bucketID] = &RWMutexCounterBucket{counter: 0}
Expand Down
8 changes: 4 additions & 4 deletions common/files.go
Expand Up @@ -27,7 +27,7 @@ var staticFileMutex sync.RWMutex
type SFile struct {
Data []byte
GzipData []byte
Sha256 []byte
Sha256 string
Pos int64
Length int64
GzipLength int64
Expand Down Expand Up @@ -240,7 +240,7 @@ func (list SFileList) JSTmplInit() error {
// Get a checksum for CSPs and cache busting
hasher := sha256.New()
hasher.Write(data)
checksum := []byte(hex.EncodeToString(hasher.Sum(nil)))
checksum := hex.EncodeToString(hasher.Sum(nil))

list.Set("/static/"+path, SFile{data, gzipData, checksum, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})

Expand All @@ -267,7 +267,7 @@ func (list SFileList) Init() error {
// Get a checksum for CSPs and cache busting
hasher := sha256.New()
hasher.Write(data)
checksum := []byte(hex.EncodeToString(hasher.Sum(nil)))
checksum := hex.EncodeToString(hasher.Sum(nil))

// Avoid double-compressing images
var gzipData []byte
Expand Down Expand Up @@ -318,7 +318,7 @@ func (list SFileList) Add(path string, prefix string) error {
// Get a checksum for CSPs and cache busting
hasher := sha256.New()
hasher.Write(data)
checksum := []byte(hex.EncodeToString(hasher.Sum(nil)))
checksum := hex.EncodeToString(hasher.Sum(nil))

list.Set("/static"+path, SFile{data, gzipData, checksum, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})

Expand Down
44 changes: 40 additions & 4 deletions common/pages.go
Expand Up @@ -10,14 +10,20 @@ import (
"github.com/Azareal/Gosora/common/phrases"
)

type HResource struct {
Name string
Hash string
}

// TODO: Allow resources in spots other than /static/ and possibly even external domains (e.g. CDNs)
// TODO: Preload Trumboyg on Cosora on the forum list
type Header struct {
Title string
//Title []byte // Experimenting with []byte for increased efficiency, let's avoid converting too many things to []byte, as it involves a lot of extra boilerplate
NoticeList []string
Scripts []string
PreScriptsAsync []string
Scripts []HResource
PreScriptsAsync []HResource
ScriptsAsync []HResource
//Preload []string
Stylesheets []string
Widgets PageWidgets
Expand All @@ -44,11 +50,41 @@ type Header struct {
}

func (header *Header) AddScript(name string) {
header.Scripts = append(header.Scripts, name)
fname := "/static/" + name
var hash string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
}
}
//log.Print("name:", name)
//log.Print("hash:", hash)
header.Scripts = append(header.Scripts, HResource{name, hash})
}

func (header *Header) AddPreScriptAsync(name string) {
header.PreScriptsAsync = append(header.PreScriptsAsync, name)
fname := "/static/" + name
var hash string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
}
}
header.PreScriptsAsync = append(header.PreScriptsAsync, HResource{name, hash})
}

func (header *Header) AddScriptAsync(name string) {
fname := "/static/" + name
var hash string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
}
}
header.ScriptsAsync = append(header.ScriptsAsync, HResource{name, hash})
}

/*func (header *Header) Preload(name string) {
Expand Down
12 changes: 10 additions & 2 deletions common/routes_common.go
Expand Up @@ -131,7 +131,11 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
if ext == "css" {
header.AddSheet(resource.Name)
} else if ext == "js" {
header.AddScript(resource.Name)
if resource.Async {
header.AddScriptAsync(resource.Name)
} else {
header.AddScript(resource.Name)
}
}
}
}
Expand Down Expand Up @@ -229,7 +233,11 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head
if ext == "css" {
header.AddSheet(resource.Name)
} else if ext == "js" {
header.AddScript(resource.Name)
if resource.Async {
header.AddScriptAsync(resource.Name)
} else {
header.AddScript(resource.Name)
}
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions common/template_init.go
Expand Up @@ -109,8 +109,9 @@ func tmplInitHeaders(user User, user2 User, user3 User) (*Header, *Header, *Head
CurrentUser: user,
NoticeList: []string{"test"},
Stylesheets: []string{"panel.css"},
Scripts: []string{"whatever.js"},
PreScriptsAsync: []string{"whatever.js"},
Scripts: []HResource{HResource{"whatever.js", "d"}},
PreScriptsAsync: []HResource{HResource{"whatever.js", "d"}},
ScriptsAsync: []HResource{HResource{"whatever.js", "d"}},
Widgets: PageWidgets{
LeftSidebar: template.HTML("lalala"),
},
Expand Down
32 changes: 30 additions & 2 deletions common/templates/templates.go
Expand Up @@ -2,11 +2,13 @@ package tmpl

import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"reflect"
"runtime/debug"
"strconv"
"strings"
"text/template/parse"
Expand Down Expand Up @@ -70,7 +72,8 @@ type CTemplateSet struct {
themeName string
perThemeTmpls map[string]bool

logger *log.Logger
logger *log.Logger
loggerf *os.File
}

func NewCTemplateSet(in string) *CTemplateSet {
Expand Down Expand Up @@ -110,7 +113,8 @@ func NewCTemplateSet(in string) *CTemplateSet {
"dyntmpl": true,
"index": true,
},
logger: log.New(f, "", log.LstdFlags),
logger: log.New(f, "", log.LstdFlags),
loggerf: f,
}
}

Expand Down Expand Up @@ -155,6 +159,7 @@ func (c *CTemplateSet) ResetLogs(in string) {
panic(err)
}
c.logger = log.New(f, "", log.LstdFlags)
c.loggerf = f
}

type SkipBlock struct {
Expand Down Expand Up @@ -268,6 +273,19 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
}

func (c *CTemplateSet) compile(name string, content string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
defer func() {
r := recover()
if r != nil {
fmt.Println(r)
debug.PrintStack()
err := c.loggerf.Sync()
if err != nil {
fmt.Println(err)
}
log.Fatal("")
return
}
}()
//c.dumpCall("compile", name, content, expects, expectsInt, varList, imports)
//c.detailf("c: %+v\n", c)
c.importMap = map[string]string{}
Expand Down Expand Up @@ -1460,6 +1478,16 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
c.addText(con, []byte("false"))
con.Push("endelse", "}\n")
return
case reflect.Slice:
if val.Len() == 0 {
c.critical("varname:", varname)
panic("The sample data needs at-least one or more elements for the slices. We're looking into removing this requirement at some point!")
}
item := val.Index(0)
if item.Type().Name() != "uint8" { // uint8 == byte, complicated because it's a type alias
panic("unable to format " + item.Type().Name() + " as text")
}
base = varname
case reflect.String:
if val.Type().Name() != "string" && !strings.HasPrefix(varname, "string(") {
varname = "string(" + varname + ")"
Expand Down
3 changes: 2 additions & 1 deletion common/theme.go
Expand Up @@ -77,6 +77,7 @@ type ThemeResource struct {
Name string
Location string
Loggedin bool // Only serve this resource to logged in users
Async bool
}

type ThemeMapTmplToDock struct {
Expand Down Expand Up @@ -162,7 +163,7 @@ func (theme *Theme) AddThemeStaticFiles() error {
// Get a checksum for CSPs and cache busting
hasher := sha256.New()
hasher.Write(data)
checksum := []byte(hex.EncodeToString(hasher.Sum(nil)))
checksum := hex.EncodeToString(hasher.Sum(nil))

StaticFiles.Set("/static/"+theme.Name+path, SFile{data, gzipData, checksum, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})

Expand Down
6 changes: 6 additions & 0 deletions common/websockets.go
Expand Up @@ -92,6 +92,12 @@ func RouteWebsockets(w http.ResponseWriter, r *http.Request, user User) RouteErr
currentPage = string(msgblocks[1])
wsPageResponses(wsUser, conn, currentPage)
}
} else if bytes.HasPrefix(msg, []byte("resume ")) {
msgblocks := bytes.SplitN(msg, []byte(" "), 2)
if len(msgblocks) < 2 {
continue
}
//log.Print("resuming on " + string(msgblocks[1]))
}
/*if bytes.Equal(message,[]byte(`start-view`)) {
} else if bytes.Equal(message,[]byte(`end-view`)) {
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration.md
Expand Up @@ -84,7 +84,7 @@ MaxTopicTitleLength - The maximum length that a topic can be. Please note that t

MaxUsernameLength - The maximum length that a user's name can be. Please note that this measures the number of bytes and may differ from language to language with it being equal to a letter in English and being two bytes in others.

ReadTimeout - The number of seconds that we are allowed to take to fully read a request. Defaults to 5.
ReadTimeout - The number of seconds that we are allowed to take to fully read a request. Defaults to 8.

WriteTimeout - The number of seconds that a route is allowed to run for before the request is automatically terminated. Defaults to 10.

Expand Down
14 changes: 14 additions & 0 deletions gen_router.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions langs/english.json
Expand Up @@ -708,6 +708,8 @@
"option_yes":"Yes",
"option_no":"No",

"panel_back_to_site":"Back to Site",
"panel_welcome":"Welcome ",
"panel_menu_head":"Control Panel",
"panel_menu_aria":"The control panel menu",
"panel_menu_users":"Users",
Expand Down
11 changes: 5 additions & 6 deletions main.go
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/Azareal/Gosora/common/counters"
"github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen"
"github.com/Azareal/Gosora/routes"
"github.com/fsnotify/fsnotify"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -181,15 +180,15 @@ func afterDBInit() (err error) {
if err != nil {
return errors.WithStack(err)
}
counters.OSViewCounter, err = counters.NewDefaultOSViewCounter()
counters.OSViewCounter, err = counters.NewDefaultOSViewCounter(acc)
if err != nil {
return errors.WithStack(err)
}
counters.LangViewCounter, err = counters.NewDefaultLangViewCounter()
counters.LangViewCounter, err = counters.NewDefaultLangViewCounter(acc)
if err != nil {
return errors.WithStack(err)
}
counters.RouteViewCounter, err = counters.NewDefaultRouteViewCounter()
counters.RouteViewCounter, err = counters.NewDefaultRouteViewCounter(acc)
if err != nil {
return errors.WithStack(err)
}
Expand Down Expand Up @@ -472,7 +471,7 @@ func startServer() {
var newServer = func(addr string, handler http.Handler) *http.Server {
rtime := common.Config.ReadTimeout
if rtime == 0 {
rtime = 5
rtime = 8
} else if rtime == -1 {
rtime = 0
}
Expand Down Expand Up @@ -527,7 +526,7 @@ func startServer() {
// TODO: Redirect to port 443
go func() {
log.Print("Listening on port 80")
common.StoppedServer(newServer(":80", &routes.HTTPSRedirect{}).ListenAndServe())
common.StoppedServer(newServer(":80", &HTTPSRedirect{}).ListenAndServe())
}()
}
log.Printf("Listening on port %s", common.Site.Port)
Expand Down

0 comments on commit 660f24a

Please sign in to comment.