himbot/lib/himbucks.go

163 lines
4.1 KiB
Go
Raw Normal View History

2024-11-05 00:19:36 -06:00
package lib
import (
"database/sql"
"fmt"
"time"
"github.com/bwmarrin/discordgo"
)
const (
HimbucksPerReward = 10
MessageCountThreshold = 5
CooldownPeriod = time.Minute
)
type HimbucksEntry struct {
Username string
Balance int
MessageCount int
}
func ProcessMessage(s *discordgo.Session, m *discordgo.MessageCreate) error {
// Ignore bot messages
if m.Author.Bot {
return nil
}
2024-11-05 00:42:25 -06:00
// Start transaction for user creation/lookup and himbucks entry
tx, err := DBClient.Begin()
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer tx.Rollback()
2024-11-05 00:39:09 -06:00
// Get user from database, create if doesn't exist
2024-11-05 00:19:36 -06:00
var userID int
2024-11-05 00:42:25 -06:00
err = tx.QueryRow("SELECT id FROM users WHERE discord_id = ?", m.Author.ID).Scan(&userID)
2024-11-05 00:39:09 -06:00
if err == sql.ErrNoRows {
2024-11-05 00:42:25 -06:00
// Store user in database using existing StoreUser function within transaction
result, err := tx.Exec(
"INSERT INTO users (discord_id, username) VALUES (?, ?)",
m.Author.ID, m.Author.Username)
2024-11-05 00:39:09 -06:00
if err != nil {
return fmt.Errorf("failed to store user: %w", err)
2024-11-05 00:28:33 -06:00
}
2024-11-05 00:42:25 -06:00
id, err := result.LastInsertId()
2024-11-05 00:39:09 -06:00
if err != nil {
return fmt.Errorf("failed to get new user ID: %w", err)
}
2024-11-05 00:42:25 -06:00
userID = int(id)
// Immediately create corresponding himbucks entry
_, err = tx.Exec(`
INSERT INTO himbucks (user_id, guild_id, balance, message_count)
VALUES (?, ?, 0, 0)`,
userID, m.GuildID)
if err != nil {
return fmt.Errorf("failed to create initial himbucks entry: %w", err)
}
2024-11-05 00:39:09 -06:00
} else if err != nil {
return fmt.Errorf("failed to query user: %w", err)
2024-11-05 00:19:36 -06:00
}
2024-11-05 00:42:25 -06:00
// For existing users, ensure himbucks entry exists
_, err = tx.Exec(`
2024-11-05 00:39:09 -06:00
INSERT INTO himbucks (user_id, guild_id, balance, message_count)
VALUES (?, ?, 0, 0)
ON CONFLICT (user_id, guild_id) DO NOTHING`,
userID, m.GuildID)
2024-11-05 00:19:36 -06:00
if err != nil {
return fmt.Errorf("failed to create himbucks entry: %w", err)
}
2024-11-05 00:42:25 -06:00
// Process the message count and rewards
2024-11-05 00:19:36 -06:00
var messageCount int
var lastEarnedAt sql.NullTime
err = tx.QueryRow(`
2024-11-05 00:39:09 -06:00
SELECT message_count, last_earned_at
FROM himbucks
WHERE user_id = ? AND guild_id = ?`,
2024-11-05 00:19:36 -06:00
userID, m.GuildID).Scan(&messageCount, &lastEarnedAt)
if err != nil {
return fmt.Errorf("failed to get message count: %w", err)
}
messageCount++
shouldReward := messageCount >= MessageCountThreshold &&
(!lastEarnedAt.Valid || time.Since(lastEarnedAt.Time) >= CooldownPeriod)
if shouldReward {
_, err = tx.Exec(`
2024-11-05 00:39:09 -06:00
UPDATE himbucks
SET balance = balance + ?, message_count = 0, last_earned_at = CURRENT_TIMESTAMP
WHERE user_id = ? AND guild_id = ?`,
2024-11-05 00:19:36 -06:00
HimbucksPerReward, userID, m.GuildID)
} else {
_, err = tx.Exec(`
2024-11-05 00:39:09 -06:00
UPDATE himbucks
SET message_count = ?
WHERE user_id = ? AND guild_id = ?`,
2024-11-05 00:19:36 -06:00
messageCount, userID, m.GuildID)
}
if err != nil {
return fmt.Errorf("failed to update himbucks: %w", err)
}
return tx.Commit()
}
func GetBalance(discordID, guildID string) (int, error) {
var balance int
2024-11-05 12:49:10 -06:00
_, syncError := DBConnector.Sync()
if syncError != nil {
fmt.Println("Error syncing database:", syncError)
}
queryError := DBClient.QueryRow(`
2024-11-05 00:19:36 -06:00
SELECT h.balance
FROM himbucks h
JOIN users u ON h.user_id = u.id
WHERE u.discord_id = ? AND h.guild_id = ?`,
discordID, guildID).Scan(&balance)
2024-11-05 12:49:10 -06:00
if queryError == sql.ErrNoRows {
2024-11-05 00:19:36 -06:00
return 0, nil
}
2024-11-05 12:49:10 -06:00
if queryError != nil {
return 0, fmt.Errorf("failed to get balance: %w", queryError)
2024-11-05 00:19:36 -06:00
}
return balance, nil
}
func GetLeaderboard(guildID string, limit int) ([]HimbucksEntry, error) {
rows, err := DBClient.Query(`
SELECT u.username, h.balance, h.message_count
FROM himbucks h
JOIN users u ON h.user_id = u.id
WHERE h.guild_id = ?
ORDER BY h.balance DESC
LIMIT ?`,
guildID, limit)
if err != nil {
return nil, fmt.Errorf("failed to get leaderboard: %w", err)
}
defer rows.Close()
var entries []HimbucksEntry
for rows.Next() {
var entry HimbucksEntry
err := rows.Scan(&entry.Username, &entry.Balance, &entry.MessageCount)
if err != nil {
return nil, fmt.Errorf("failed to scan leaderboard entry: %w", err)
}
entries = append(entries, entry)
}
return entries, nil
}