242 lines
6.7 KiB
Go
242 lines
6.7 KiB
Go
package chat
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"eq2emu/internal/database"
|
|
)
|
|
|
|
// DatabaseChannelManager implements ChannelDatabase interface using the existing database wrapper
|
|
type DatabaseChannelManager struct {
|
|
db *database.DB
|
|
}
|
|
|
|
// NewDatabaseChannelManager creates a new database channel manager
|
|
func NewDatabaseChannelManager(db *database.DB) *DatabaseChannelManager {
|
|
return &DatabaseChannelManager{
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// LoadWorldChannels retrieves all persistent world channels from database
|
|
func (dcm *DatabaseChannelManager) LoadWorldChannels(ctx context.Context) ([]ChatChannelData, error) {
|
|
query := "SELECT `name`, `password`, `level_restriction`, `classes`, `races` FROM `channels`"
|
|
|
|
rows, err := dcm.db.QueryContext(ctx, query)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to query channels: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var channels []ChatChannelData
|
|
for rows.Next() {
|
|
var channel ChatChannelData
|
|
var password *string
|
|
|
|
err := rows.Scan(
|
|
&channel.Name,
|
|
&password,
|
|
&channel.LevelRestriction,
|
|
&channel.ClassRestriction,
|
|
&channel.RaceRestriction,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to scan channel row: %w", err)
|
|
}
|
|
|
|
// Handle nullable password field
|
|
if password != nil {
|
|
channel.Password = *password
|
|
}
|
|
|
|
channels = append(channels, channel)
|
|
}
|
|
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("error iterating channel rows: %w", err)
|
|
}
|
|
|
|
return channels, nil
|
|
}
|
|
|
|
// SaveChannel persists a channel to database (world channels only)
|
|
func (dcm *DatabaseChannelManager) SaveChannel(ctx context.Context, channel ChatChannelData) error {
|
|
// Insert or update channel
|
|
query := `
|
|
INSERT OR REPLACE INTO channels
|
|
(name, password, level_restriction, classes, races)
|
|
VALUES (?, ?, ?, ?, ?)`
|
|
|
|
var password *string
|
|
if channel.Password != "" {
|
|
password = &channel.Password
|
|
}
|
|
|
|
_, err := dcm.db.ExecContext(ctx, query,
|
|
channel.Name,
|
|
password,
|
|
channel.LevelRestriction,
|
|
channel.ClassRestriction,
|
|
channel.RaceRestriction,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to save channel %s: %w", channel.Name, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeleteChannel removes a channel from database
|
|
func (dcm *DatabaseChannelManager) DeleteChannel(ctx context.Context, channelName string) error {
|
|
query := "DELETE FROM channels WHERE name = ?"
|
|
|
|
result, err := dcm.db.ExecContext(ctx, query, channelName)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete channel %s: %w", channelName, err)
|
|
}
|
|
|
|
rowsAffected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check rows affected for channel %s: %w", channelName, err)
|
|
}
|
|
|
|
if rowsAffected == 0 {
|
|
return fmt.Errorf("channel %s not found in database", channelName)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EnsureChannelsTable creates the channels table if it doesn't exist
|
|
func (dcm *DatabaseChannelManager) EnsureChannelsTable(ctx context.Context) error {
|
|
query := `
|
|
CREATE TABLE IF NOT EXISTS channels (
|
|
name TEXT PRIMARY KEY,
|
|
password TEXT,
|
|
level_restriction INTEGER NOT NULL DEFAULT 0,
|
|
classes INTEGER NOT NULL DEFAULT 0,
|
|
races INTEGER NOT NULL DEFAULT 0,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`
|
|
|
|
_, err := dcm.db.ExecContext(ctx, query)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create channels table: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetChannelCount returns the total number of channels in the database
|
|
func (dcm *DatabaseChannelManager) GetChannelCount(ctx context.Context) (int, error) {
|
|
query := "SELECT COUNT(*) FROM channels"
|
|
|
|
var count int
|
|
err := dcm.db.QueryRowContext(ctx, query).Scan(&count)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to get channel count: %w", err)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// GetChannelByName retrieves a specific channel by name
|
|
func (dcm *DatabaseChannelManager) GetChannelByName(ctx context.Context, channelName string) (*ChatChannelData, error) {
|
|
query := "SELECT `name`, `password`, `level_restriction`, `classes`, `races` FROM `channels` WHERE `name` = ?"
|
|
|
|
var channel ChatChannelData
|
|
var password *string
|
|
|
|
err := dcm.db.QueryRowContext(ctx, query, channelName).Scan(
|
|
&channel.Name,
|
|
&password,
|
|
&channel.LevelRestriction,
|
|
&channel.ClassRestriction,
|
|
&channel.RaceRestriction,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get channel %s: %w", channelName, err)
|
|
}
|
|
|
|
// Handle nullable password field
|
|
if password != nil {
|
|
channel.Password = *password
|
|
}
|
|
|
|
return &channel, nil
|
|
}
|
|
|
|
// ListChannelNames returns a list of all channel names in the database
|
|
func (dcm *DatabaseChannelManager) ListChannelNames(ctx context.Context) ([]string, error) {
|
|
query := "SELECT name FROM channels ORDER BY name"
|
|
|
|
rows, err := dcm.db.QueryContext(ctx, query)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to query channel names: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var names []string
|
|
for rows.Next() {
|
|
var name string
|
|
if err := rows.Scan(&name); err != nil {
|
|
return nil, fmt.Errorf("failed to scan channel name: %w", err)
|
|
}
|
|
names = append(names, name)
|
|
}
|
|
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("error iterating channel name rows: %w", err)
|
|
}
|
|
|
|
return names, nil
|
|
}
|
|
|
|
// UpdateChannelPassword updates just the password for a channel
|
|
func (dcm *DatabaseChannelManager) UpdateChannelPassword(ctx context.Context, channelName, password string) error {
|
|
query := "UPDATE channels SET password = ?, updated_at = CURRENT_TIMESTAMP WHERE name = ?"
|
|
|
|
var passwordParam *string
|
|
if password != "" {
|
|
passwordParam = &password
|
|
}
|
|
|
|
result, err := dcm.db.ExecContext(ctx, query, passwordParam, channelName)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update password for channel %s: %w", channelName, err)
|
|
}
|
|
|
|
rowsAffected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check rows affected for channel %s: %w", channelName, err)
|
|
}
|
|
|
|
if rowsAffected == 0 {
|
|
return fmt.Errorf("channel %s not found in database", channelName)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateChannelRestrictions updates the level, race, and class restrictions for a channel
|
|
func (dcm *DatabaseChannelManager) UpdateChannelRestrictions(ctx context.Context, channelName string, levelRestriction, classRestriction, raceRestriction int32) error {
|
|
query := "UPDATE channels SET level_restriction = ?, classes = ?, races = ?, updated_at = CURRENT_TIMESTAMP WHERE name = ?"
|
|
|
|
result, err := dcm.db.ExecContext(ctx, query, levelRestriction, classRestriction, raceRestriction, channelName)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update restrictions for channel %s: %w", channelName, err)
|
|
}
|
|
|
|
rowsAffected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check rows affected for channel %s: %w", channelName, err)
|
|
}
|
|
|
|
if rowsAffected == 0 {
|
|
return fmt.Errorf("channel %s not found in database", channelName)
|
|
}
|
|
|
|
return nil
|
|
} |