Greatly reduced the number of w.Write calls in the generated templates.
The topic list should only be rebuilt for a short window after something related to it changes on single server setups. Swapped out the RebuildGroupPermissions call in UpdatePerms with a more general and versable Groups.Reload call. The template generator now use log instead of fmt for writing debug logs.
This commit is contained in:
parent
f508ef9898
commit
1aac6f1268
|
@ -155,6 +155,7 @@ func (fps *MemoryForumPermsStore) Reload(fid int) error {
|
||||||
}
|
}
|
||||||
DebugDetailf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee)
|
DebugDetailf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee)
|
||||||
}
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ func (mfs *MemoryForumStore) LoadForums() error {
|
||||||
addForum(forum)
|
addForum(forum)
|
||||||
}
|
}
|
||||||
mfs.forumView.Store(forumView)
|
mfs.forumView.Store(forumView)
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return rows.Err()
|
return rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +186,7 @@ func (mfs *MemoryForumStore) BypassGet(id int) (*Forum, error) {
|
||||||
forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
|
forum.Link = BuildForumURL(NameToSlug(forum.Name), forum.ID)
|
||||||
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
|
forum.LastTopic = Topics.DirtyGet(forum.LastTopicID)
|
||||||
forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
|
forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
|
||||||
|
TopicListThaw.Thaw()
|
||||||
|
|
||||||
return forum, err
|
return forum, err
|
||||||
}
|
}
|
||||||
|
@ -213,6 +215,7 @@ func (mfs *MemoryForumStore) Reload(id int) error {
|
||||||
forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
|
forum.LastReplyer = Users.DirtyGet(forum.LastReplyerID)
|
||||||
|
|
||||||
mfs.CacheSet(forum)
|
mfs.CacheSet(forum)
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +286,7 @@ func (mfs *MemoryForumStore) Delete(id int) error {
|
||||||
}
|
}
|
||||||
_, err := mfs.delete.Exec(id)
|
_, err := mfs.delete.Exec(id)
|
||||||
mfs.CacheDelete(id)
|
mfs.CacheDelete(id)
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,6 @@ func (group *Group) ChangeRank(isAdmin bool, isMod bool, isBanned bool) (err err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
Groups.Reload(group.ID)
|
Groups.Reload(group.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +67,6 @@ func (group *Group) Update(name string, tag string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
Groups.Reload(group.ID)
|
Groups.Reload(group.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -83,7 +81,7 @@ func (group *Group) UpdatePerms(perms map[string]bool) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return RebuildGroupPermissions(group.ID)
|
return Groups.Reload(group.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy gives you a non-pointer concurrency safe copy of the group
|
// Copy gives you a non-pointer concurrency safe copy of the group
|
||||||
|
|
|
@ -90,6 +90,7 @@ func (mgs *MemoryGroupStore) LoadGroups() error {
|
||||||
|
|
||||||
DebugLog("Binding the Not Loggedin Group")
|
DebugLog("Binding the Not Loggedin Group")
|
||||||
GuestPerms = mgs.dirtyGetUnsafe(6).Perms
|
GuestPerms = mgs.dirtyGetUnsafe(6).Perms
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +153,7 @@ func (mgs *MemoryGroupStore) Reload(id int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +282,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
|
||||||
mgs.groupCount++
|
mgs.groupCount++
|
||||||
mgs.Unlock()
|
mgs.Unlock()
|
||||||
|
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return gid, FPStore.ReloadAll()
|
return gid, FPStore.ReloadAll()
|
||||||
//return gid, TopicList.RebuildPermTree()
|
//return gid, TopicList.RebuildPermTree()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
package tmpl
|
package tmpl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Fragment struct {
|
||||||
|
Body string
|
||||||
|
TemplateName string
|
||||||
|
Index int
|
||||||
|
Seen bool
|
||||||
|
}
|
||||||
|
|
||||||
type OutBufferFrame struct {
|
type OutBufferFrame struct {
|
||||||
Body string
|
Body string
|
||||||
Type string
|
Type string
|
||||||
TemplateName string
|
TemplateName string
|
||||||
|
Extra interface{}
|
||||||
|
Extra2 interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CContext struct {
|
type CContext struct {
|
||||||
|
@ -18,39 +26,12 @@ type CContext struct {
|
||||||
OutBuf *[]OutBufferFrame
|
OutBuf *[]OutBufferFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
func (con *CContext) Push(nType string, body string) {
|
func (con *CContext) Push(nType string, body string) (index int) {
|
||||||
*con.OutBuf = append(*con.OutBuf, OutBufferFrame{body, nType, con.TemplateName})
|
*con.OutBuf = append(*con.OutBuf, OutBufferFrame{body, nType, con.TemplateName, nil, nil})
|
||||||
|
return len(*con.OutBuf) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (con *CContext) GetLastType() string {
|
func (con *CContext) PushText(body string, fragIndex int, fragOutIndex int) (index int) {
|
||||||
outBuf := *con.OutBuf
|
*con.OutBuf = append(*con.OutBuf, OutBufferFrame{body, "text", con.TemplateName, fragIndex, fragOutIndex})
|
||||||
if len(outBuf) == 0 {
|
return len(*con.OutBuf) - 1
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return outBuf[len(outBuf)-1].Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (con *CContext) GetLastBody() string {
|
|
||||||
outBuf := *con.OutBuf
|
|
||||||
if len(outBuf) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return outBuf[len(outBuf)-1].Body
|
|
||||||
}
|
|
||||||
|
|
||||||
func (con *CContext) SetLastBody(newBody string) error {
|
|
||||||
outBuf := *con.OutBuf
|
|
||||||
if len(outBuf) == 0 {
|
|
||||||
return errors.New("outbuf is empty")
|
|
||||||
}
|
|
||||||
outBuf[len(outBuf)-1].Body = newBody
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (con *CContext) GetLastTemplate() string {
|
|
||||||
outBuf := *con.OutBuf
|
|
||||||
if len(outBuf) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return outBuf[len(outBuf)-1].TemplateName
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,6 @@ type CTemplateConfig struct {
|
||||||
PackageName string
|
PackageName string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fragment struct {
|
|
||||||
Body string
|
|
||||||
TemplateName string
|
|
||||||
Index int
|
|
||||||
}
|
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
type CTemplateSet struct {
|
type CTemplateSet struct {
|
||||||
templateList map[string]*parse.Tree
|
templateList map[string]*parse.Tree
|
||||||
|
@ -53,7 +47,7 @@ type CTemplateSet struct {
|
||||||
funcMap map[string]interface{}
|
funcMap map[string]interface{}
|
||||||
importMap map[string]string
|
importMap map[string]string
|
||||||
TemplateFragmentCount map[string]int
|
TemplateFragmentCount map[string]int
|
||||||
Fragments map[string]int
|
FragOnce map[string]bool
|
||||||
fragmentCursor map[string]int
|
fragmentCursor map[string]int
|
||||||
FragOut string
|
FragOut string
|
||||||
fragBuf []Fragment
|
fragBuf []Fragment
|
||||||
|
@ -122,6 +116,16 @@ func (c *CTemplateSet) SetBuildTags(tags string) {
|
||||||
c.buildTags = tags
|
c.buildTags = tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SkipBlock struct {
|
||||||
|
Frags map[int]int
|
||||||
|
LastCount int
|
||||||
|
ClosestFragSkip int
|
||||||
|
}
|
||||||
|
type Skipper struct {
|
||||||
|
Count int
|
||||||
|
Index int
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
|
func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) {
|
||||||
if c.config.Debug {
|
if c.config.Debug {
|
||||||
fmt.Println("Compiling template '" + name + "'")
|
fmt.Println("Compiling template '" + name + "'")
|
||||||
|
@ -173,10 +177,11 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
||||||
c.localVars = make(map[string]map[string]VarItemReflect)
|
c.localVars = make(map[string]map[string]VarItemReflect)
|
||||||
c.localVars[fname] = make(map[string]VarItemReflect)
|
c.localVars[fname] = make(map[string]VarItemReflect)
|
||||||
c.localVars[fname]["."] = VarItemReflect{".", con.VarHolder, con.HoldReflect}
|
c.localVars[fname]["."] = VarItemReflect{".", con.VarHolder, con.HoldReflect}
|
||||||
if c.Fragments == nil {
|
if c.FragOnce == nil {
|
||||||
c.Fragments = make(map[string]int)
|
c.FragOnce = make(map[string]bool)
|
||||||
}
|
}
|
||||||
c.fragmentCursor = map[string]int{fname: 0}
|
c.fragmentCursor = map[string]int{fname: 0}
|
||||||
|
c.fragBuf = nil
|
||||||
c.langIndexToName = nil
|
c.langIndexToName = nil
|
||||||
|
|
||||||
// TODO: Is this the first template loaded in? We really should have some sort of constructor for CTemplateSet
|
// TODO: Is this the first template loaded in? We really should have some sort of constructor for CTemplateSet
|
||||||
|
@ -187,6 +192,11 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
||||||
c.rootIterate(c.templateList[fname], con)
|
c.rootIterate(c.templateList[fname], con)
|
||||||
c.TemplateFragmentCount[fname] = c.fragmentCursor[fname] + 1
|
c.TemplateFragmentCount[fname] = c.fragmentCursor[fname] + 1
|
||||||
|
|
||||||
|
_, ok := c.FragOnce[fname]
|
||||||
|
if !ok {
|
||||||
|
c.FragOnce[fname] = true
|
||||||
|
}
|
||||||
|
|
||||||
if len(c.langIndexToName) > 0 {
|
if len(c.langIndexToName) > 0 {
|
||||||
c.importMap[langPkg] = langPkg
|
c.importMap[langPkg] = langPkg
|
||||||
}
|
}
|
||||||
|
@ -195,7 +205,6 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
||||||
for _, item := range c.importMap {
|
for _, item := range c.importMap {
|
||||||
importList += "import \"" + item + "\"\n"
|
importList += "import \"" + item + "\"\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
var varString string
|
var varString string
|
||||||
for _, varItem := range c.varList {
|
for _, varItem := range c.varList {
|
||||||
varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
|
varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
|
||||||
|
@ -205,7 +214,6 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
||||||
if c.buildTags != "" {
|
if c.buildTags != "" {
|
||||||
fout += "// +build " + c.buildTags + "\n\n"
|
fout += "// +build " + c.buildTags + "\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
fout += "// Code generated by Gosora. More below:\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
|
fout += "// Code generated by Gosora. More below:\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
|
||||||
fout += "package " + c.config.PackageName + "\n" + importList + "\n"
|
fout += "package " + c.config.PackageName + "\n" + importList + "\n"
|
||||||
|
|
||||||
|
@ -238,20 +246,74 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe
|
||||||
fout += "var plist = phrases.GetTmplPhrasesBytes(" + fname + "_tmpl_phrase_id)\n"
|
fout += "var plist = phrases.GetTmplPhrasesBytes(" + fname + "_tmpl_phrase_id)\n"
|
||||||
}
|
}
|
||||||
fout += varString
|
fout += varString
|
||||||
for _, frame := range outBuf {
|
|
||||||
fout += frame.Body
|
var skipped = make(map[string]*SkipBlock) // map[templateName]*SkipBlock{map[atIndexAndAfter]skipThisMuch,lastCount}
|
||||||
|
|
||||||
|
var writeTextFrame = func(tmplName string, index int) {
|
||||||
|
out := "w.Write(" + tmplName + "_frags[" + strconv.Itoa(index) + "]" + ")\n"
|
||||||
|
c.detail("writing ", out)
|
||||||
|
fout += out
|
||||||
|
}
|
||||||
|
|
||||||
|
for fid := 0; len(outBuf) > fid; fid++ {
|
||||||
|
frame := outBuf[fid]
|
||||||
|
if frame.Type == "text" {
|
||||||
|
c.detail("text frame:")
|
||||||
|
c.detail(frame)
|
||||||
|
oid := fid
|
||||||
|
skipBlock, ok := skipped[frame.TemplateName]
|
||||||
|
if !ok {
|
||||||
|
skipBlock = &SkipBlock{make(map[int]int), 0, 0}
|
||||||
|
skipped[frame.TemplateName] = skipBlock
|
||||||
|
}
|
||||||
|
skip := skipBlock.LastCount
|
||||||
|
c.detailf("skipblock %+v\n", skipBlock)
|
||||||
|
for len(outBuf) > fid+1 && outBuf[fid+1].Type == "text" && outBuf[fid+1].TemplateName == frame.TemplateName {
|
||||||
|
next := outBuf[fid+1]
|
||||||
|
c.detail("next frame:", next)
|
||||||
|
c.detail("frame frag:", c.fragBuf[frame.Extra2.(int)])
|
||||||
|
c.detail("next frag:", c.fragBuf[next.Extra2.(int)])
|
||||||
|
c.fragBuf[frame.Extra2.(int)].Body += c.fragBuf[next.Extra2.(int)].Body
|
||||||
|
c.fragBuf[next.Extra2.(int)].Seen = true
|
||||||
|
fid++
|
||||||
|
skipBlock.LastCount += (fid - oid)
|
||||||
|
skipBlock.Frags[frame.Extra.(int)] = skipBlock.LastCount
|
||||||
|
}
|
||||||
|
writeTextFrame(frame.TemplateName, frame.Extra.(int)-skip)
|
||||||
|
} else {
|
||||||
|
c.detail(frame.Type + " frame")
|
||||||
|
fout += frame.Body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fout += "return nil\n}\n"
|
fout += "return nil\n}\n"
|
||||||
|
|
||||||
|
var writeFrag = func(tmplName string, index int, body string) {
|
||||||
|
fragmentPrefix := tmplName + "_frags[" + strconv.Itoa(index) + "]" + " = []byte(`" + body + "`)\n"
|
||||||
|
c.detail("writing ", fragmentPrefix)
|
||||||
|
c.FragOut += fragmentPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, frag := range c.fragBuf {
|
||||||
|
c.detail("frag: ", frag)
|
||||||
|
if frag.Seen {
|
||||||
|
c.detail("invisible")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
skipBlock := skipped[frag.TemplateName]
|
||||||
|
skip := skipBlock.Frags[skipBlock.ClosestFragSkip]
|
||||||
|
_, ok := skipBlock.Frags[frag.Index]
|
||||||
|
if ok {
|
||||||
|
skipBlock.ClosestFragSkip = frag.Index
|
||||||
|
}
|
||||||
|
c.detailf("skipblock %+v\n", skipBlock)
|
||||||
|
c.detail("skipping ", skip)
|
||||||
|
writeFrag(frag.TemplateName, frag.Index-skip, frag.Body)
|
||||||
|
}
|
||||||
|
|
||||||
fout = strings.Replace(fout, `))
|
fout = strings.Replace(fout, `))
|
||||||
w.Write([]byte(`, " + ", -1)
|
w.Write([]byte(`, " + ", -1)
|
||||||
fout = strings.Replace(fout, "` + `", "", -1)
|
fout = strings.Replace(fout, "` + `", "", -1)
|
||||||
|
|
||||||
for _, frag := range c.fragBuf {
|
|
||||||
fragmentPrefix := frag.TemplateName + "_frags[" + strconv.Itoa(frag.Index) + "]"
|
|
||||||
c.FragOut += fragmentPrefix + " = []byte(`" + frag.Body + "`)\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.config.Debug {
|
if c.config.Debug {
|
||||||
for index, count := range c.stats {
|
for index, count := range c.stats {
|
||||||
fmt.Println(index+": ", strconv.Itoa(count))
|
fmt.Println(index+": ", strconv.Itoa(count))
|
||||||
|
@ -264,6 +326,7 @@ w.Write([]byte(`, " + ", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) rootIterate(tree *parse.Tree, con CContext) {
|
func (c *CTemplateSet) rootIterate(tree *parse.Tree, con CContext) {
|
||||||
|
c.dumpCall("rootIterate", tree, con)
|
||||||
c.detail(tree.Root)
|
c.detail(tree.Root)
|
||||||
treeLength := len(tree.Root.Nodes)
|
treeLength := len(tree.Root.Nodes)
|
||||||
for index, node := range tree.Root.Nodes {
|
for index, node := range tree.Root.Nodes {
|
||||||
|
@ -275,10 +338,12 @@ func (c *CTemplateSet) rootIterate(tree *parse.Tree, con CContext) {
|
||||||
}
|
}
|
||||||
c.compileSwitch(con, node)
|
c.compileSwitch(con, node)
|
||||||
}
|
}
|
||||||
|
c.retCall("rootIterate")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compileSwitch(con CContext, node parse.Node) {
|
func (c *CTemplateSet) compileSwitch(con CContext, node parse.Node) {
|
||||||
c.dumpCall("compileSwitch", con, node)
|
c.dumpCall("compileSwitch", con, node)
|
||||||
|
defer c.retCall("compileSwitch")
|
||||||
switch node := node.(type) {
|
switch node := node.(type) {
|
||||||
case *parse.ActionNode:
|
case *parse.ActionNode:
|
||||||
c.detail("Action Node")
|
c.detail("Action Node")
|
||||||
|
@ -333,15 +398,12 @@ func (c *CTemplateSet) compileSwitch(con CContext, node parse.Node) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fragmentName := con.TemplateName + "_" + strconv.Itoa(c.fragmentCursor[con.TemplateName])
|
nodeText := string(node.Text)
|
||||||
fragmentPrefix := con.TemplateName + "_frags[" + strconv.Itoa(c.fragmentCursor[con.TemplateName]) + "]"
|
fragIndex := c.fragmentCursor[con.TemplateName]
|
||||||
_, ok := c.Fragments[fragmentName]
|
_, ok := c.FragOnce[con.TemplateName]
|
||||||
if !ok {
|
c.fragBuf = append(c.fragBuf, Fragment{nodeText, con.TemplateName, fragIndex, ok})
|
||||||
c.Fragments[fragmentName] = len(node.Text)
|
con.PushText(strconv.Itoa(fragIndex), fragIndex, len(c.fragBuf)-1)
|
||||||
c.fragBuf = append(c.fragBuf, Fragment{string(node.Text), con.TemplateName, c.fragmentCursor[con.TemplateName]})
|
c.fragmentCursor[con.TemplateName] = fragIndex + 1
|
||||||
}
|
|
||||||
c.fragmentCursor[con.TemplateName] = c.fragmentCursor[con.TemplateName] + 1
|
|
||||||
con.Push("text", "w.Write("+fragmentPrefix+")\n")
|
|
||||||
default:
|
default:
|
||||||
c.unknownNode(node)
|
c.unknownNode(node)
|
||||||
}
|
}
|
||||||
|
@ -349,6 +411,7 @@ func (c *CTemplateSet) compileSwitch(con CContext, node parse.Node) {
|
||||||
|
|
||||||
func (c *CTemplateSet) compileRangeNode(con CContext, node *parse.RangeNode) {
|
func (c *CTemplateSet) compileRangeNode(con CContext, node *parse.RangeNode) {
|
||||||
c.dumpCall("compileRangeNode", con, node)
|
c.dumpCall("compileRangeNode", con, node)
|
||||||
|
defer c.retCall("compileRangeNode")
|
||||||
c.detail("node.Pipe: ", node.Pipe)
|
c.detail("node.Pipe: ", node.Pipe)
|
||||||
var expr string
|
var expr string
|
||||||
var outVal reflect.Value
|
var outVal reflect.Value
|
||||||
|
@ -653,8 +716,11 @@ func (c *CTemplateSet) compareJoin(con CContext, pos int, node *parse.CommandNod
|
||||||
|
|
||||||
func (c *CTemplateSet) compileIdentSwitch(con CContext, node *parse.CommandNode) (out string, val reflect.Value, literal bool) {
|
func (c *CTemplateSet) compileIdentSwitch(con CContext, node *parse.CommandNode) (out string, val reflect.Value, literal bool) {
|
||||||
c.dumpCall("compileIdentSwitch", con, node)
|
c.dumpCall("compileIdentSwitch", con, node)
|
||||||
var litString = func(inner string) {
|
var litString = func(inner string, bytes bool) {
|
||||||
out = "w.Write([]byte(" + inner + "))\n"
|
if !bytes {
|
||||||
|
inner = "[]byte(" + inner + ")"
|
||||||
|
}
|
||||||
|
out = "w.Write(" + inner + ")\n"
|
||||||
literal = true
|
literal = true
|
||||||
}
|
}
|
||||||
ArgLoop:
|
ArgLoop:
|
||||||
|
@ -682,7 +748,7 @@ ArgLoop:
|
||||||
leftParam, _ := c.compileIfVarSub(con, leftOperand)
|
leftParam, _ := c.compileIfVarSub(con, leftOperand)
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
// TODO: Validate that this is actually a time.Time
|
// TODO: Validate that this is actually a time.Time
|
||||||
litString("time.Since(" + leftParam + ").String()")
|
litString("time.Since("+leftParam+").String()", false)
|
||||||
c.importMap["time"] = "time"
|
c.importMap["time"] = "time"
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "dock":
|
case "dock":
|
||||||
|
@ -692,7 +758,6 @@ ArgLoop:
|
||||||
if len(leftOperand) == 0 || len(rightOperand) == 0 {
|
if len(leftOperand) == 0 || len(rightOperand) == 0 {
|
||||||
panic("The left or right operand for function dock cannot be left blank")
|
panic("The left or right operand for function dock cannot be left blank")
|
||||||
}
|
}
|
||||||
|
|
||||||
leftParam := leftOperand
|
leftParam := leftOperand
|
||||||
if leftOperand[0] != '"' {
|
if leftOperand[0] != '"' {
|
||||||
leftParam, _ = c.compileIfVarSub(con, leftParam)
|
leftParam, _ = c.compileIfVarSub(con, leftParam)
|
||||||
|
@ -707,7 +772,7 @@ ArgLoop:
|
||||||
val = val3
|
val = val3
|
||||||
|
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
litString("common.BuildWidget(" + leftParam + "," + rightParam + ")")
|
litString("common.BuildWidget("+leftParam+","+rightParam+")", false)
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "lang":
|
case "lang":
|
||||||
// TODO: Implement string literals properly
|
// TODO: Implement string literals properly
|
||||||
|
@ -718,11 +783,10 @@ ArgLoop:
|
||||||
if leftOperand[0] != '"' {
|
if leftOperand[0] != '"' {
|
||||||
panic("Phrase names cannot be dynamic")
|
panic("Phrase names cannot be dynamic")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! Slightly crude but it does the job
|
// ! Slightly crude but it does the job
|
||||||
leftParam := strings.Replace(leftOperand, "\"", "", -1)
|
leftParam := strings.Replace(leftOperand, "\"", "", -1)
|
||||||
c.langIndexToName = append(c.langIndexToName, leftParam)
|
c.langIndexToName = append(c.langIndexToName, leftParam)
|
||||||
litString("plist[" + strconv.Itoa(len(c.langIndexToName)-1) + "]")
|
litString("plist["+strconv.Itoa(len(c.langIndexToName)-1)+"]", true)
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "level":
|
case "level":
|
||||||
// TODO: Implement level literals
|
// TODO: Implement level literals
|
||||||
|
@ -732,7 +796,7 @@ ArgLoop:
|
||||||
}
|
}
|
||||||
leftParam, _ := c.compileIfVarSub(con, leftOperand)
|
leftParam, _ := c.compileIfVarSub(con, leftOperand)
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
litString("phrases.GetLevelPhrase(" + leftParam + ")")
|
litString("phrases.GetLevelPhrase("+leftParam+")", false)
|
||||||
c.importMap[langPkg] = langPkg
|
c.importMap[langPkg] = langPkg
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "scope":
|
case "scope":
|
||||||
|
@ -991,6 +1055,7 @@ func (c *CTemplateSet) retCall(name string, params ...interface{}) {
|
||||||
|
|
||||||
func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.Value, assLines string, onEnd func(string) string) {
|
func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.Value, assLines string, onEnd func(string) string) {
|
||||||
c.dumpCall("compileVarSub", con, varname, val, assLines, onEnd)
|
c.dumpCall("compileVarSub", con, varname, val, assLines, onEnd)
|
||||||
|
defer c.retCall("compileVarSub")
|
||||||
if onEnd == nil {
|
if onEnd == nil {
|
||||||
onEnd = func(in string) string {
|
onEnd = func(in string) string {
|
||||||
return in
|
return in
|
||||||
|
@ -999,7 +1064,7 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
|
||||||
|
|
||||||
// Is this a literal string?
|
// Is this a literal string?
|
||||||
if len(varname) != 0 && varname[0] == '"' {
|
if len(varname) != 0 && varname[0] == '"' {
|
||||||
con.Push("varsub", onEnd(assLines+"w.Write([]byte("+varname+"))\n"))
|
con.Push("lvarsub", onEnd(assLines+"w.Write([]byte("+varname+"))\n"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, varItem := range c.varList {
|
for _, varItem := range c.varList {
|
||||||
|
@ -1030,17 +1095,23 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
|
||||||
switch val.Kind() {
|
switch val.Kind() {
|
||||||
case reflect.Int:
|
case reflect.Int:
|
||||||
c.importMap["strconv"] = "strconv"
|
c.importMap["strconv"] = "strconv"
|
||||||
base = "w.Write([]byte(strconv.Itoa(" + varname + ")))\n"
|
base = "[]byte(strconv.Itoa(" + varname + "))"
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
base = "if " + varname + " {\nw.Write([]byte(\"true\"))} else {\nw.Write([]byte(\"false\"))\n}\n"
|
con.Push("startif", "if "+varname+" {\n")
|
||||||
|
con.Push("varsub", "w.Write([]byte(\"true\"))")
|
||||||
|
con.Push("endif", "} ")
|
||||||
|
con.Push("startelse", "else {\n")
|
||||||
|
con.Push("varsub", "w.Write([]byte(\"false\"))")
|
||||||
|
con.Push("endelse", "}\n")
|
||||||
|
return
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if val.Type().Name() != "string" && !strings.HasPrefix(varname, "string(") {
|
if val.Type().Name() != "string" && !strings.HasPrefix(varname, "string(") {
|
||||||
varname = "string(" + varname + ")"
|
varname = "string(" + varname + ")"
|
||||||
}
|
}
|
||||||
base = "w.Write([]byte(" + varname + "))\n"
|
base = "[]byte(" + varname + ")"
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
c.importMap["strconv"] = "strconv"
|
c.importMap["strconv"] = "strconv"
|
||||||
base = "w.Write([]byte(strconv.FormatInt(" + varname + ", 10)))\n"
|
base = "[]byte(strconv.FormatInt(" + varname + ", 10))"
|
||||||
default:
|
default:
|
||||||
if !val.IsValid() {
|
if !val.IsValid() {
|
||||||
panic(assLines + varname + "^\n" + "Invalid value. Maybe, it doesn't exist?")
|
panic(assLines + varname + "^\n" + "Invalid value. Maybe, it doesn't exist?")
|
||||||
|
@ -1050,12 +1121,17 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V
|
||||||
fmt.Println("Unknown Type:", val.Type().Name())
|
fmt.Println("Unknown Type:", val.Type().Name())
|
||||||
panic("-- I don't know what this variable's type is o.o\n")
|
panic("-- I don't know what this variable's type is o.o\n")
|
||||||
}
|
}
|
||||||
|
base = "w.Write(" + base + ")\n"
|
||||||
c.detail("base: ", base)
|
c.detail("base: ", base)
|
||||||
con.Push("varsub", onEnd(assLines+base))
|
if assLines == "" {
|
||||||
|
con.Push("varsub", base)
|
||||||
|
} else {
|
||||||
|
con.Push("lvarsub", onEnd(assLines+base))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNode) {
|
func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNode) {
|
||||||
c.debugCall("compileSubTemplate", pcon, node)
|
c.dumpCall("compileSubTemplate", pcon, node)
|
||||||
c.detail("Template Node: ", node.Name)
|
c.detail("Template Node: ", node.Name)
|
||||||
|
|
||||||
fname := strings.TrimSuffix(node.Name, filepath.Ext(node.Name))
|
fname := strings.TrimSuffix(node.Name, filepath.Ext(node.Name))
|
||||||
|
@ -1107,26 +1183,33 @@ func (c *CTemplateSet) compileSubTemplate(pcon CContext, node *parse.TemplateNod
|
||||||
c.localVars[fname] = make(map[string]VarItemReflect)
|
c.localVars[fname] = make(map[string]VarItemReflect)
|
||||||
c.localVars[fname]["."] = VarItemReflect{".", con.VarHolder, con.HoldReflect}
|
c.localVars[fname]["."] = VarItemReflect{".", con.VarHolder, con.HoldReflect}
|
||||||
c.fragmentCursor[fname] = 0
|
c.fragmentCursor[fname] = 0
|
||||||
|
con.Push("starttemplate", "{\n")
|
||||||
c.rootIterate(subtree, con)
|
c.rootIterate(subtree, con)
|
||||||
|
con.Push("endtemplate", "}\n")
|
||||||
c.TemplateFragmentCount[fname] = c.fragmentCursor[fname] + 1
|
c.TemplateFragmentCount[fname] = c.fragmentCursor[fname] + 1
|
||||||
|
|
||||||
|
_, ok := c.FragOnce[fname]
|
||||||
|
if !ok {
|
||||||
|
c.FragOnce[fname] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should we rethink the way the log methods work or their names?
|
// TODO: Should we rethink the way the log methods work or their names?
|
||||||
|
|
||||||
func (c *CTemplateSet) detail(args ...interface{}) {
|
func (c *CTemplateSet) detail(args ...interface{}) {
|
||||||
if c.config.SuperDebug {
|
if c.config.SuperDebug {
|
||||||
fmt.Println(args...)
|
log.Println(args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) detailf(left string, args ...interface{}) {
|
func (c *CTemplateSet) detailf(left string, args ...interface{}) {
|
||||||
if c.config.SuperDebug {
|
if c.config.SuperDebug {
|
||||||
fmt.Printf(left, args...)
|
log.Printf(left, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) error(args ...interface{}) {
|
func (c *CTemplateSet) error(args ...interface{}) {
|
||||||
if c.config.Debug {
|
if c.config.Debug {
|
||||||
fmt.Println(args...)
|
log.Println(args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TopicListThaw ThawInt
|
||||||
|
|
||||||
|
type ThawInt interface {
|
||||||
|
Thawed() bool
|
||||||
|
Thaw()
|
||||||
|
|
||||||
|
Tick() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type SingleServerThaw struct {
|
||||||
|
DefaultThaw
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSingleServerThaw() *SingleServerThaw {
|
||||||
|
thaw := &SingleServerThaw{}
|
||||||
|
if Config.ServerCount == 1 {
|
||||||
|
AddScheduledSecondTask(thaw.Tick)
|
||||||
|
}
|
||||||
|
return thaw
|
||||||
|
}
|
||||||
|
|
||||||
|
func (thaw *SingleServerThaw) Thawed() bool {
|
||||||
|
if Config.ServerCount == 1 {
|
||||||
|
return thaw.DefaultThaw.Thawed()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (thaw *SingleServerThaw) Thaw() {
|
||||||
|
if Config.ServerCount == 1 {
|
||||||
|
thaw.DefaultThaw.Thaw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultThaw struct {
|
||||||
|
thawed int64
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultThaw() *DefaultThaw {
|
||||||
|
thaw := &DefaultThaw{}
|
||||||
|
AddScheduledSecondTask(thaw.Tick)
|
||||||
|
return thaw
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrement the thawed counter once a second until it goes cold
|
||||||
|
func (thaw *DefaultThaw) Tick() error {
|
||||||
|
thaw.Lock()
|
||||||
|
defer thaw.Unlock()
|
||||||
|
prior := thaw.thawed
|
||||||
|
if prior > 0 {
|
||||||
|
atomic.StoreInt64(&thaw.thawed, prior-1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (thaw *DefaultThaw) Thawed() bool {
|
||||||
|
return thaw.thawed > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (thaw *DefaultThaw) Thaw() {
|
||||||
|
atomic.StoreInt64(&thaw.thawed, 5)
|
||||||
|
}
|
|
@ -192,6 +192,7 @@ func (topic *Topic) cacheRemove() {
|
||||||
if tcache != nil {
|
if tcache != nil {
|
||||||
tcache.Remove(topic.ID)
|
tcache.Remove(topic.ID)
|
||||||
}
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// TODO: Write a test for this
|
||||||
|
@ -259,6 +260,7 @@ func (topic *Topic) Like(score int, uid int) (err error) {
|
||||||
|
|
||||||
// TODO: Implement this
|
// TODO: Implement this
|
||||||
func (topic *Topic) Unlike(uid int) error {
|
func (topic *Topic) Unlike(uid int) error {
|
||||||
|
topic.cacheRemove()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,12 @@ func NewDefaultTopicList() (*DefaultTopicList, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tList *DefaultTopicList) Tick() error {
|
func (tList *DefaultTopicList) Tick() error {
|
||||||
|
//fmt.Println("TopicList.Tick")
|
||||||
|
if !TopicListThaw.Thawed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
//fmt.Println("building topic list")
|
||||||
|
|
||||||
var oddLists = make(map[int]*TopicListHolder)
|
var oddLists = make(map[int]*TopicListHolder)
|
||||||
var evenLists = make(map[int]*TopicListHolder)
|
var evenLists = make(map[int]*TopicListHolder)
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ func (mts *DefaultTopicStore) Reload(id int) error {
|
||||||
} else {
|
} else {
|
||||||
_ = mts.cache.Remove(id)
|
_ = mts.cache.Remove(id)
|
||||||
}
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,7 @@ func (user *User) CacheRemove() {
|
||||||
if ucache != nil {
|
if ucache != nil {
|
||||||
ucache.Remove(user.ID)
|
ucache.Remove(user.ID)
|
||||||
}
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) Ban(duration time.Duration, issuedBy int) error {
|
func (user *User) Ban(duration time.Duration, issuedBy int) error {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
||||||
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
||||||
register: acc.Insert("users").Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
|
register: acc.Insert("users").Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
|
||||||
usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""),
|
usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""),
|
||||||
userCount: acc.SimpleCount("users", "", ""),
|
userCount: acc.Count("users").Prepare(),
|
||||||
}, acc.FirstError()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +244,7 @@ func (mus *DefaultUserStore) Reload(id int) error {
|
||||||
|
|
||||||
user.Init()
|
user.Init()
|
||||||
_ = mus.cache.Set(user)
|
_ = mus.cache.Set(user)
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,12 +271,10 @@ func (mus *DefaultUserStore) Create(username string, password string, email stri
|
||||||
if err != ErrNoRows {
|
if err != ErrNoRows {
|
||||||
return 0, ErrAccountExists
|
return 0, ErrAccountExists
|
||||||
}
|
}
|
||||||
|
|
||||||
salt, err := GenerateSafeString(SaltLength)
|
salt, err := GenerateSafeString(SaltLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password+salt), bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password+salt), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
|
@ -69,6 +69,7 @@ func gloinit() (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
common.TopicListThaw = common.NewSingleServerThaw()
|
||||||
common.SwitchToTestDB()
|
common.SwitchToTestDB()
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
Loading…
Reference in New Issue