Skip to content

Commit

Permalink
all: improve state interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
jogramming committed Mar 12, 2019
1 parent 10cabab commit 8eddf03
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 106 deletions.
69 changes: 26 additions & 43 deletions autorole/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,8 @@ func runDurationChecker() {

if len(guildsToCheck) < 0 || i >= len(guildsToCheck) {
// Copy the list of guilds so that we dont need to keep the entire state locked
state.RLock()
guildsToCheck = make([]*dstate.GuildState, 0, len(state.Guilds))
guildsToCheck = state.GuildsSlice(true)
i = 0
for _, v := range state.Guilds {
if v == nil || v.ID == 0 {
continue
}
guildsToCheck = append(guildsToCheck, v)
}
state.RUnlock()

// Hit each guild once per minute
numToCheckPerRun = len(guildsToCheck) / 60
Expand All @@ -157,58 +149,48 @@ func runDurationChecker() {
}
}

func checkGuild(gs *dstate.GuildState) {
// returns true if we should skip the guild
func stateLockedSkipGuild(gs *dstate.GuildState, conf *GeneralConfig) bool {
gs.RLock()
defer gs.RUnlock()
if gs.Guild.Unavailable {
return
}

logger := logrus.WithField("guild", gs.ID)
working, err := WorkingOnFullScan(gs.ID)
if err != nil {
logger.WithError(err).Error("failed checking working on full scan")
if gs.Guild.Unavailable {
return true
}

if working {
return // Working on a full scan, do nothing
if !bot.BotProbablyHasPermissionGS(false, gs, 0, discordgo.PermissionManageRoles) {
return true
}

perms, err := gs.MemberPermissions(false, 0, common.BotUser.ID)
if err != nil && err != dstate.ErrChannelNotFound {
logger.WithError(err).Error("Error checking perms")
return
if gs.Role(false, conf.Role) == nil {
conf.Role = 0
saveGeneral(gs.ID, conf)
return true
}

if perms&discordgo.PermissionManageRoles == 0 {
// Not enough permissions to assign roles, skip this guild
return
}
return false
}

gs.RUnlock()
func checkGuild(gs *dstate.GuildState) {
conf, err := GuildCacheGetGeneralConfig(gs)
gs.RLock()
if err != nil {
logger.WithError(err).Error("Failed retrieivng general config")
logrus.WithField("guild", gs.ID).WithError(err).Error("Failed retrieivng general config")
return
}

if conf.Role == 0 || conf.OnlyOnJoin {
return
}

// Make sure the role exists
for _, role := range gs.Guild.Roles {
if role.ID == conf.Role {
go processGuild(gs, conf)
return
}
if stateLockedSkipGuild(gs, conf) {
return
}

if WorkingOnFullScan(gs.ID) {
return // Working on a full scan, do nothing
}

// If not remove it
logger.Info("Autorole role dosen't exist, removing config...")
conf.Role = 0
saveGeneral(gs.ID, conf)
go processGuild(gs, conf)
}

func processGuild(gs *dstate.GuildState, config *GeneralConfig) {
Expand Down Expand Up @@ -440,14 +422,15 @@ OUTER:
}
}

func WorkingOnFullScan(guildID int64) (bool, error) {
func WorkingOnFullScan(guildID int64) bool {
var b bool
err := common.RedisPool.Do(radix.Cmd(&b, "EXISTS", RedisKeyGuildChunkProecssing(guildID)))
if err != nil {
return false, err
logrus.WithError(err).WithField("guild", guildID).Error("[autorole] failed checking WorkingOnFullScan")
return false
}

return b, nil
return b
}

type CacheKey int
Expand Down
5 changes: 1 addition & 4 deletions autorole/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ func handleGetAutoroleMainPage(w http.ResponseWriter, r *http.Request) interface
tmpl["Processing"] = proc
tmpl["ProcessingETA"] = int(proc / 60)

fullScanActive, err := WorkingOnFullScan(activeGuild.ID)
if err != nil {
web.CtxLogger(ctx).WithError(err).Error("failed checking full scan")
}
fullScanActive := WorkingOnFullScan(activeGuild.ID)
tmpl["FullScanActive"] = fullScanActive

return tmpl
Expand Down
23 changes: 5 additions & 18 deletions bot/botrest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,15 +204,7 @@ func HandleGuild(w http.ResponseWriter, r *http.Request) {
return
}

guild.RLock()
defer guild.RUnlock()

gCopy := new(discordgo.Guild)
*gCopy = *guild.Guild

gCopy.Members = nil
gCopy.Presences = nil
gCopy.VoiceStates = nil
gCopy := guild.DeepCopy(true, true, false, true)

ServeJson(w, r, gCopy)
}
Expand All @@ -226,17 +218,12 @@ func HandleBotMember(w http.ResponseWriter, r *http.Request) {
return
}

guild.RLock()
ms := guild.Member(false, common.BotUser.ID)
if ms == nil {
guild.RUnlock()
member := guild.MemberDGoCopy(true, common.BotUser.ID)
if member == nil {
ServerError(w, r, errors.New("Bot Member not found"))
return
}

member := ms.DGoCopy()
guild.RUnlock()

ServeJson(w, r, member)
}

Expand Down Expand Up @@ -303,8 +290,8 @@ func HandleGetMemberColors(w http.ResponseWriter, r *http.Request) {

memberStates, _ := bot.GetMembers(gId, uIDsParsed...)

guild.RLock()
defer guild.RUnlock()
guild.Lock()
defer guild.Unlock()

// Make sure the roles are in the proper order
sort.Sort(dutil.Roles(guild.Guild.Roles))
Expand Down
12 changes: 4 additions & 8 deletions customcommands/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,10 @@ func handleDelayedRunCC(evt *schEventsModels.ScheduledEvent, data interface{}) (
cs := gs.Channel(true, dataCast.ChannelID)
if cs == nil {
// don't reschedule if channel is deleted, make sure its actually not there, and not just a discord downtime
gs.RLock()
if gs.Guild.Unavailable {
gs.RUnlock()
if !gs.IsAvailable(true) {
return true, nil
}
gs.RUnlock()

return false, nil
}

Expand Down Expand Up @@ -241,12 +239,10 @@ func handleNextRunScheduledEVent(evt *schEventsModels.ScheduledEvent, data inter
cs := gs.Channel(true, cmd.ContextChannel)
if cs == nil {
// don't reschedule if channel is deleted, make sure its actually not there, and not just a discord downtime
gs.RLock()
if gs.Guild.Unavailable {
gs.RUnlock()
if !gs.IsAvailable(true) {
return true, nil
}
gs.RUnlock()

return false, nil
}

Expand Down
8 changes: 3 additions & 5 deletions logs/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,12 @@ func CreateChannelLog(ctx context.Context, config *models.GuildLoggingConfig, gu
count = 300
}

cs := bot.State.Channel(true, channelID)
if cs == nil {
// Make a light copy of the channel
channel := bot.State.ChannelCopy(true, channelID)
if channel == nil {
return nil, errors.New("Unknown channel")
}

// Make a light copy of the channel
channel := cs.Copy(true)

msgs, err := bot.GetMessages(channel.ID, count, true)
if err != nil {
return nil, err
Expand Down
8 changes: 2 additions & 6 deletions logs/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,29 +341,25 @@ func HandlePresenceUpdate(evt *eventsystem.EventData) {
}

gs.RLock()
defer gs.RUnlock()

ms := gs.Member(false, pu.User.ID)
if ms == nil || !ms.PresenceSet || !ms.MemberSet {
gs.RUnlock()

go func() { evtChan <- pu }()
return
}

if pu.User.Username != "" {
if pu.User.Username != ms.Username {
gs.RUnlock()
go func() { evtChan <- pu }()
return
}
}

if pu.Nick != ms.Nick {
gs.RUnlock()
go func() { evtChan <- pu }()
return
}

gs.RUnlock()
}

// While presence update is sent when user changes username.... MAKES NO SENSE IMO BUT WHATEVER
Expand Down
4 changes: 1 addition & 3 deletions notifications/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,12 @@ func sendTemplate(cs *dstate.ChannelState, tmpl string, ms *dstate.MemberState,
func HandleChannelUpdate(evt *eventsystem.EventData) {
cu := evt.ChannelUpdate()

curChannel := bot.State.Channel(true, cu.ID)
curChannel := bot.State.ChannelCopy(true, cu.ID)
if curChannel == nil {
return
}

curChannel.Owner.RLock()
oldTopic := curChannel.Topic
curChannel.Owner.RUnlock()

if oldTopic == cu.Topic {
return
Expand Down
12 changes: 2 additions & 10 deletions serverstats/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,17 +224,9 @@ OUTER:

if len(guildsToCheck) < 0 || i >= len(guildsToCheck) {
// Copy the list of guilds so that we dont need to keep the entire state locked
state.RLock()
guildsToCheck = make([]*dstate.GuildState, 0, len(state.Guilds))
i = 0
for _, v := range state.Guilds {
if v == nil || v.ID == 0 {
continue
}

guildsToCheck = append(guildsToCheck, v)
}
state.RUnlock()
i = 0
guildsToCheck = state.GuildsSlice(true)

// Hit each guild once per hour more or less
numToCheckPerRun = len(guildsToCheck) / 2500
Expand Down
10 changes: 1 addition & 9 deletions stdcommands/mentionrole/mentionrole.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,7 @@ func handleResetMentionableRole(evt *seventsmodels.ScheduledEvent, dataInterface
return false, nil
}

var role *discordgo.Role
gs.RLock()
defer gs.RUnlock()
for _, r := range gs.Guild.Roles {
if r.ID == data.RoleID {
role = r
break
}
}
role := gs.RoleCopy(true, data.RoleID)

if role == nil {
return false, nil // Assume role was deleted or something in the meantime
Expand Down

0 comments on commit 8eddf03

Please sign in to comment.