gosora/group_store.go

215 lines
5.1 KiB
Go

/* Under Heavy Construction */
package main
import (
"encoding/json"
"errors"
"log"
"sync"
)
var groupCreateMutex sync.Mutex
var groupUpdateMutex sync.Mutex
var gstore GroupStore
// ? - We could fallback onto the database when an item can't be found in the cache?
type GroupStore interface {
LoadGroups() error
DirtyGet(id int) *Group
Get(id int) (*Group, error)
GetCopy(id int) (Group, error)
Exists(id int) bool
Create(groupName string, tag string, isAdmin bool, isMod bool, isBanned bool) (int, error)
GetAll() ([]*Group, error)
GetRange(lower int, higher int) ([]*Group, error)
}
type GroupCache interface {
Length() int
}
type MemoryGroupStore struct {
groups []*Group // TODO: Use a sync.Map instead of a slice
groupCapCount int
}
func NewMemoryGroupStore() *MemoryGroupStore {
return &MemoryGroupStore{}
}
func (mgs *MemoryGroupStore) LoadGroups() error {
mgs.groups = []*Group{&Group{ID: 0, Name: "Unknown"}}
rows, err := getGroupsStmt.Query()
if err != nil {
return err
}
defer rows.Close()
i := 1
for ; rows.Next(); i++ {
group := Group{ID: 0}
err := rows.Scan(&group.ID, &group.Name, &group.PermissionsText, &group.PluginPermsText, &group.IsMod, &group.IsAdmin, &group.IsBanned, &group.Tag)
if err != nil {
return err
}
err = json.Unmarshal(group.PermissionsText, &group.Perms)
if err != nil {
return err
}
if dev.DebugMode {
log.Print(group.Name + ": ")
log.Printf("%+v\n", group.Perms)
}
err = json.Unmarshal(group.PluginPermsText, &group.PluginPerms)
if err != nil {
return err
}
if dev.DebugMode {
log.Print(group.Name + ": ")
log.Printf("%+v\n", group.PluginPerms)
}
//group.Perms.ExtData = make(map[string]bool)
mgs.groups = append(mgs.groups, &group)
}
err = rows.Err()
if err != nil {
return err
}
mgs.groupCapCount = i
if dev.DebugMode {
log.Print("Binding the Not Loggedin Group")
}
GuestPerms = mgs.groups[6].Perms
return nil
}
func (mgs *MemoryGroupStore) DirtyGet(gid int) *Group {
if !mgs.Exists(gid) {
return &blankGroup
}
return mgs.groups[gid]
}
func (mgs *MemoryGroupStore) Get(gid int) (*Group, error) {
if !mgs.Exists(gid) {
return nil, ErrNoRows
}
return mgs.groups[gid], nil
}
func (mgs *MemoryGroupStore) GetCopy(gid int) (Group, error) {
if !mgs.Exists(gid) {
return blankGroup, ErrNoRows
}
return *mgs.groups[gid], nil
}
func (mgs *MemoryGroupStore) Exists(gid int) bool {
return (gid <= mgs.groupCapCount) && (gid > -1) && mgs.groups[gid].Name != ""
}
func (mgs *MemoryGroupStore) Create(groupName string, tag string, isAdmin bool, isMod bool, isBanned bool) (int, error) {
groupCreateMutex.Lock()
defer groupCreateMutex.Unlock()
var permstr = "{}"
res, err := createGroupStmt.Exec(groupName, tag, isAdmin, isMod, isBanned, permstr)
if err != nil {
return 0, err
}
gid64, err := res.LastInsertId()
if err != nil {
return 0, err
}
var gid = int(gid64)
var perms = BlankPerms
var blankForums []ForumPerms
var blankIntList []int
var pluginPerms = make(map[string]bool)
var pluginPermsBytes = []byte("{}")
if vhooks["create_group_preappend"] != nil {
runVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
}
mgs.groups = append(mgs.groups, &Group{gid, groupName, isMod, isAdmin, isBanned, tag, perms, []byte(permstr), pluginPerms, pluginPermsBytes, blankForums, blankIntList})
// Generate the forum permissions based on the presets...
fdata, err := fstore.GetAll()
if err != nil {
return 0, err
}
permUpdateMutex.Lock()
defer permUpdateMutex.Unlock()
for _, forum := range fdata {
var thePreset string
if isAdmin {
thePreset = "admins"
} else if isMod {
thePreset = "staff"
} else if isBanned {
thePreset = "banned"
} else {
thePreset = "members"
}
permmap := presetToPermmap(forum.Preset)
permitem := permmap[thePreset]
permitem.Overrides = true
permstr, err := json.Marshal(permitem)
if err != nil {
return gid, err
}
perms := string(permstr)
_, err = addForumPermsToGroupStmt.Exec(gid, forum.ID, forum.Preset, perms)
if err != nil {
return gid, err
}
err = rebuildForumPermissions(forum.ID)
if err != nil {
return gid, err
}
}
return gid, nil
}
// ! NOT CONCURRENT
func (mgs *MemoryGroupStore) GetAll() ([]*Group, error) {
return mgs.groups, nil
}
// ? - It's currently faster to use GetAll(), but we'll be dropping the guarantee that the slices are ordered soon
// ? - Set the lower and higher numbers to 0 to remove the bounds
// ? - Currently uses slicing for efficiency, so it might behave a little weirdly
func (mgs *MemoryGroupStore) GetRange(lower int, higher int) (groups []*Group, err error) {
if lower == 0 && higher == 0 {
return mgs.GetAll()
} else if lower == 0 {
if higher < 0 {
return nil, errors.New("higher may not be lower than 0")
}
if higher > len(mgs.groups) {
higher = len(mgs.groups)
}
groups = mgs.groups[:higher]
} else if higher == 0 {
if lower < 0 {
return nil, errors.New("lower may not be lower than 0")
}
groups = mgs.groups[lower:]
}
return groups, nil
}
func (mgs *MemoryGroupStore) Length() int {
return len(mgs.groups)
}