diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38b8aab --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.gocache \ No newline at end of file diff --git a/jobs/clan_monitor_job.go b/jobs/clan_monitor_job.go index b171bf2..595d578 100644 --- a/jobs/clan_monitor_job.go +++ b/jobs/clan_monitor_job.go @@ -35,6 +35,7 @@ type ClanMonitorJob struct { recipientID string clashClient *clash.Client discordClient *discord.Client + notified map[string]time.Time } func newClanMonitorJobFromEnv() (*ClanMonitorJob, error) { @@ -63,6 +64,7 @@ func newClanMonitorJobFromEnv() (*ClanMonitorJob, error) { recipientID: recipientID, clashClient: clash.NewClient(clashToken), discordClient: discord.NewClient(discordToken), + notified: make(map[string]time.Time), }, nil } @@ -107,7 +109,24 @@ func (j *ClanMonitorJob) Run(ctx context.Context) error { return inactive[i].InactiveFor > inactive[j].InactiveFor }) - messages := buildMessages(inactive) + j.purgeResolved(inactive) + + var newlyInactive []inactiveMember + for _, member := range inactive { + if _, alreadyNotified := j.notified[member.Tag]; alreadyNotified { + continue + } + + newlyInactive = append(newlyInactive, member) + j.notified[member.Tag] = time.Now() + log.Printf("clan monitor: notifying inactivity for %s (%s); offline %s", member.Name, member.Tag, formatDuration(member.InactiveFor)) + } + + if len(newlyInactive) == 0 { + return nil + } + + messages := buildMessages(newlyInactive) for _, message := range messages { if err := j.discordClient.SendDM(ctx, j.recipientID, message); err != nil { @@ -123,6 +142,19 @@ type inactiveMember struct { InactiveFor time.Duration } +func (j *ClanMonitorJob) purgeResolved(inactive []inactiveMember) { + active := make(map[string]struct{}, len(inactive)) + for _, member := range inactive { + active[member.Tag] = struct{}{} + } + + for tag := range j.notified { + if _, stillInactive := active[tag]; !stillInactive { + delete(j.notified, tag) + } + } +} + func buildMessages(members []inactiveMember) []string { header := fmt.Sprintf("Clan members inactive ≥ %s\n", formatDuration(offlineThreshold)) var chunks []string