This commit is contained in:
203
main.go
203
main.go
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
|
_ "github.com/mattn/go-sqlite3" // SQLite3-Treiber importieren
|
||||||
)
|
)
|
||||||
|
|
||||||
// ===== Defaults / Names (pro Guild per Commands konfigurierbar) =====
|
// ===== Defaults / Names (pro Guild per Commands konfigurierbar) =====
|
||||||
@@ -20,53 +21,21 @@ const (
|
|||||||
defaultCategory = "Private Räume"
|
defaultCategory = "Private Räume"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Pfad zur SQLite-Datenbank
|
||||||
|
var dbPath = func() string {
|
||||||
|
if v := os.Getenv("DB_PATH"); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return "guild_config.db"
|
||||||
|
}()
|
||||||
|
|
||||||
// Pfad zur Persistenz-Datei (überschreibbar via CONFIG_PATH)
|
// Pfad zur Persistenz-Datei (überschreibbar via CONFIG_PATH)
|
||||||
var configPath = func() string {
|
/*var configPath = func() string {
|
||||||
if v := os.Getenv("CONFIG_PATH"); v != "" {
|
if v := os.Getenv("CONFIG_PATH"); v != "" {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
return "guild_config.json"
|
return "guild_config.json"
|
||||||
}()
|
}()*/
|
||||||
|
|
||||||
// Persistenz der Guild-Konfiguration
|
|
||||||
func loadGuildCfgs() error {
|
|
||||||
f, err := os.Open(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
var m map[string]*GuildConfig
|
|
||||||
if err := json.NewDecoder(f).Decode(&m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cfgMu.Lock()
|
|
||||||
for k, v := range m {
|
|
||||||
guildCfgs[k] = v
|
|
||||||
}
|
|
||||||
cfgMu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveGuildCfgs() error {
|
|
||||||
tmp := configPath + ".tmp"
|
|
||||||
f, err := os.Create(tmp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
enc := json.NewEncoder(f)
|
|
||||||
enc.SetIndent("", " ")
|
|
||||||
|
|
||||||
cfgMu.RLock()
|
|
||||||
err = enc.Encode(guildCfgs)
|
|
||||||
cfgMu.RUnlock()
|
|
||||||
_ = f.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.Rename(tmp, configPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Per-Guild Config (in-memory) =====
|
// ===== Per-Guild Config (in-memory) =====
|
||||||
type GuildConfig struct {
|
type GuildConfig struct {
|
||||||
@@ -75,29 +44,121 @@ type GuildConfig struct {
|
|||||||
TimeoutMin int `json:"timeout_min"`
|
TimeoutMin int `json:"timeout_min"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var db *sql.DB
|
||||||
|
|
||||||
|
// Initialize DB
|
||||||
|
func initDB() {
|
||||||
|
var err error
|
||||||
|
db, err = sql.Open("sqlite3", dbPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Datenbank-Fehler: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tabelle erstellen, falls sie noch nicht existiert
|
||||||
|
createTableSQL := `CREATE TABLE IF NOT EXISTS guild_config (
|
||||||
|
guild_id TEXT PRIMARY KEY,
|
||||||
|
lobby_name TEXT,
|
||||||
|
category_name TEXT,
|
||||||
|
timeout_min INTEGER
|
||||||
|
);`
|
||||||
|
_, err = db.Exec(createTableSQL)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Fehler beim Erstellen der Tabelle: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close DB connection
|
||||||
|
func closeDB() {
|
||||||
|
if err := db.Close(); err != nil {
|
||||||
|
log.Fatalf("Fehler beim Schließen der DB: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Laden der Guild-Konfiguration aus der Datenbank
|
||||||
|
func loadGuildCfgs() error {
|
||||||
|
rows, err := db.Query("SELECT guild_id, lobby_name, category_name, timeout_min FROM guild_config")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var guildID, lobbyName, categoryName string
|
||||||
|
var timeoutMin int
|
||||||
|
if err := rows.Scan(&guildID, &lobbyName, &categoryName, &timeoutMin); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
guildCfgs[guildID] = &GuildConfig{
|
||||||
|
LobbyName: lobbyName,
|
||||||
|
CategoryName: categoryName,
|
||||||
|
TimeoutMin: timeoutMin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speichern der Guild-Konfiguration in die Datenbank
|
||||||
|
func saveGuildCfgs() error {
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
for guildID, cfg := range guildCfgs {
|
||||||
|
// UPDATE oder INSERT, je nachdem, ob es bereits eine Konfiguration gibt
|
||||||
|
_, err := tx.Exec(`
|
||||||
|
INSERT INTO guild_config (guild_id, lobby_name, category_name, timeout_min)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
ON CONFLICT(guild_id)
|
||||||
|
DO UPDATE SET
|
||||||
|
lobby_name = excluded.lobby_name,
|
||||||
|
category_name = excluded.category_name,
|
||||||
|
timeout_min = excluded.timeout_min
|
||||||
|
`, guildID, cfg.LobbyName, cfg.CategoryName, cfg.TimeoutMin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaktion abschließen
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cfgMu sync.RWMutex
|
cfgMu sync.Mutex
|
||||||
guildCfgs = map[string]*GuildConfig{}
|
guildCfgs = map[string]*GuildConfig{}
|
||||||
createdCmds = map[string][]*discordgo.ApplicationCommand{} // guildID -> cmds
|
createdCmds = map[string][]*discordgo.ApplicationCommand{} // guildID -> cmds
|
||||||
registerOnce sync.Once
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getCfg(guildID string) *GuildConfig {
|
func getCfg(guildID string) *GuildConfig {
|
||||||
cfgMu.RLock()
|
cfgMu.Lock()
|
||||||
c, ok := guildCfgs[guildID]
|
c, ok := guildCfgs[guildID]
|
||||||
cfgMu.RUnlock()
|
cfgMu.Unlock()
|
||||||
if ok {
|
if ok {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
cfgMu.Lock()
|
|
||||||
defer cfgMu.Unlock()
|
// Falls nicht vorhanden, Daten aus DB laden
|
||||||
c = &GuildConfig{
|
var guildCfg GuildConfig
|
||||||
LobbyName: defaultLobbyName,
|
err := db.QueryRow("SELECT lobby_name, category_name, timeout_min FROM guild_config WHERE guild_id = ?", guildID).Scan(&guildCfg.LobbyName, &guildCfg.CategoryName, &guildCfg.TimeoutMin)
|
||||||
CategoryName: defaultCategory,
|
if err != nil {
|
||||||
TimeoutMin: envTimeoutDefault(60),
|
if err != sql.ErrNoRows {
|
||||||
|
log.Printf("Fehler beim Abrufen der Guild-Konfiguration: %v", err)
|
||||||
|
}
|
||||||
|
// Fallback-Werte, falls die Guild nicht in der DB existiert
|
||||||
|
guildCfg = GuildConfig{
|
||||||
|
LobbyName: defaultLobbyName,
|
||||||
|
CategoryName: defaultCategory,
|
||||||
|
TimeoutMin: envTimeoutDefault(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
guildCfgs[guildID] = c
|
|
||||||
return c
|
cfgMu.Lock()
|
||||||
|
guildCfgs[guildID] = &guildCfg
|
||||||
|
cfgMu.Unlock()
|
||||||
|
return &guildCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func envTimeoutDefault(def int) int {
|
func envTimeoutDefault(def int) int {
|
||||||
@@ -541,8 +602,8 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
})
|
})
|
||||||
|
|
||||||
case "settimeout":
|
case "settimeout":
|
||||||
// Admin-Check zuerst
|
|
||||||
if !isGuildAdmin(s, guildID, i.User, i.Member) {
|
if !isGuildAdmin(s, guildID, i.User, i.Member) {
|
||||||
|
log.Println("User is not an admin")
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
Data: &discordgo.InteractionResponseData{
|
Data: &discordgo.InteractionResponseData{
|
||||||
@@ -553,7 +614,6 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// minutes lesen
|
|
||||||
minutes := int64(getCfg(guildID).TimeoutMin)
|
minutes := int64(getCfg(guildID).TimeoutMin)
|
||||||
for _, o := range data.Options {
|
for _, o := range data.Options {
|
||||||
if o.Name == "minutes" {
|
if o.Name == "minutes" {
|
||||||
@@ -564,9 +624,12 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
minutes = 1
|
minutes = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Setting timeout for %d minutes", minutes)
|
||||||
|
|
||||||
// speichern
|
// speichern
|
||||||
cfgMu.Lock()
|
cfgMu.Lock()
|
||||||
getCfg(guildID).TimeoutMin = int(minutes)
|
getCfg(guildID).TimeoutMin = int(minutes)
|
||||||
|
log.Println("1-0815")
|
||||||
cfgMu.Unlock()
|
cfgMu.Unlock()
|
||||||
if err := saveGuildCfgs(); err != nil {
|
if err := saveGuildCfgs(); err != nil {
|
||||||
log.Printf("saveGuildCfgs failed: %v", err)
|
log.Printf("saveGuildCfgs failed: %v", err)
|
||||||
@@ -580,6 +643,8 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("2-0815")
|
||||||
|
|
||||||
// Antwort <= 3s
|
// Antwort <= 3s
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
@@ -698,6 +763,7 @@ func onGuildCreate(s *discordgo.Session, g *discordgo.GuildCreate) {
|
|||||||
cfgMu.Lock()
|
cfgMu.Lock()
|
||||||
createdCmds[g.ID] = append(createdCmds[g.ID], c)
|
createdCmds[g.ID] = append(createdCmds[g.ID], c)
|
||||||
cfgMu.Unlock()
|
cfgMu.Unlock()
|
||||||
|
log.Printf("Command-Registrierung in %s", g.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,7 +819,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func registerCommandsForGuild(s *discordgo.Session, guildID string) {
|
/*func registerCommandsForGuild(s *discordgo.Session, guildID string) {
|
||||||
appID := s.State.User.ID
|
appID := s.State.User.ID
|
||||||
cmds, err := s.ApplicationCommandBulkOverwrite(appID, guildID, slashCommands)
|
cmds, err := s.ApplicationCommandBulkOverwrite(appID, guildID, slashCommands)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -763,18 +829,21 @@ func registerCommandsForGuild(s *discordgo.Session, guildID string) {
|
|||||||
cfgMu.Lock()
|
cfgMu.Lock()
|
||||||
createdCmds[guildID] = cmds
|
createdCmds[guildID] = cmds
|
||||||
cfgMu.Unlock()
|
cfgMu.Unlock()
|
||||||
}
|
//fmt.Println(createdCmds)
|
||||||
|
}*/
|
||||||
|
|
||||||
// ===== main: Multi-Guild, pro Guild registrieren =====
|
// ===== main: Multi-Guild, pro Guild registrieren =====
|
||||||
func main() {
|
func main() {
|
||||||
|
initDB()
|
||||||
token := os.Getenv("DISCORD_TOKEN")
|
token := os.Getenv("DISCORD_TOKEN")
|
||||||
|
token = "MTQwMzg1MTM5NDQ1MjI5MTU4NA.GVi04l.qjraLIbFdi_N49UcSUv_BqK89ihb6xXY648J7A"
|
||||||
if token == "" {
|
if token == "" {
|
||||||
log.Fatal("Bitte setze DISCORD_TOKEN")
|
log.Fatal("Bitte setze DISCORD_TOKEN")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistente Konfiguration laden (optional)
|
// Persistente Konfiguration laden (optional)
|
||||||
if err := loadGuildCfgs(); err != nil {
|
if err := loadGuildCfgs(); err != nil {
|
||||||
log.Printf("Hinweis: Konnte %s nicht laden (%v). Starte mit Defaults.", configPath, err)
|
log.Printf("Hinweis: Konnte %s nicht laden (%v). Starte mit Defaults.", dbPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := discordgo.New("Bot " + token)
|
s, err := discordgo.New("Bot " + token)
|
||||||
@@ -786,16 +855,16 @@ func main() {
|
|||||||
|
|
||||||
s.AddHandler(onVoiceStateUpdate)
|
s.AddHandler(onVoiceStateUpdate)
|
||||||
s.AddHandler(onGuildCreate)
|
s.AddHandler(onGuildCreate)
|
||||||
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
|
/*s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
|
||||||
for _, g := range s.State.Guilds {
|
for _, g := range s.State.Guilds {
|
||||||
registerCommandsForGuild(s, g.ID)
|
registerCommandsForGuild(s, g.ID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
s.AddHandler(func(s *discordgo.Session, g *discordgo.GuildCreate) {
|
s.AddHandler(func(s *discordgo.Session, g *discordgo.GuildCreate) {
|
||||||
registerCommandsForGuild(s, g.ID)
|
registerCommandsForGuild(s, g.ID)
|
||||||
})
|
})*/
|
||||||
s.AddHandler(onInteractionCreate(""))
|
s.AddHandler(onInteractionCreate(""))
|
||||||
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
|
/*s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
|
||||||
log.Printf("Eingeloggt als %s", r.User.Username)
|
log.Printf("Eingeloggt als %s", r.User.Username)
|
||||||
registerOnce.Do(func() {
|
registerOnce.Do(func() {
|
||||||
appID := s.State.User.ID
|
appID := s.State.User.ID
|
||||||
@@ -812,7 +881,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Printf("Defaults → Lobby: %q | Kategorie: %q | Timeout: %d min", defaultLobbyName, defaultCategory, envTimeoutDefault(60))
|
log.Printf("Defaults → Lobby: %q | Kategorie: %q | Timeout: %d min", defaultLobbyName, defaultCategory, envTimeoutDefault(60))
|
||||||
})
|
})
|
||||||
})
|
})*/
|
||||||
|
|
||||||
if err := s.Open(); err != nil {
|
if err := s.Open(); err != nil {
|
||||||
log.Fatalf("Gateway-Start fehlgeschlagen: %v", err)
|
log.Fatalf("Gateway-Start fehlgeschlagen: %v", err)
|
||||||
@@ -829,6 +898,8 @@ func main() {
|
|||||||
for _, c := range cmds {
|
for _, c := range cmds {
|
||||||
if delErr := s.ApplicationCommandDelete(appID, guildID, c.ID); delErr != nil {
|
if delErr := s.ApplicationCommandDelete(appID, guildID, c.ID); delErr != nil {
|
||||||
log.Printf("Cmd-Delete (%s/%s) fehlgeschlagen: %v", guildID, c.Name, delErr)
|
log.Printf("Cmd-Delete (%s/%s) fehlgeschlagen: %v", guildID, c.Name, delErr)
|
||||||
|
} else {
|
||||||
|
log.Printf("Cmd-Delete (%s/%s) ok", guildID, c.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user