Skip to content

Commit

Permalink
Merge pull request #676 from cj123/schedule-event-fix
Browse files Browse the repository at this point in the history
Schedule event fix
  • Loading branch information
cj123 authored Dec 16, 2019
2 parents 6b7f367 + 32f074f commit 3e567e7
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 50 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Added:
Fixes:

* Fixed an issue with filtering from results files in Race Weekends when the Race Weekend is within a Championship.
* We've changed the method that we use to check if scheduled events need running. Hopefully this should make scheduled events more reliable!

---

Expand Down
37 changes: 23 additions & 14 deletions championship_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"time"

"github.com/cj123/assetto-server-manager/pkg/udp"
"github.com/cj123/assetto-server-manager/pkg/when"

"github.com/cj123/caldav-go/icalendar"
"github.com/cj123/caldav-go/icalendar/components"
Expand All @@ -32,8 +33,8 @@ type ChampionshipManager struct {
activeChampionship *ActiveChampionship
mutex sync.Mutex

championshipEventStartTimers map[string]*time.Timer
championshipEventReminderTimers map[string]*time.Timer
championshipEventStartTimers map[string]*when.Timer
championshipEventReminderTimers map[string]*when.Timer
}

func NewChampionshipManager(raceManager *RaceManager) *ChampionshipManager {
Expand Down Expand Up @@ -658,8 +659,6 @@ func (cm *ChampionshipManager) ScheduleEvent(championshipID string, eventID stri
}

// add a scheduled event on date
duration := time.Until(date)

if recurrence != "already-set" {
if recurrence != "" {
err := event.SetRecurrenceRule(recurrence)
Expand All @@ -683,20 +682,23 @@ func (cm *ChampionshipManager) ScheduleEvent(championshipID string, eventID stri
}
}

cm.championshipEventStartTimers[event.ID.String()] = time.AfterFunc(duration, func() {
cm.championshipEventStartTimers[event.ID.String()], err = when.When(date, func() {
err := cm.StartScheduledEvent(championship, event)

if err != nil {
logrus.WithError(err).Errorf("couldn't start scheduled championship event")
}
})

if err != nil {
return err
}

if cm.notificationManager.HasNotificationReminders() {
for _, timer := range cm.notificationManager.GetNotificationReminders() {
duration = time.Until(date.Add(time.Duration(0-timer) * time.Minute))
thisTimer := timer

cm.championshipEventReminderTimers[event.ID.String()] = time.AfterFunc(duration, func() {
cm.championshipEventReminderTimers[event.ID.String()], err = when.When(date.Add(time.Duration(0-timer)*time.Minute), func() {
cm.notificationManager.SendChampionshipReminderMessage(championship, event, thisTimer)
})
}
Expand Down Expand Up @@ -1602,8 +1604,8 @@ func (cm *ChampionshipManager) HandleChampionshipSignUp(r *http.Request) (respon
}

func (cm *ChampionshipManager) InitScheduledChampionships() error {
cm.championshipEventStartTimers = make(map[string]*time.Timer)
cm.championshipEventReminderTimers = make(map[string]*time.Timer)
cm.championshipEventStartTimers = make(map[string]*when.Timer)
cm.championshipEventReminderTimers = make(map[string]*when.Timer)
championships, err := cm.ListChampionships()

if err != nil {
Expand All @@ -1622,26 +1624,33 @@ func (cm *ChampionshipManager) InitScheduledChampionships() error {

if event.Scheduled.After(time.Now()) {
// add a scheduled event on date
duration := time.Until(event.Scheduled)

cm.championshipEventStartTimers[event.ID.String()] = time.AfterFunc(duration, func() {
cm.championshipEventStartTimers[event.ID.String()], err = when.When(event.Scheduled, func() {
err := cm.StartScheduledEvent(championship, event)

if err != nil {
logrus.WithError(err).Errorf("couldn't start scheduled championship event")
}
})

if err != nil {
logrus.WithError(err).Errorf("Could not schedule event: %s", event.ID.String())
continue
}

if cm.notificationManager.HasNotificationReminders() {
for _, timer := range cm.notificationManager.GetNotificationReminders() {
if event.Scheduled.Add(time.Duration(0-timer) * time.Minute).After(time.Now()) {
// add reminder
duration = time.Until(event.Scheduled.Add(time.Duration(0-timer) * time.Minute))
thisTimer := timer

cm.championshipEventReminderTimers[event.ID.String()] = time.AfterFunc(duration, func() {
cm.championshipEventReminderTimers[event.ID.String()], err = when.When(event.Scheduled.Add(time.Duration(0-timer)*time.Minute), func() {
cm.notificationManager.SendChampionshipReminderMessage(championship, event, thisTimer)
})

if err != nil {
logrus.WithError(err).Errorf("Could not schedule event: %s", event.ID.String())
continue
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion championships_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sort"
"time"

"4d63.com/tz"
"github.com/go-chi/chi"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -368,7 +369,7 @@ func (ch *ChampionshipsHandler) scheduleEvent(w http.ResponseWriter, r *http.Req
timeString := r.FormValue("event-schedule-time")
timezone := r.FormValue("event-schedule-timezone")

location, err := time.LoadLocation(timezone)
location, err := tz.LoadLocation(timezone)

if err != nil {
logrus.WithError(err).Errorf("could not find location: %s", location)
Expand Down
6 changes: 5 additions & 1 deletion cmd/server-manager/typescript/sass/_calendar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@

.pl-4-5 {
padding-left: 2rem!important;
}
}

.fc-today {
background: #9ec6f5;
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/cj123/assetto-server-manager

require (
4d63.com/tz v1.1.0
github.com/Clinet/discordgo-embed v0.0.0-20190411043415-d754bc1a576c
github.com/Masterminds/goutils v1.1.0 // indirect
github.com/Masterminds/semver v1.4.2
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
4d63.com/embedfiles v0.0.0-20190311033909-995e0740726f h1:oyYjGRBNq1TxAIG8aHqtxlvqUfzdZf+MbcRb/oweNfY=
4d63.com/embedfiles v0.0.0-20190311033909-995e0740726f/go.mod h1:HxEsUxoVZyRxsZML/S6e2xAuieFMlGO0756ncWx1aXE=
4d63.com/tz v1.1.0 h1:Hi58WbeFjiUH4XOWuCpl5iSzuUuw1axZzTqIfMKPKrg=
4d63.com/tz v1.1.0/go.mod h1:SHGqVdL7hd2ZaX2T9uEiOZ/OFAUfCCLURdLPJsd8ZNs=
github.com/Clinet/discordgo-embed v0.0.0-20190411043415-d754bc1a576c h1:XB4X3MWxiq+Tb0lmc6CY1S9t5sJG1zFCrfpGQuKEGFc=
github.com/Clinet/discordgo-embed v0.0.0-20190411043415-d754bc1a576c/go.mod h1:0ydUl+01209LCyzJk68BeRtCN1IMrNJgX4IBmwmC1f8=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
Expand Down
78 changes: 78 additions & 0 deletions pkg/when/when.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package when

import (
"errors"
"sync"
"time"

"github.com/sirupsen/logrus"
)

var (
// Resolution is how often each When is checked.
Resolution = time.Second

timers = make(map[*Timer]bool)
mutex = sync.Mutex{}
once = sync.Once{}
)

type Timer struct {
fn func()
t time.Time
}

func newTimer(t time.Time, fn func()) *Timer {
r := &Timer{
t: t,
fn: fn,
}

return r
}

func (t *Timer) Stop() {
mutex.Lock()
delete(timers, t)
mutex.Unlock()
}

var ErrTimeInPast = errors.New("when: time specified is in the past")

func When(t time.Time, fn func()) (*Timer, error) {
if t.Before(time.Now()) {
return nil, ErrTimeInPast
}

once.Do(func() {
go func() {
ticker := time.NewTicker(Resolution)

for tick := range ticker.C {
var toStop []*Timer

mutex.Lock()
for timer := range timers {
if tick.Round(Resolution).Equal(timer.t.Round(Resolution)) || tick.Round(Resolution).After(timer.t.Round(Resolution)) {
logrus.Debugf("Starting scheduled event (is now %s)", timer.t)
go timer.fn()
toStop = append(toStop, timer)
}
}
mutex.Unlock()

for _, timer := range toStop {
timer.Stop()
}
}
}()
})

x := newTimer(t, fn)

mutex.Lock()
timers[x] = true
mutex.Unlock()

return x, nil
}
3 changes: 2 additions & 1 deletion race_custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"time"

"4d63.com/tz"
"github.com/go-chi/chi"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -182,7 +183,7 @@ func (crh *CustomRaceHandler) schedule(w http.ResponseWriter, r *http.Request) {
timeString := r.FormValue("event-schedule-time")
timezone := r.FormValue("event-schedule-timezone")

location, err := time.LoadLocation(timezone)
location, err := tz.LoadLocation(timezone)

if err != nil {
logrus.WithError(err).Errorf("could not find location: %s", location)
Expand Down
Loading

0 comments on commit 3e567e7

Please sign in to comment.