eq2go/cmd/login_server/config.go

164 lines
4.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
)
// Config holds all login server configuration
type Config struct {
Port int `json:"port"`
MaxConnections int `json:"max_connections"`
TimeoutSeconds int `json:"timeout_seconds"`
EnableCompression bool `json:"enable_compression"`
EnableEncryption bool `json:"enable_encryption"`
AllowAccountCreation bool `json:"allow_account_creation"`
DefaultSubscriptionLevel uint32 `json:"default_subscription_level"`
ExpansionFlag uint16 `json:"expansion_flag"`
CitiesFlag uint8 `json:"cities_flag"`
EnabledRaces uint32 `json:"enabled_races"`
SupportedVersions []uint16 `json:"supported_versions"`
Database DatabaseConfig `json:"database"`
WebServer WebServerConfig `json:"web_server"`
WorldServers []WorldServerConfig `json:"world_servers"`
}
// WebServerConfig holds web server settings
type WebServerConfig struct {
Enabled bool `json:"enabled"`
Address string `json:"address"`
Port int `json:"port"`
CertFile string `json:"cert_file"`
KeyFile string `json:"key_file"`
KeyPassword string `json:"key_password"`
Username string `json:"username"`
Password string `json:"password"`
}
// WorldServerConfig holds world server connection info
type WorldServerConfig struct {
ID int32 `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
Port int `json:"port"`
SharedKey string `json:"shared_key"`
AutoConnect bool `json:"auto_connect"`
}
// DefaultConfig returns sensible default configuration
func DefaultConfig() *Config {
return &Config{
Port: 5999,
MaxConnections: 1000,
TimeoutSeconds: 45,
EnableCompression: true,
EnableEncryption: true,
AllowAccountCreation: false,
DefaultSubscriptionLevel: 0xFFFFFFFF,
ExpansionFlag: 0x7CFF,
CitiesFlag: 0xFF,
EnabledRaces: 0xFFFF,
SupportedVersions: []uint16{283, 373, 546, 561, 1096, 1208},
Database: DatabaseConfig{
FilePath: "eq2login.db",
MaxConnections: 10,
BusyTimeout: 5000,
},
WebServer: WebServerConfig{
Enabled: true,
Address: "0.0.0.0",
Port: 8080,
},
}
}
// LoadConfig loads configuration from a JSON file
func LoadConfig(filename string) (*Config, error) {
// Start with defaults
config := DefaultConfig()
// Check if config file exists
if _, err := os.Stat(filename); os.IsNotExist(err) {
// Create default config file
if err := SaveConfig(filename, config); err != nil {
return nil, fmt.Errorf("failed to create default config: %w", err)
}
fmt.Printf("Created default configuration file: %s\n", filename)
return config, nil
}
// Read existing config file
data, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
// Parse JSON
if err := json.Unmarshal(data, config); err != nil {
return nil, fmt.Errorf("failed to parse config JSON: %w", err)
}
// Validate configuration
if err := config.Validate(); err != nil {
return nil, fmt.Errorf("invalid configuration: %w", err)
}
return config, nil
}
// SaveConfig saves configuration to a JSON file
func SaveConfig(filename string, config *Config) error {
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal config: %w", err)
}
if err := os.WriteFile(filename, data, 0644); err != nil {
return fmt.Errorf("failed to write config file: %w", err)
}
return nil
}
// Validate checks if the configuration is valid
func (c *Config) Validate() error {
if c.Port < 1 || c.Port > 65535 {
return fmt.Errorf("invalid port: %d", c.Port)
}
if c.MaxConnections < 1 {
return fmt.Errorf("max_connections must be positive")
}
if c.TimeoutSeconds < 1 {
return fmt.Errorf("timeout_seconds must be positive")
}
if len(c.SupportedVersions) == 0 {
return fmt.Errorf("must specify at least one supported version")
}
return nil
}
// IsVersionSupported checks if a client version is supported
func (c *Config) IsVersionSupported(version uint16) bool {
for _, supported := range c.SupportedVersions {
if supported == version {
return true
}
}
return false
}
// GetWorldServerConfig returns configuration for a specific world server
func (c *Config) GetWorldServerConfig(id int32) *WorldServerConfig {
for i := range c.WorldServers {
if c.WorldServers[i].ID == id {
return &c.WorldServers[i]
}
}
return nil
}