package dbengine import ( "context" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "nilfm.cc/git/felt/models" "time" ) const errNoCollection string = "collection not found: felt.%s" const errNoDocument string = "document with name/id '%s' doesn't exist in collection: %s" const errNotAString string = "document property is not a string: %s.%s" type DbAdapter interface { Init(mongoUri string) error CreateTable(table models.TableKey) error DestroyTable(table models.TableKey) error InsertDiceRoll(table models.TableKey, diceRoll models.DiceRoll) error GetDiceRolls(table models.TableKey) ([]models.DiceRoll, error) SetMapImageUrl(table models.TableKey, url string) error GetMapImageUrl(table models.TableKey) (string, error) AddToken(table models.TableKey, token models.Token) error RemoveToken(table models.TableKey, tokenId string) error ModifyToken(table models.TableKey, token models.Token) error GetTokens(table models.TableKey) ([]models.Token, error) } type DbEngine struct { client mongo.Client } func (self *DbEngine) mkCtx(timeoutSec int) context.Context { return context.WithTimeout(context.Background(), 10*time.Second) } func (self *DbEngine) Init(mongoUri string) error { client, err := mongo.NewClient(options.Client().ApplyURI(mongoUri)) if err != nil { return err } self.client = client ctx, _ := self.mkCtx(10) err = client.Connect(ctx) if err != nil { return err } defer client.Disconnect(ctx) db := client.Database("felt") err = self.ensureCollections(db) return err } func (self *DbEngine) ensureCollections(db mongo.Database) error { tables := db.Collection("tables") if tables == nil { createCmd := bson.D{ {"create", "tables"}, {"clusteredIndex", { {"key", {"name"}}, {"unique", true}, {"name", "idx_tables_unique_names"}, }}, } var createResult bson.M err := db.RunCommand( self.mkCtx(10), createCmd).Decode(&createResult) if err != nil { return err } } return nil } func (self *DbEngine) CreateTable(table models.TableKey) error { tables := self.db.Collection("tables") if tables != nil { _, err := tables.InsertOne(self.mkCtx(10), bson.D{ {"name", table.Name}, {"passcode", table.Passcode}, {"mapUri", ""}, {"diceRolls", bson.A{}}, {"tokens", bson.A{}}, }) return err } return errors.New(fmt.Sprintf(errNoCollection, "tables")) } func (self *DbEngine) SetMapImageUrl(table models.TableKey, url string) error { tables := self.db.Collection("tables") if tables != nil { _, err := tables.UpdateOne( self.mkCtx(10), bson.D{ {"name", table.Name}, {"passcode", table.Passcode}, }, bson.D{ {"mapImageUrl", url}, }, ) return err } return errors.New(fmt.Sprintf(errNoCollection, "tables")) } func (self *DbEngine) GetMapImageUrl(table models.TableKey) (string, error) { tables := self.db.Collection("tables") if tables != nil { fromDb := tables.FindOne( self.mkCtx(10), bson.D{ {"name", table.Name}, {"passcode", table.Passcode}, }) if fromDb != nil { url, ok := fromDb.Lookup("mapUri").StringValueOK() if ok { return url, nil } else { return "", errors.New(fmt.Sprintf(errNotAString, "table", table.Name, "mapUri")) } } else { return "", errors.New(fmt.Sprintf(errNoDocument, table.Name, "tables")) } } return "", errors.New(fmt.Sprintf(errNoCollection, "tables")) }