From 4cf9c3295f7429112163c30f0814c1b421ebe547 Mon Sep 17 00:00:00 2001 From: Atridad Lahiji Date: Fri, 22 Nov 2024 17:04:33 -0600 Subject: [PATCH] HIMBOT RETURNS --- .env.example | 1 + command/himbucks.go | 97 ++++++++++++++---------------- lib/db.go | 29 ++------- lib/himbucks.go | 142 ++++++++++++++++++++------------------------ main.go | 37 +++++------- 5 files changed, 132 insertions(+), 174 deletions(-) diff --git a/.env.example b/.env.example index 21acad3..acd882c 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ # Tokens DISCORD_TOKEN="" +ROOT_DIR="" diff --git a/command/himbucks.go b/command/himbucks.go index 794b193..49ef33e 100644 --- a/command/himbucks.go +++ b/command/himbucks.go @@ -22,15 +22,6 @@ func BalanceGetCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (st return fmt.Sprintf("💸 You have %d Himbucks! 💸", balance), nil } -func BalanceSyncCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (string, error) { - syncError := lib.SyncBalance() - if syncError != nil { - return "", syncError - } - - return fmt.Sprintf("💸 Force-Synchronized Himbucks! 💸"), nil -} - func LeaderboardCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (string, error) { entries, err := lib.GetLeaderboard(i.GuildID, 10) if err != nil { @@ -51,48 +42,48 @@ func LeaderboardCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (s } func BalanceSendCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (string, error) { - options := i.ApplicationCommandData().Options - - // Discord handles the user mention/tag and provides the correct user ID - var recipientID string - var amount int - - for _, opt := range options { - switch opt.Name { - case "user": - recipientID = opt.UserValue(nil).ID - case "amount": - amount = int(opt.IntValue()) - } - } - - // Validate amount - if amount <= 0 { - return "", fmt.Errorf("amount must be positive") - } - - // Get sender's info - sender, err := lib.GetUser(i) - if err != nil { - return "", fmt.Errorf("failed to get sender info: %w", err) - } - - // Don't allow sending to self - if sender.ID == recipientID { - return "", fmt.Errorf("you cannot send himbucks to yourself") - } - - // Get recipient's info - recipient, err := s.User(recipientID) - if err != nil { - return "", fmt.Errorf("failed to get recipient info: %w", err) - } - - // Send the himbucks - err = lib.SendBalance(sender.ID, recipientID, i.GuildID, amount) - if err != nil { - return "", fmt.Errorf("failed to send himbucks: %w", err) - } - - return fmt.Sprintf("💸 Successfully sent %d Himbucks to %s! 💸", amount, recipient.Username), nil + options := i.ApplicationCommandData().Options + + // Discord handles the user mention/tag and provides the correct user ID + var recipientID string + var amount int + + for _, opt := range options { + switch opt.Name { + case "user": + recipientID = opt.UserValue(nil).ID + case "amount": + amount = int(opt.IntValue()) + } + } + + // Validate amount + if amount <= 0 { + return "", fmt.Errorf("amount must be positive") + } + + // Get sender's info + sender, err := lib.GetUser(i) + if err != nil { + return "", fmt.Errorf("failed to get sender info: %w", err) + } + + // Don't allow sending to self + if sender.ID == recipientID { + return "", fmt.Errorf("you cannot send himbucks to yourself") + } + + // Get recipient's info + recipient, err := s.User(recipientID) + if err != nil { + return "", fmt.Errorf("failed to get recipient info: %w", err) + } + + // Send the himbucks + err = lib.SendBalance(sender.ID, recipientID, i.GuildID, amount) + if err != nil { + return "", fmt.Errorf("failed to send himbucks: %w", err) + } + + return fmt.Sprintf("💸 Successfully sent %d Himbucks to %s! 💸", amount, recipient.Username), nil } diff --git a/lib/db.go b/lib/db.go index a896ef4..968941d 100644 --- a/lib/db.go +++ b/lib/db.go @@ -17,35 +17,16 @@ var DBClient *sql.DB var DBConnector *libsql.Connector func InitDB() error { - dbUrl := os.Getenv("DATABASE_URL") - dbToken := os.Getenv("DATABASE_AUTH_TOKEN") - - if dbUrl == "" || dbToken == "" { - return fmt.Errorf("database configuration missing") - } - // Determine DB path based on /data directory existence - dbPath := "himbot.db" // default to local - if _, err := os.Stat("/data"); !os.IsNotExist(err) { - dbPath = "/data/himbot.db" - } + dbName := "file:./himbot.db" - connector, connectorError := libsql.NewEmbeddedReplicaConnector( - dbPath, - dbUrl, - libsql.WithAuthToken(dbToken), - ) - - if connectorError != nil { - fmt.Fprintf(os.Stderr, "failed to open db %s: %s", dbUrl, connectorError) + db, err := sql.Open("libsql", dbName) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to open db %s", err) os.Exit(1) } - // finalDBUrl := fmt.Sprintf("%s?authToken=%s", dbUrl, dbToken) - client := sql.OpenDB(connector) - - DBClient = client - DBConnector = connector + DBClient = db return runMigrations() } diff --git a/lib/himbucks.go b/lib/himbucks.go index c65210c..0500376 100644 --- a/lib/himbucks.go +++ b/lib/himbucks.go @@ -85,98 +85,88 @@ func GetBalance(discordID, guildID string) (int, error) { } func SendBalance(fromDiscordID, toDiscordID, guildID string, amount int) error { - // Start database transaction - tx, err := DBClient.Begin() - if err != nil { - return fmt.Errorf("failed to start transaction: %w", err) - } - defer tx.Rollback() + // Start database transaction + tx, err := DBClient.Begin() + if err != nil { + return fmt.Errorf("failed to start transaction: %w", err) + } + defer tx.Rollback() - // Get sender's user ID - var fromUserID string - err = tx.QueryRow(` - SELECT id - FROM users + // Get sender's user ID + var fromUserID string + err = tx.QueryRow(` + SELECT id + FROM users WHERE discord_id = ?`, fromDiscordID).Scan(&fromUserID) - if err != nil { - return fmt.Errorf("sender not found: %w", err) - } + if err != nil { + return fmt.Errorf("sender not found: %w", err) + } - // Get recipient's user ID - var toUserID string - err = tx.QueryRow(` - SELECT id - FROM users + // Get recipient's user ID + var toUserID string + err = tx.QueryRow(` + SELECT id + FROM users WHERE discord_id = ?`, toDiscordID).Scan(&toUserID) - if err != nil { - return fmt.Errorf("recipient not found: %w", err) - } + if err != nil { + return fmt.Errorf("recipient not found: %w", err) + } - // Check if sender has sufficient balance - var senderBalance int - err = tx.QueryRow(` - SELECT currency_balance - FROM guild_profiles + // Check if sender has sufficient balance + var senderBalance int + err = tx.QueryRow(` + SELECT currency_balance + FROM guild_profiles WHERE user_id = ? AND guild_id = ?`, - fromUserID, guildID).Scan(&senderBalance) - if err != nil { - return fmt.Errorf("failed to get sender balance: %w", err) - } + fromUserID, guildID).Scan(&senderBalance) + if err != nil { + return fmt.Errorf("failed to get sender balance: %w", err) + } - if senderBalance < amount { - return fmt.Errorf("insufficient balance: have %d, trying to send %d", senderBalance, amount) - } + if senderBalance < amount { + return fmt.Errorf("insufficient balance: have %d, trying to send %d", senderBalance, amount) + } - // Deduct from sender - _, err = tx.Exec(` - UPDATE guild_profiles - SET currency_balance = currency_balance - ? + // Deduct from sender + _, err = tx.Exec(` + UPDATE guild_profiles + SET currency_balance = currency_balance - ? WHERE user_id = ? AND guild_id = ?`, - amount, fromUserID, guildID) - if err != nil { - return fmt.Errorf("failed to deduct from sender: %w", err) - } + amount, fromUserID, guildID) + if err != nil { + return fmt.Errorf("failed to deduct from sender: %w", err) + } - // Add to recipient - result, err := tx.Exec(` - UPDATE guild_profiles - SET currency_balance = currency_balance + ? + // Add to recipient + result, err := tx.Exec(` + UPDATE guild_profiles + SET currency_balance = currency_balance + ? WHERE user_id = ? AND guild_id = ?`, - amount, toUserID, guildID) - if err != nil { - return fmt.Errorf("failed to add to recipient: %w", err) - } + amount, toUserID, guildID) + if err != nil { + return fmt.Errorf("failed to add to recipient: %w", err) + } - // Check if recipient exists in guild_profiles - rowsAffected, err := result.RowsAffected() - if err != nil { - return fmt.Errorf("failed to check rows affected: %w", err) - } + // Check if recipient exists in guild_profiles + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("failed to check rows affected: %w", err) + } - // If recipient doesn't have a profile in this guild, create one - if rowsAffected == 0 { - _, err = tx.Exec(` + // If recipient doesn't have a profile in this guild, create one + if rowsAffected == 0 { + _, err = tx.Exec(` INSERT INTO guild_profiles (user_id, guild_id, currency_balance, message_count) VALUES (?, ?, ?, 0)`, - toUserID, guildID, amount) - if err != nil { - return fmt.Errorf("failed to create recipient profile: %w", err) - } - } + toUserID, guildID, amount) + if err != nil { + return fmt.Errorf("failed to create recipient profile: %w", err) + } + } - // Commit transaction - if err = tx.Commit(); err != nil { - return fmt.Errorf("failed to commit transaction: %w", err) - } - - return nil -} - -func SyncBalance() error { - _, syncError := DBConnector.Sync() - if syncError != nil { - fmt.Println("Error syncing database:", syncError) - return syncError + // Commit transaction + if err = tx.Commit(); err != nil { + return fmt.Errorf("failed to commit transaction: %w", err) } return nil diff --git a/main.go b/main.go index 20a8de0..3a8a822 100644 --- a/main.go +++ b/main.go @@ -51,28 +51,24 @@ var ( Name: "himboard", Description: "View the himbucks leaderboard", }, - { - Name: "syncbucks", - Description: "Sync your himbucks balance with the database", - }, { Name: "sendbucks", - Description: "Send himbucks to another user", - Options: []*discordgo.ApplicationCommandOption{ - { - Type: discordgo.ApplicationCommandOptionUser, - Name: "user", - Description: "The user to send himbucks to", - Required: true, - }, - { - Type: discordgo.ApplicationCommandOptionInteger, - Name: "amount", - Description: "Amount of himbucks to send", - Required: true, - MinValue: &[]float64{1}[0], - }, - }, + Description: "Send himbucks to another user", + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionUser, + Name: "user", + Description: "The user to send himbucks to", + Required: true, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "amount", + Description: "Amount of himbucks to send", + Required: true, + MinValue: &[]float64{1}[0], + }, + }, }, } @@ -82,7 +78,6 @@ var ( "markov": lib.HandleCommand("markov", 30*time.Second, command.MarkovCommand), "himbucks": lib.HandleCommand("himbucks", 5*time.Second, command.BalanceGetCommand), "himboard": lib.HandleCommand("himboard", 5*time.Second, command.LeaderboardCommand), - "syncbucks": lib.HandleCommand("syncbucks", 1800*time.Second, command.BalanceSyncCommand), "sendbucks": lib.HandleCommand("sendbucks", 1800*time.Second, command.BalanceSendCommand), } )