diff --git a/common/likes.go b/common/likes.go index 54ca7f68..9b636f4e 100644 --- a/common/likes.go +++ b/common/likes.go @@ -10,6 +10,7 @@ var Likes LikeStore type LikeStore interface { BulkExists(ids []int, sentBy int, targetType string) ([]int, error) + BulkExistsFunc(ids []int, sentBy int, targetType string, f func(int) error) error Delete(targetID int, targetType string) error Count() (count int) } @@ -56,6 +57,36 @@ func (s *DefaultLikeStore) BulkExists(ids []int, sentBy int, targetType string) return eids, rows.Err() } +// TODO: Write a test for this +func (s *DefaultLikeStore) BulkExistsFunc(ids []int, sentBy int, targetType string, f func(id int) error) (e error) { + if len(ids) == 0 { + return nil + } + var rows *sql.Rows + if len(ids) == 1 { + rows, e = s.singleExists.Query(sentBy, targetType, ids[0]) + } else { + rows, e = qgen.NewAcc().Select("likes").Columns("targetItem").Where("sentBy=? AND targetType=?").In("targetItem", ids).Query(sentBy, targetType) + } + if e == sql.ErrNoRows { + return nil + } else if e != nil { + return e + } + defer rows.Close() + + var id int + for rows.Next() { + if e := rows.Scan(&id); e != nil { + return e + } + if e := f(id); e != nil { + return e + } + } + return rows.Err() +} + func (s *DefaultLikeStore) Delete(targetID int, targetType string) error { _, err := s.delete.Exec(targetID, targetType) return err diff --git a/common/menus.go b/common/menus.go index fa1317fb..4cadc3e5 100644 --- a/common/menus.go +++ b/common/menus.go @@ -77,32 +77,32 @@ func init() { } func (i MenuItem) Commit() error { - _, err := menuItemStmts.update.Exec(i.Name, i.HTMLID, i.CSSClass, i.Position, i.Path, i.Aria, i.Tooltip, i.TmplName, i.GuestOnly, i.MemberOnly, i.SuperModOnly, i.AdminOnly, i.ID) + _, e := menuItemStmts.update.Exec(i.Name, i.HTMLID, i.CSSClass, i.Position, i.Path, i.Aria, i.Tooltip, i.TmplName, i.GuestOnly, i.MemberOnly, i.SuperModOnly, i.AdminOnly, i.ID) Menus.Load(i.MenuID) - return err + return e } func (i MenuItem) Create() (int, error) { - res, err := menuItemStmts.insert.Exec(i.MenuID, i.Name, i.HTMLID, i.CSSClass, i.Position, i.Path, i.Aria, i.Tooltip, i.TmplName, i.GuestOnly, i.MemberOnly, i.SuperModOnly, i.AdminOnly) - if err != nil { - return 0, err + res, e := menuItemStmts.insert.Exec(i.MenuID, i.Name, i.HTMLID, i.CSSClass, i.Position, i.Path, i.Aria, i.Tooltip, i.TmplName, i.GuestOnly, i.MemberOnly, i.SuperModOnly, i.AdminOnly) + if e != nil { + return 0, e } Menus.Load(i.MenuID) - miid64, err := res.LastInsertId() - return int(miid64), err + miid64, e := res.LastInsertId() + return int(miid64), e } func (i MenuItem) Delete() error { - _, err := menuItemStmts.delete.Exec(i.ID) + _, e := menuItemStmts.delete.Exec(i.ID) Menus.Load(i.MenuID) - return err + return e } -func (h *MenuListHolder) LoadTmpl(name string) (t MenuTmpl, err error) { - data, err := ioutil.ReadFile("./templates/" + name + ".html") - if err != nil { - return t, err +func (h *MenuListHolder) LoadTmpl(name string) (t MenuTmpl, e error) { + data, e := ioutil.ReadFile("./templates/" + name + ".html") + if e != nil { + return t, e } return h.Parse(name, []byte(tmpl.Minify(string(data)))), nil } @@ -110,31 +110,31 @@ func (h *MenuListHolder) LoadTmpl(name string) (t MenuTmpl, err error) { // TODO: Make this atomic, maybe with a transaction or store the order on the menu itself? func (h *MenuListHolder) UpdateOrder(updateMap map[int]int) error { for miid, order := range updateMap { - _, err := menuItemStmts.updateOrder.Exec(order, miid) - if err != nil { - return err + _, e := menuItemStmts.updateOrder.Exec(order, miid) + if e != nil { + return e } } Menus.Load(h.MenuID) return nil } -func (h *MenuListHolder) LoadTmpls() (tmpls map[string]MenuTmpl, err error) { +func (h *MenuListHolder) LoadTmpls() (tmpls map[string]MenuTmpl, e error) { tmpls = make(map[string]MenuTmpl) load := func(name string) error { - menuTmpl, err := h.LoadTmpl(name) - if err != nil { - return err + menuTmpl, e := h.LoadTmpl(name) + if e != nil { + return e } tmpls[name] = menuTmpl return nil } - err = load("menu_item") - if err != nil { - return tmpls, err + e = load("menu_item") + if e != nil { + return tmpls, e } - err = load("menu_alerts") - return tmpls, err + e = load("menu_alerts") + return tmpls, e } // TODO: Run this in main, sync ticks, when the phrase file changes (need to implement the sync for that first), and when the settings are changed @@ -259,8 +259,8 @@ type MenuTmpl struct { func menuDumpSlice(outerSlice [][]byte) { for sliceID, slice := range outerSlice { fmt.Print(strconv.Itoa(sliceID) + ":[") - for _, char := range slice { - fmt.Print(string(char)) + for _, ch := range slice { + fmt.Print(string(ch)) } fmt.Print("] ") } diff --git a/common/tasks.go b/common/tasks.go index 6b96d100..8f80b241 100644 --- a/common/tasks.go +++ b/common/tasks.go @@ -23,6 +23,7 @@ var ScheduledHalfSecondTasks []func() error var ScheduledSecondTasks []func() error var ScheduledFifteenMinuteTasks []func() error var ScheduledHourTasks []func() error +var ScheduledDayTasks []func() error var ShutdownTasks []func() error var taskStmts TaskStmts var lastSync time.Time @@ -59,6 +60,11 @@ func AddScheduledHourTask(task func() error) { ScheduledHourTasks = append(ScheduledHourTasks, task) } +// AddScheduledDayTask is not concurrency safe +func AddScheduledDayTask(task func() error) { + ScheduledDayTasks = append(ScheduledDayTasks, task) +} + // AddShutdownTask is not concurrency safe func AddShutdownTask(task func() error) { ShutdownTasks = append(ShutdownTasks, task) @@ -84,6 +90,11 @@ func ScheduledHourTaskCount() int { return len(ScheduledHourTasks) } +// ScheduledDayTaskCount is not concurrency safe +func ScheduledDayTaskCount() int { + return len(ScheduledDayTasks) +} + // ShutdownTaskCount is not concurrency safe func ShutdownTaskCount() int { return len(ShutdownTasks) @@ -105,8 +116,7 @@ func HandleExpiredScheduledGroups() error { // Sneaky way of initialising a *User, please use the methods on the UserStore instead user := BlankUser() user.ID = uid - e = user.RevertGroupUpdate() - if e != nil { + if e = user.RevertGroupUpdate(); e != nil { return e } } @@ -130,20 +140,17 @@ func HandleServerSync() error { } if lastUpdate.After(lastSync) { - e = Forums.LoadForums() - if e != nil { + if e = Forums.LoadForums(); e != nil { log.Print("Unable to reload the forums") return e } // TODO: Resync the groups // TODO: Resync the permissions - e = LoadSettings() - if e != nil { + if e = LoadSettings(); e != nil { log.Print("Unable to reload the settings") return e } - e = WordFilters.ReloadAll() - if e != nil { + if e = WordFilters.ReloadAll(); e != nil { log.Print("Unable to reload the word filters") return e } diff --git a/common/topic.go b/common/topic.go index 9d1b07ab..a9f2c02e 100644 --- a/common/topic.go +++ b/common/topic.go @@ -1048,12 +1048,12 @@ func (t *TopicUser) Replies(offset int /*pFrag int, */, user *User) (rlist []*Re // TODO: Add a config setting to disable the liked query for a burst of extra speed if user.Liked > 0 && len(likedQueryList) > 0 /*&& user.LastLiked <= time.Now()*/ { - eids, err := Likes.BulkExists(likedQueryList, user.ID, "replies") - if err != nil { - return nil, externalHead, err - } - for _, eid := range eids { + e := Likes.BulkExistsFunc(likedQueryList, user.ID, "replies", func(eid int) error { rlist[likedMap[eid]].Liked = true + return nil + }) + if e != nil { + return nil, externalHead, e } }