diff --git a/cmd/modlastfm/main.go b/cmd/modlastfm/main.go index ade1ee224c26087cb210bc721f45358c4cc97325..a4dac13681d5f82d931313517bb89ac432668d85 100644 --- a/cmd/modlastfm/main.go +++ b/cmd/modlastfm/main.go @@ -6,6 +6,7 @@ import ( "github.com/boltdb/bolt" "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/gauntlet" + "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/store" "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/util" ) @@ -13,35 +14,25 @@ func main() { log.Println("Initialising stella-irc Last.fm module, hold tight...") config := util.NewConfig() - db, err := bolt.Open(config.DBPath, 0600, nil) if err != nil { log.Fatalf("Could not open database: %s", err.Error()) } + st, err := store.NewBoltStore(db) + + if err != nil { + log.Fatalf("Error initialising database: %s", err.Error()) + } + // initialise commands - gauntlet.New(config, db) + gauntlet.New(config, st) - out := gauntlet.Run("ne7split", `artist Begrime Exemious`) + // TODO: collect this from IRC input + out := gauntlet.Run("Mike", `l`, st) if out != "" { log.Println(out) } - - /* - st, err := store.NewBoltStore(db) - - if err != nil { - log.Fatalf("Error initialising database: %s", err.Error()) - } - - inputChannel := make(chan *input.Message) - - input.Watch(inputChannel, func(m *input.Message) { - if m != nil { - log.Println(m) - } - }) - */ } diff --git a/internal/app/modlastfm/command/init.go b/internal/app/modlastfm/command/init.go index cdfcf2b2f2eee6a65bb813edc8a49ac4d21b0ec1..798609695b54226e0dee1870e38d145f046cb8a2 100644 --- a/internal/app/modlastfm/command/init.go +++ b/internal/app/modlastfm/command/init.go @@ -4,9 +4,9 @@ import ( "fmt" "strconv" - "github.com/boltdb/bolt" "github.com/n7st/lastfm-go/lastfm" + "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/store" "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/util" ) @@ -17,7 +17,7 @@ type ( type Fn struct { Config *util.Config - DB *bolt.DB + Store *store.BoltStore LastFM *lastfm.Api } diff --git a/internal/app/modlastfm/command/user.go b/internal/app/modlastfm/command/user.go index f12713ecbff198ffb99da62f74765965d41deb2a..34ff6ee1f649fe4c2ed729fb18db4157ae6d5c89 100644 --- a/internal/app/modlastfm/command/user.go +++ b/internal/app/modlastfm/command/user.go @@ -14,6 +14,26 @@ const ( noTopArtistsForPeriodF = "%s has no listening data for this period" ) +func (f *Fn) SetUser(message string) string { + var err error + + if message == "" { + err = f.Store.RemoveAssociatedUser("Mike") + + return "Last.fm username unset" + } + + args := strings.Split(message, " ") + + err = f.Store.SetAssociatedUser("Mike", args[0]) + + if err != nil { + return fmtError(err) + } + + return fmt.Sprintf("Last.fm username set to %s", args[0]) +} + func (f *Fn) NowPlaying(message string, username string) string { resp, err := f.LastFM.User.GetRecentTracks(lastfm.P{ "autocorrect": 1, diff --git a/internal/app/modlastfm/gauntlet/run.go b/internal/app/modlastfm/gauntlet/run.go index 1a5f050947148cb2fcbbc0ab2a0ae2fe444622a3..71fb6b13d094c494e0989693425c567c7e9362b0 100644 --- a/internal/app/modlastfm/gauntlet/run.go +++ b/internal/app/modlastfm/gauntlet/run.go @@ -1,9 +1,10 @@ package gauntlet import ( + "fmt" + "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/store" "strings" - "github.com/boltdb/bolt" "github.com/n7st/lastfm-go/lastfm" "git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/command" @@ -20,10 +21,10 @@ var ( // sets up fn commands (which contain the configuration, database and an // instance of shkh/lastfm-go/lastfm) -func New(c *util.Config, db *bolt.DB) { +func New(c *util.Config, store *store.BoltStore) { var fn = command.Fn{ Config: c, - DB: db, + Store: store, LastFM: lastfm.New(c.APIKey, c.APISecret), } @@ -41,18 +42,27 @@ func New(c *util.Config, db *bolt.DB) { } openCommands = map[string]command.OpenFnCommand{ - "artist": fn.ArtistInfo, - "band": fn.ArtistInfo, + "artist": fn.ArtistInfo, + "band": fn.ArtistInfo, + "setuser": fn.SetUser, } } // Run() attempts to run a command with the given user input -func Run(username string, message string) string { +func Run(nickname string, message string, db *store.BoltStore) string { var arguments = strings.Split(message, " ") userFnCommand := userCommands[arguments[0]] if userFnCommand != nil { + username, err := db.GetAssociatedUser(nickname) + + if err != nil || username == "" { + return fmt.Sprintf("No Last.fm username found for %s. Set one with setuser ", + nickname, + ) + } + return userFnCommand(strings.Join(arguments[1:], " "), username) } diff --git a/internal/app/modlastfm/input/watcher.go b/internal/app/modlastfm/input/watcher.go deleted file mode 100644 index 495843ce92f577377b6c19aa73c69783f526b822..0000000000000000000000000000000000000000 --- a/internal/app/modlastfm/input/watcher.go +++ /dev/null @@ -1,12 +0,0 @@ -package input - -type Message struct { - Raw string - Target string -} - -func Watch(channel chan *Message, sendFunc func(*Message)) { - for msg := range channel { - sendFunc(msg) - } -} diff --git a/internal/app/modlastfm/store/bolt.go b/internal/app/modlastfm/store/bolt.go index 5cc798d87cdfb9122b17a55d32379466e2e089d0..30e440733acb95e47b2a3f0711ad2c138ca9309b 100644 --- a/internal/app/modlastfm/store/bolt.go +++ b/internal/app/modlastfm/store/bolt.go @@ -1,8 +1,13 @@ package store -import "github.com/boltdb/bolt" +import ( + "github.com/boltdb/bolt" +) -const userBucketKey = "user" +const ( + userBucketKey = "user" + noUserBucketErr = "DB error: no user bucket" +) type BoltStore struct { db *bolt.DB @@ -12,7 +17,6 @@ type BoltStore struct { // member func NewBoltStore(db *bolt.DB) (*BoltStore, error) { st := &BoltStore{db: db} - err := st.init() if err != nil { @@ -22,6 +26,54 @@ func NewBoltStore(db *bolt.DB) (*BoltStore, error) { return st, err } +// SetAssociatedUser() sets an associated Last.fm user against an IRC nickname +func (b *BoltStore) SetAssociatedUser(nickname string, username string) error { + err := b.db.Update(func(tx *bolt.Tx) error { + userBucket := tx.Bucket([]byte(userBucketKey)) + + if userBucket == nil { + panic(noUserBucketErr) + } + + return userBucket.Put([]byte(nickname), []byte(username)) + }) + + return err +} + +// GetAssociatedUser() gets an associated Last.fm username for an IRC nickname +func (b *BoltStore) GetAssociatedUser(nickname string) (string, error) { + var username []byte + + err := b.db.View(func(tx *bolt.Tx) error { + userBucket := tx.Bucket([]byte(userBucketKey)) + + if userBucket == nil { + panic(noUserBucketErr) + } + + username = userBucket.Get([]byte(nickname)) + + return nil + }) + + return string(username), err +} + +// RemoveAssociatedUser() deletes a username set against a nickname (woo, GDPR +// compliance!) +func (b *BoltStore) RemoveAssociatedUser(nickname string) error { + return b.db.Update(func (tx *bolt.Tx) error { + userBucket := tx.Bucket([]byte(userBucketKey)) + + if userBucket == nil { + panic(noUserBucketErr) + } + + return userBucket.Delete([]byte(nickname)) + }) +} + // init() initialises the database with the required buckets func (b *BoltStore) init() error { return b.db.Update(func(tx *bolt.Tx) error { @@ -29,4 +81,4 @@ func (b *BoltStore) init() error { return err }) -} +} \ No newline at end of file