subscribe-bot/db/db.go

168 lines
3.8 KiB
Go
Raw Normal View History

2020-10-12 13:47:28 +00:00
package db
2020-10-11 19:32:58 +00:00
// Database is laid out like this:
// mapper/<mapper_id>/trackers/<channel_id> -> priority
// mapper/<mapper_id>/latestEvent
// channel/<channel_id>/tracks/<mapper_id> -> priority
import (
"strconv"
2021-07-21 22:09:06 +00:00
"github.com/pkg/errors"
2020-10-11 19:32:58 +00:00
bolt "go.etcd.io/bbolt"
2021-07-21 22:09:06 +00:00
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/clause"
2020-10-12 14:26:39 +00:00
"subscribe-bot/osuapi"
2020-10-11 19:32:58 +00:00
)
var (
LATEST_EVENT = []byte("latestEvent")
2020-10-14 19:33:23 +00:00
MAPPERS = []byte("mapper")
CHANNELS = []byte("channels")
2020-10-11 19:32:58 +00:00
)
type Db struct {
2021-07-21 22:09:06 +00:00
gorm *gorm.DB
api *osuapi.Osuapi
2020-10-11 19:32:58 +00:00
}
2020-10-12 13:47:28 +00:00
func OpenDb(path string, api *osuapi.Osuapi) (db *Db, err error) {
2021-07-21 22:09:06 +00:00
gorm, err := gorm.Open(sqlite.Open(path), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// auto-migrate
gorm.AutoMigrate(&Config{})
gorm.AutoMigrate(&User{})
gorm.AutoMigrate(&Beatmapset{})
gorm.AutoMigrate(&DiscordChannel{})
db = &Db{gorm, api}
2020-10-11 19:32:58 +00:00
return
}
// Loop over channels that are tracking this specific mapper
2021-07-21 22:09:06 +00:00
func (db *Db) IterTrackingChannels(mapperId int, fn func(channel DiscordChannel) error) (err error) {
var channels []DiscordChannel
db.gorm.Model(&User{ID: mapperId}).Association("TrackingChannels").Find(&channels)
for _, channel := range channels {
fn(channel)
}
2020-10-11 19:32:58 +00:00
return
}
2020-10-14 19:33:23 +00:00
// Loop over tracked mappers for this channel
2021-07-21 22:09:06 +00:00
func (db *Db) IterChannelTrackedMappers(channelId string, fn func(user User) error) (err error) {
var mappers []User
db.gorm.Model(&DiscordChannel{ID: channelId}).Association("TrackedMappers").Find(&mappers)
for _, mapper := range mappers {
fn(mapper)
}
2020-10-14 19:33:23 +00:00
return
}
// Loop over all tracked mappers
2021-07-21 22:09:06 +00:00
func (db *Db) IterAllTrackedMappers(fn func(user User) error) (err error) {
var mappers []User
db.gorm.Find(&mappers)
for _, mapper := range mappers {
fn(mapper)
}
2020-10-11 19:32:58 +00:00
return
}
2021-07-21 22:09:06 +00:00
func (db *Db) UpdateMapperLastEvent(userId int, eventId int) (err error) {
if eventId == -1 {
var events []osuapi.Event
events, err = db.api.GetUserEvents(userId, 1, 0)
2020-10-11 19:32:58 +00:00
if err != nil {
2021-07-21 22:09:06 +00:00
err = errors.Wrap(err, "couldn't get user events from API")
return
2020-10-11 19:32:58 +00:00
}
2021-07-21 22:09:06 +00:00
eventId = events[0].ID
}
2020-10-11 19:32:58 +00:00
2021-07-21 22:09:06 +00:00
db.gorm.Model(&User{}).Where("id = ?", userId).Update("latest_event_id", eventId)
return nil
2020-10-11 19:32:58 +00:00
}
// Get the latest event ID of this mapper, if they have one
func (db *Db) MapperLastEvent(userId int) (has bool, id int) {
2021-07-21 22:09:06 +00:00
var user User
db.gorm.Select("latest_event_id").First(&user)
return true, user.LatestEventID
2020-10-11 19:32:58 +00:00
}
// Start tracking a new mapper (if they're not already tracked)
func (db *Db) ChannelTrackMapper(channelId string, mapperId int, priority int) (err error) {
2021-07-21 22:09:06 +00:00
err = db.gorm.Model(&DiscordChannel{ID: channelId}).Association("TrackedMappers").Append(db.getUser(mapperId))
2020-10-11 19:32:58 +00:00
if err != nil {
2021-07-21 22:09:06 +00:00
err = errors.Wrap(err, "could not add tracking for channel "+channelId)
2020-10-11 19:32:58 +00:00
return
}
2021-07-21 22:09:06 +00:00
err = db.UpdateMapperLastEvent(mapperId, -1)
if err != nil {
err = errors.Wrap(err, "could not update mapper latest event")
return
}
return nil
2020-10-11 19:32:58 +00:00
}
func (db *Db) Close() {
2021-07-21 22:09:06 +00:00
}
func (db *Db) getUser(userId int) (user *User, err error) {
// TODO: cache user info for some time?
apiUser, err := db.api.GetUser(strconv.Itoa(userId))
if err != nil {
err = errors.Wrap(err, "could not retrieve user from the API")
return
}
user = &User{
ID: userId,
Username: apiUser.Username,
Country: apiUser.CountryCode,
}
db.gorm.Clauses(clause.OnConflict{UpdateAll: true}).Create(user)
return
2020-10-11 19:32:58 +00:00
}
func getMapper(tx *bolt.Tx, userId int) (mapper *bolt.Bucket) {
2020-10-14 19:33:23 +00:00
mappers := tx.Bucket(MAPPERS)
2020-10-11 19:32:58 +00:00
if mappers == nil {
return nil
}
mapper = mappers.Bucket([]byte(strconv.Itoa(userId)))
if mapper == nil {
return nil
}
return
}
func getMapperMut(tx *bolt.Tx, userId int) (mapper *bolt.Bucket, err error) {
2020-10-14 19:33:23 +00:00
mappers, err := tx.CreateBucketIfNotExists(MAPPERS)
2020-10-11 19:32:58 +00:00
if err != nil {
return
}
mapper, err = mappers.CreateBucketIfNotExists([]byte(strconv.Itoa(userId)))
if err != nil {
return
}
return
}