main.go aktualisiert
All checks were successful
release-tag / release-image (push) Successful in 1m41s
All checks were successful
release-tag / release-image (push) Successful in 1m41s
This commit is contained in:
229
main.go
229
main.go
@@ -14,9 +14,9 @@ import (
|
|||||||
|
|
||||||
// ===== Defaults / Names (pro Guild per Commands konfigurierbar) =====
|
// ===== Defaults / Names (pro Guild per Commands konfigurierbar) =====
|
||||||
const (
|
const (
|
||||||
pollInterval = 15 * time.Second
|
pollInterval = 15 * time.Second
|
||||||
defaultLobbyName = "➕ Erstelle privaten Raum"
|
defaultLobbyName = "➕ Erstelle privaten Raum"
|
||||||
defaultCategory = "Private Räume"
|
defaultCategory = "Private Räume"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ===== Per-Guild Config (in-memory) =====
|
// ===== Per-Guild Config (in-memory) =====
|
||||||
@@ -27,9 +27,9 @@ type GuildConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cfgMu sync.RWMutex
|
cfgMu sync.RWMutex
|
||||||
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
|
registerOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -286,10 +286,14 @@ func onVoiceStateUpdate(s *discordgo.Session, e *discordgo.VoiceStateUpdate) {
|
|||||||
|
|
||||||
// ===== Permissions Helper =====
|
// ===== Permissions Helper =====
|
||||||
func isGuildAdmin(s *discordgo.Session, guildID string, user *discordgo.User, member *discordgo.Member) bool {
|
func isGuildAdmin(s *discordgo.Session, guildID string, user *discordgo.User, member *discordgo.Member) bool {
|
||||||
if user == nil && member == nil { return false }
|
if user == nil && member == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if member == nil {
|
if member == nil {
|
||||||
m, err := s.GuildMember(guildID, user.ID)
|
m, err := s.GuildMember(guildID, user.ID)
|
||||||
if err != nil { return false }
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
member = m
|
member = m
|
||||||
}
|
}
|
||||||
g, err := s.State.Guild(guildID)
|
g, err := s.State.Guild(guildID)
|
||||||
@@ -297,7 +301,9 @@ func isGuildAdmin(s *discordgo.Session, guildID string, user *discordgo.User, me
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
roles, err := s.GuildRoles(guildID)
|
roles, err := s.GuildRoles(guildID)
|
||||||
if err != nil { return false }
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
rolePerm := int64(0)
|
rolePerm := int64(0)
|
||||||
for _, r := range roles {
|
for _, r := range roles {
|
||||||
for _, mr := range member.Roles {
|
for _, mr := range member.Roles {
|
||||||
@@ -318,27 +324,38 @@ func isGuildAdmin(s *discordgo.Session, guildID string, user *discordgo.User, me
|
|||||||
// Slash-Commands: makevc / setlobby / setcategory / settimeout (Admin-geschützt)
|
// Slash-Commands: makevc / setlobby / setcategory / settimeout (Admin-geschützt)
|
||||||
func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
return func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
return func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
if i.Type != discordgo.InteractionApplicationCommand { return }
|
if i.Type != discordgo.InteractionApplicationCommand {
|
||||||
|
return
|
||||||
|
}
|
||||||
data := i.ApplicationCommandData()
|
data := i.ApplicationCommandData()
|
||||||
guildID := i.GuildID
|
guildID := i.GuildID
|
||||||
switch data.Name {
|
switch data.Name {
|
||||||
case "makevc":
|
case "makevc":
|
||||||
cfg := getCfg(guildID)
|
cfg := getCfg(guildID)
|
||||||
user := i.User
|
user := i.User
|
||||||
if user == nil && i.Member != nil { user = i.Member.User }
|
if user == nil && i.Member != nil {
|
||||||
if user == nil { return }
|
user = i.Member.User
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
userLimit := 0
|
userLimit := 0
|
||||||
timeoutMin := cfg.TimeoutMin
|
timeoutMin := cfg.TimeoutMin
|
||||||
var nameOpt string
|
var nameOpt string
|
||||||
for _, o := range data.Options {
|
for _, o := range data.Options {
|
||||||
switch o.Name {
|
switch o.Name {
|
||||||
case "name": nameOpt = o.StringValue()
|
case "name":
|
||||||
case "user_limit": userLimit = int(o.IntValue())
|
nameOpt = o.StringValue()
|
||||||
case "timeout_min": timeoutMin = int(o.IntValue())
|
case "user_limit":
|
||||||
|
userLimit = int(o.IntValue())
|
||||||
|
case "timeout_min":
|
||||||
|
timeoutMin = int(o.IntValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
display := displayName(i)
|
display := displayName(i)
|
||||||
if nameOpt != "" { display = nameOpt }
|
if nameOpt != "" {
|
||||||
|
display = nameOpt
|
||||||
|
}
|
||||||
catID, err := findOrCreateCategoryID(s, guildID, cfg.CategoryName)
|
catID, err := findOrCreateCategoryID(s, guildID, cfg.CategoryName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "Konnte Kategorie nicht finden/erstellen.", Flags: discordgo.MessageFlagsEphemeral}})
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "Konnte Kategorie nicht finden/erstellen.", Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
@@ -351,7 +368,11 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("✅ Voice-Channel **%s** erstellt.", newChan.Name)
|
msg := fmt.Sprintf("✅ Voice-Channel **%s** erstellt.", newChan.Name)
|
||||||
if srcVC == "" { msg += " Du bist aktuell in keinem Voice-Channel; join bitte manuell in deinen neuen Raum." } else { msg += " Ich verschiebe dich jetzt dort hinein." }
|
if srcVC == "" {
|
||||||
|
msg += " Du bist aktuell in keinem Voice-Channel; join bitte manuell in deinen neuen Raum."
|
||||||
|
} else {
|
||||||
|
msg += " Ich verschiebe dich jetzt dort hinein."
|
||||||
|
}
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: msg, Flags: discordgo.MessageFlagsEphemeral}})
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: msg, Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
|
|
||||||
case "setlobby":
|
case "setlobby":
|
||||||
@@ -360,9 +381,18 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var name string
|
var name string
|
||||||
for _, o := range data.Options { if o.Name == "name" { name = o.StringValue() } }
|
for _, o := range data.Options {
|
||||||
if name == "" { _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "Bitte gib einen Namen an.", Flags: discordgo.MessageFlagsEphemeral}}); return }
|
if o.Name == "name" {
|
||||||
cfgMu.Lock(); getCfg(guildID).LobbyName = name; cfgMu.Unlock()
|
name = o.StringValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "Bitte gib einen Namen an.", Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfgMu.Lock()
|
||||||
|
getCfg(guildID).LobbyName = name
|
||||||
|
cfgMu.Unlock()
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "✅ Lobby-Name aktualisiert auf: " + name, Flags: discordgo.MessageFlagsEphemeral}})
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "✅ Lobby-Name aktualisiert auf: " + name, Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
|
|
||||||
case "setcategory":
|
case "setcategory":
|
||||||
@@ -371,9 +401,18 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var name string
|
var name string
|
||||||
for _, o := range data.Options { if o.Name == "name" { name = o.StringValue() } }
|
for _, o := range data.Options {
|
||||||
if name == "" { _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "Bitte gib einen Namen an.", Flags: discordgo.MessageFlagsEphemeral}}); return }
|
if o.Name == "name" {
|
||||||
cfgMu.Lock(); getCfg(guildID).CategoryName = name; cfgMu.Unlock()
|
name = o.StringValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "Bitte gib einen Namen an.", Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfgMu.Lock()
|
||||||
|
getCfg(guildID).CategoryName = name
|
||||||
|
cfgMu.Unlock()
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "✅ Kategorie-Name aktualisiert auf: " + name, Flags: discordgo.MessageFlagsEphemeral}})
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: "✅ Kategorie-Name aktualisiert auf: " + name, Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
|
|
||||||
case "settimeout":
|
case "settimeout":
|
||||||
@@ -382,17 +421,117 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var minutes int64 = int64(getCfg(guildID).TimeoutMin)
|
var minutes int64 = int64(getCfg(guildID).TimeoutMin)
|
||||||
for _, o := range data.Options { if o.Name == "minutes" { minutes = o.IntValue() } }
|
for _, o := range data.Options {
|
||||||
if minutes < 1 { minutes = 1 }
|
if o.Name == "minutes" {
|
||||||
cfgMu.Lock(); getCfg(guildID).TimeoutMin = int(minutes); cfgMu.Unlock()
|
minutes = o.IntValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if minutes < 1 {
|
||||||
|
minutes = 1
|
||||||
|
}
|
||||||
|
cfgMu.Lock()
|
||||||
|
getCfg(guildID).TimeoutMin = int(minutes)
|
||||||
|
cfgMu.Unlock()
|
||||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: fmt.Sprintf("✅ Timeout auf %d Minuten gesetzt.", minutes), Flags: discordgo.MessageFlagsEphemeral}})
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{Content: fmt.Sprintf("✅ Timeout auf %d Minuten gesetzt.", minutes), Flags: discordgo.MessageFlagsEphemeral}})
|
||||||
|
case "adduser":
|
||||||
|
// wer ruft auf?
|
||||||
|
requester := i.User
|
||||||
|
if requester == nil && i.Member != nil {
|
||||||
|
requester = i.Member.User
|
||||||
|
}
|
||||||
|
if requester == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ziel-User aus den Optionen holen
|
||||||
|
var target *discordgo.User
|
||||||
|
for _, o := range data.Options {
|
||||||
|
if o.Name == "user" {
|
||||||
|
// UserValue braucht die Session
|
||||||
|
u := o.UserValue(s)
|
||||||
|
if u != nil {
|
||||||
|
target = u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if target == nil {
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: "Bitte gib ein gültiges Mitglied an.",
|
||||||
|
Flags: discordgo.MessageFlagsEphemeral,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// In welchem VC ist der Aufrufer gerade?
|
||||||
|
srcVC := findUserVoiceChannelID(s, guildID, requester.ID)
|
||||||
|
if srcVC == "" {
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: "Du bist aktuell in keinem Voice-Channel. Betritt zuerst deinen privaten Channel.",
|
||||||
|
Flags: discordgo.MessageFlagsEphemeral,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sicherheits-Check: darf der Aufrufer diesen Channel verwalten?
|
||||||
|
// (Der Owner bekommt in deinem Code ManageChannels → das ist unser Indikator)
|
||||||
|
perms, err := s.UserChannelPermissions(requester.ID, srcVC)
|
||||||
|
if err != nil || perms&int64(discordgo.PermissionManageChannels) == 0 {
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: "❌ Du bist nicht der Besitzer dieses Channels oder dir fehlen Rechte (Manage Channel).",
|
||||||
|
Flags: discordgo.MessageFlagsEphemeral,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite setzen: Ziel-User darf sehen & beitreten (& sprechen/Stream/VAD)
|
||||||
|
allow := int64(
|
||||||
|
discordgo.PermissionViewChannel |
|
||||||
|
discordgo.PermissionVoiceConnect |
|
||||||
|
discordgo.PermissionVoiceSpeak |
|
||||||
|
discordgo.PermissionVoiceUseVAD |
|
||||||
|
discordgo.PermissionVoiceStreamVideo,
|
||||||
|
)
|
||||||
|
if err := s.ChannelPermissionSet(
|
||||||
|
srcVC,
|
||||||
|
target.ID,
|
||||||
|
discordgo.PermissionOverwriteTypeMember,
|
||||||
|
allow,
|
||||||
|
0,
|
||||||
|
); err != nil {
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: fmt.Sprintf("Konnte Berechtigung nicht setzen: %v", err),
|
||||||
|
Flags: discordgo.MessageFlagsEphemeral,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: fmt.Sprintf("✅ %s hat jetzt Zugriff auf deinen Voice-Channel.", target.Username),
|
||||||
|
Flags: discordgo.MessageFlagsEphemeral,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Commands Definition =====
|
// ===== Commands Definition =====
|
||||||
var (
|
var (
|
||||||
adminPerm = int64(discordgo.PermissionAdministrator)
|
adminPerm = int64(discordgo.PermissionAdministrator)
|
||||||
slashCommands = []*discordgo.ApplicationCommand{
|
slashCommands = []*discordgo.ApplicationCommand{
|
||||||
{
|
{
|
||||||
Name: "makevc",
|
Name: "makevc",
|
||||||
@@ -404,39 +543,55 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "setlobby",
|
Name: "setlobby",
|
||||||
Description: "Setzt den Namen des Lobby-Voice-Channels",
|
Description: "Setzt den Namen des Lobby-Voice-Channels",
|
||||||
DefaultMemberPermissions: &adminPerm,
|
DefaultMemberPermissions: &adminPerm,
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
{Type: discordgo.ApplicationCommandOptionString, Name: "name", Description: "Neuer Lobby-Name", Required: true},
|
{Type: discordgo.ApplicationCommandOptionString, Name: "name", Description: "Neuer Lobby-Name", Required: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "setcategory",
|
Name: "setcategory",
|
||||||
Description: "Setzt den Namen der Kategorie für private Räume",
|
Description: "Setzt den Namen der Kategorie für private Räume",
|
||||||
DefaultMemberPermissions: &adminPerm,
|
DefaultMemberPermissions: &adminPerm,
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
{Type: discordgo.ApplicationCommandOptionString, Name: "name", Description: "Neue Kategorie-Bezeichnung", Required: true},
|
{Type: discordgo.ApplicationCommandOptionString, Name: "name", Description: "Neue Kategorie-Bezeichnung", Required: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "settimeout",
|
Name: "settimeout",
|
||||||
Description: "Setzt das Auto-Lösch-Timeout (Minuten)",
|
Description: "Setzt das Auto-Lösch-Timeout (Minuten)",
|
||||||
DefaultMemberPermissions: &adminPerm,
|
DefaultMemberPermissions: &adminPerm,
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
{Type: discordgo.ApplicationCommandOptionInteger, Name: "minutes", Description: "Minuten (>=1)", Required: true, MaxValue: 480},
|
{Type: discordgo.ApplicationCommandOptionInteger, Name: "minutes", Description: "Minuten (>=1)", Required: true, MaxValue: 480},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "adduser",
|
||||||
|
Description: "Gibt einem Mitglied Zugriff auf deinen aktuellen privaten Voice-Channel",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionUser,
|
||||||
|
Name: "user",
|
||||||
|
Description: "Mitglied, das Zugriff bekommen soll",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// ===== main: Multi-Guild, pro Guild registrieren =====
|
// ===== main: Multi-Guild, pro Guild registrieren =====
|
||||||
func main() {
|
func main() {
|
||||||
token := os.Getenv("DISCORD_TOKEN")
|
token := os.Getenv("DISCORD_TOKEN")
|
||||||
if token == "" { log.Fatal("Bitte setze DISCORD_TOKEN") }
|
if token == "" {
|
||||||
|
log.Fatal("Bitte setze DISCORD_TOKEN")
|
||||||
|
}
|
||||||
|
|
||||||
s, err := discordgo.New("Bot " + token)
|
s, err := discordgo.New("Bot " + token)
|
||||||
if err != nil { log.Fatalf("Session fehlgeschlagen: %v", err) }
|
if err != nil {
|
||||||
|
log.Fatalf("Session fehlgeschlagen: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
s.Identify.Intents = discordgo.IntentsGuilds | discordgo.IntentsGuildVoiceStates
|
s.Identify.Intents = discordgo.IntentsGuilds | discordgo.IntentsGuildVoiceStates
|
||||||
|
|
||||||
@@ -461,7 +616,9 @@ func main() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := s.Open(); err != nil { log.Fatalf("Gateway-Start fehlgeschlagen: %v", err) }
|
if err := s.Open(); err != nil {
|
||||||
|
log.Fatalf("Gateway-Start fehlgeschlagen: %v", err)
|
||||||
|
}
|
||||||
log.Println("Bot online. Ctrl+C zum Beenden.")
|
log.Println("Bot online. Ctrl+C zum Beenden.")
|
||||||
|
|
||||||
stop := make(chan os.Signal, 1)
|
stop := make(chan os.Signal, 1)
|
||||||
|
Reference in New Issue
Block a user