diff --git a/cmd/bot/main.go b/cmd/bot/main.go index c74a241..1bca308 100644 --- a/cmd/bot/main.go +++ b/cmd/bot/main.go @@ -8,7 +8,6 @@ import ( "time" "github.com/gempir/go-twitch-irc/v3" - "github.com/go-co-op/gocron" "github.com/joho/godotenv" _ "github.com/lib/pq" "github.com/lyx0/nourybot/internal/data" @@ -136,17 +135,11 @@ func main() { // Join the channels in the database. app.InitialJoin() + app.InitialTimers() + common.Send("nourylul", "dankCircle", app.TwitchClient) }) - s := gocron.NewScheduler(time.UTC) - s.Cron("*/5 * * * *").Do(func() { // Every 5 minutes - tc.Say("nourylul", "WeirdDoc") - tc.Say("nourybot", "gopherDance") - }) - - s.StartAsync() - // Actually connect to chat. err = app.TwitchClient.Connect() if err != nil { diff --git a/cmd/bot/timer.go b/cmd/bot/timer.go index 2c3d605..99c802e 100644 --- a/cmd/bot/timer.go +++ b/cmd/bot/timer.go @@ -3,8 +3,10 @@ package main import ( "fmt" "strings" + "time" "github.com/gempir/go-twitch-irc/v3" + "github.com/go-co-op/gocron" "github.com/lyx0/nourybot/internal/data" "github.com/lyx0/nourybot/pkg/common" ) @@ -49,3 +51,37 @@ func (app *Application) AddTimer(name string, message twitch.PrivateMessage) { return } } + +// InitialJoin is called on startup and queries the database for a list of +// channels which the TwitchClient then joins. +func (app *Application) InitialTimers() { + // GetJoinable returns a slice of channel names. + timer, err := app.Models.Timers.GetAll() + if err != nil { + app.Logger.Error(err) + return + } + + app.Logger.Info(timer) + + s := gocron.NewScheduler(time.UTC) + // Iterate over the slice of channels and join each. + for _, v := range timer { + s.TagsUnique() + app.Logger.Infow("Initial timers:", + "Name", v.Name, + "Channel", v.Channel, + "Text", v.Text, + "Repeat", v.Repeat, + "V", v, + ) + + s.Tag("pipelines", fmt.Sprintf("%s-%s", v.Channel, v.Name)).Every(v.Repeat).StartAt(time.Now()).Do(app.xD, v.Channel, v.Text) + + } + s.StartAsync() +} + +func (app *Application) xD(a, b string) { + common.Send(a, b, app.TwitchClient) +} diff --git a/internal/data/models.go b/internal/data/models.go index ba74699..66dd08d 100644 --- a/internal/data/models.go +++ b/internal/data/models.go @@ -40,6 +40,7 @@ type Models struct { Timers interface { Get(name string) (*Timer, error) Insert(timer *Timer) error + GetAll() ([]*Timer, error) } } diff --git a/internal/data/timers.go b/internal/data/timers.go index 4e837b9..6c40f84 100644 --- a/internal/data/timers.go +++ b/internal/data/timers.go @@ -1,8 +1,10 @@ package data import ( + "context" "database/sql" "errors" + "time" ) type Timer struct { @@ -71,3 +73,57 @@ func (t TimerModel) Insert(timer *Timer) error { return nil } + +// GetAll() returns a pointer to a slice of all channels (`[]*Channel`) in the database. +func (t TimerModel) GetAll() ([]*Timer, error) { + query := ` + SELECT id, name, text, channel, repeat + FROM timers + ORDER BY id` + + // Create a context with 3 seconds timeout. + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + // Use QueryContext() the context and query. This returns a + // sql.Rows resultset containing our channels. + rows, err := t.DB.QueryContext(ctx, query) + if err != nil { + return nil, err + } + + // Need to defer a call to rows.Close() to ensure the resultset + // is closed before GetAll() returns. + defer rows.Close() + + // Initialize an empty slice to hold the data. + timers := []*Timer{} + + // Iterate over the resultset. + for rows.Next() { + // Initialize an empty Channel struct where we put on + // a single channel value. + var timer Timer + + // Scan the values onto the channel struct + err := rows.Scan( + &timer.ID, + &timer.Name, + &timer.Text, + &timer.Channel, + &timer.Repeat, + ) + if err != nil { + return nil, err + } + // Add the single movie struct onto the slice. + timers = append(timers, &timer) + } + + // When rows.Next() finishes call rows.Err() to retrieve any errors. + if err = rows.Err(); err != nil { + return nil, err + } + + return timers, nil +}