Tatake/main.go
Minecodes 114521a103
[STABLE] Release v2.0.0
+ XMPP/Jabber module
 + Last ping display
 + Added async bot starter
 + Added new MOTDs
 * Added more config options
 * Fixed randomizer for motd and status
 * Fixed some smaller bugs
2023-07-17 16:41:03 +02:00

1003 lines
28 KiB
Go
Executable file

package main
import (
//"errors"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"strconv"
"strings"
"time"
//"fmt"
"log"
"os"
"os/signal"
"sync"
//"strings"
//"time"
"github.com/bwmarrin/discordgo"
"github.com/joho/godotenv"
"gosrc.io/xmpp"
"gosrc.io/xmpp/stanza"
)
var (
GuildID = flag.String("guild", "", "Test guild ID. If not passed - bot registers commands globally")
BotToken = flag.String("token", "", "Bot access token")
RemoveCommands = flag.Bool("rmcmd", true, "Remove all commands after shutdowning or not")
minPasswordLength = float64(12)
maxPasswordLength = float64(100)
passwordChars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+{}[]:;?/.,<>")
InfoMessages = []string{
`Hello, I'm a bot made by <@!556848982433857537>!`,
`Hello SlimeDiamond`,
`"Never trust a tech guy with a rat tail—too easy to carve secrets out of him." - Lone Star (Mr. Robot)`,
`me gusta los trenes`,
`Now open source on GitHub, git.minecodes.de and CodeBerg`,
`Not Windows created or running, just Debian and Arch`,
`Schnitzel mit Spätzle ist auch lercker`,
`Does anyone also hear the Doom music getting louder?`,
`HAM radio is cool :D`,
`No, I'm not proprietary, I'm open source`,
`I was coded in NodeJS, but now I'm coded in Go`,
`If you need a job: created Linux VM, then "sudo rm -rf /*" and bye bye VM`,
`Encryption should be a human right`,
`I speak XMPP/Jabber too!`,
`Is it weird that a bot has a email address?`,
}
)
/**
Config and init
**/
var s *discordgo.Session
func init() { flag.Parse() }
func init() {
var err error
err = godotenv.Load()
if BotToken == nil || *BotToken == "" {
*BotToken = os.Getenv("TOKEN")
}
if err != nil {
log.Fatal("Error loading .env file")
}
s, err = discordgo.New("Bot " + *BotToken)
if err != nil {
log.Fatalf("Invalid bot parameters: %v", err)
}
}
var (
integerOptionMinValue = 1.0
dmPermission = false
defaultMemberPermissions int64 = discordgo.PermissionManageServer
commands = []*discordgo.ApplicationCommand{
{
Name: "trains",
Description: "I like trains",
},
{
Name: "ping",
Description: "Ping the bot",
},
{
Name: "weather",
Description: "Get the weather",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "city",
Description: "Name of the city",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionBoolean,
Name: "private",
Description: "Send the weather as a message that only you can see",
Required: true,
},
},
},
{
Name: "gh",
Description: "Github commands",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "user",
Description: "Get the user info",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "user",
Description: "Name of the user",
Required: true,
},
},
},
},
},
{
Name: "httpdog",
Description: "HTTP status codes to dog pictures",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionNumber,
Name: "code",
Description: "HTTP status code",
Required: true,
MinValue: &integerOptionMinValue,
MaxValue: 599,
},
},
},
{
Name: "httpcat",
Description: "HTTP status codes to dog pictures",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionNumber,
Name: "code",
Description: "HTTP status code",
Required: true,
MinValue: &integerOptionMinValue,
MaxValue: 599,
},
},
},
{
Name: "fox",
Description: "Get a random fox picture",
},
{
Name: "qrcode",
Description: "Generate a QR code",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "text",
Description: "Text to encode",
Required: true,
},
},
},
{
Name: "password",
Description: "Generate a random password",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionInteger,
Name: "length",
Description: "Length of the password",
Required: true,
MinValue: &minPasswordLength,
MaxValue: maxPasswordLength,
},
},
},
{
Name: "motd",
Description: "Get the message of the day",
},
}
commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
"trains": dcTrains,
"ping": dcPing,
"weather": dcWeather,
"gh": dcGhUser,
"httpdog": dcHTTPDog,
"httpcat": dcHTTPCat,
"fox": dcFox,
"qrcode": dcQRCode,
"password": dcPassword,
"motd": dcMOTD,
}
)
/**
[Discord] Commands
**/
func gen(length int64) string {
password := make([]rune, length)
for i := range password {
password[i] = passwordChars[rand.Intn(len(passwordChars))]
}
// check if password has at least one number, one uppercase letter, one lowercase letter and one special character
// if not, generate a new password
if !strings.ContainsAny(string(password), "0123456789") || !strings.ContainsAny(string(password), "abcdefghijklmnopqrstuvwxyz") || !strings.ContainsAny(string(password), "ABCDEFGHIJKLMNOPQRSTUVWXYZ") || !strings.ContainsAny(string(password), "!@#$%^&*()_+{}[]:;?/.,<>") {
return gen(length)
}
return string(password)
}
func dcPassword(s *discordgo.Session, i *discordgo.InteractionCreate) {
length := i.Interaction.ApplicationCommandData().Options[0].IntValue()
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Flags: discordgo.MessageFlagsEphemeral,
Embeds: []*discordgo.MessageEmbed{
{
Title: "Password",
Color: 0x00ff00,
Description: "Your password is: `" + gen(length) + "`",
},
},
},
})
}
func dcPing(s *discordgo.Session, i *discordgo.InteractionCreate) {
msg := fmt.Sprintf("🏓 **Pong!** 🏓\n"+
"Latency: %dms\n"+
"Last check: %ds", s.HeartbeatLatency().Milliseconds(), s.LastHeartbeatSent.Second())
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: msg,
Flags: discordgo.MessageFlagsEphemeral,
},
})
}
func dcQRCode(s *discordgo.Session, i *discordgo.InteractionCreate) {
value := i.Interaction.ApplicationCommandData().Options[0].StringValue()
value = url.QueryEscape(value)
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Flags: discordgo.MessageFlagsEphemeral,
Embeds: []*discordgo.MessageEmbed{
{
Title: "QR Code",
Color: 0xffff66,
Image: &discordgo.MessageEmbedImage{
URL: "https://api.qrserver.com/v1/create-qr-code/?size=1000x1000&data=" + value,
Width: 1000,
Height: 1000,
},
},
},
},
})
}
func dcTrains(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "🚅 I like trains! 🚅",
Flags: discordgo.MessageFlagsEphemeral,
},
})
}
func dcWeather(s *discordgo.Session, i *discordgo.InteractionCreate) {
loc := i.Interaction.ApplicationCommandData().Options[0].StringValue()
// make http request
req, err := http.NewRequest("GET", "https://wttr.in/"+loc+"?0&T", nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", "curl")
req.Response, err = http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer req.Response.Body.Close()
body, err := ioutil.ReadAll(req.Response.Body)
if err != nil {
log.Fatal(err)
}
if i.Interaction.ApplicationCommandData().Options[1].BoolValue() {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Embeds: []*discordgo.MessageEmbed{
{
Title: "Weather in " + loc,
Description: "```" + string(body) + "```",
Color: 0x0E86D4,
Timestamp: time.Now().Format(time.RFC3339),
Provider: &discordgo.MessageEmbedProvider{
Name: "wttr.in",
URL: "https://wttr.in",
},
Author: &discordgo.MessageEmbedAuthor{
Name: "wttr.in",
URL: "https://wttr.in",
},
},
},
Flags: discordgo.MessageFlagsEphemeral,
},
})
} else {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Embeds: []*discordgo.MessageEmbed{
{
Title: "Weather in " + loc,
Description: "```" + string(body) + "```",
Color: 0x0E86D4,
Timestamp: time.Now().Format(time.RFC3339),
Provider: &discordgo.MessageEmbedProvider{
Name: "wttr.in",
URL: "https://wttr.in",
},
Author: &discordgo.MessageEmbedAuthor{
Name: "wttr.in",
URL: "https://wttr.in",
},
},
},
},
})
}
}
func dcHTTPDog(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Flags: discordgo.MessageFlagsEphemeral,
Embeds: []*discordgo.MessageEmbed{
{
Title: "HTTP Dog",
Color: 0xfa7c91,
Image: &discordgo.MessageEmbedImage{
URL: "https://http.dog/" + fmt.Sprint(i.Interaction.ApplicationCommandData().Options[0].FloatValue()) + ".jpg",
Width: 1400,
Height: 1600,
},
Provider: &discordgo.MessageEmbedProvider{
Name: "HTTP Dog",
URL: "https://http.dog",
},
Author: &discordgo.MessageEmbedAuthor{
Name: "HTTP Dog",
URL: "https://http.dog",
IconURL: "https://http.dog/favicon.ico",
},
Timestamp: time.Now().Format(time.RFC3339),
},
},
},
})
}
func dcHTTPCat(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Flags: discordgo.MessageFlagsEphemeral,
Embeds: []*discordgo.MessageEmbed{
{
Title: "HTTP Cat",
Color: 0xfa7c91,
Image: &discordgo.MessageEmbedImage{
URL: "https://http.cat/" + fmt.Sprint(i.Interaction.ApplicationCommandData().Options[0].FloatValue()) + ".jpg",
Width: 1400,
Height: 1600,
},
Provider: &discordgo.MessageEmbedProvider{
Name: "HTTP Cat",
URL: "https://http.cat",
},
Author: &discordgo.MessageEmbedAuthor{
Name: "HTTP Cat",
URL: "https://http.cat",
IconURL: "https://http.cat/favicon.ico",
},
Timestamp: time.Now().Format(time.RFC3339),
},
},
},
})
}
func dcGhUser(s *discordgo.Session, i *discordgo.InteractionCreate) {
if i.Interaction.ApplicationCommandData().Options[0].Name == "user" {
user := i.Interaction.ApplicationCommandData().Options[0].Options[0].StringValue()
req, err := http.NewRequest("GET", "https://api.github.com/users/"+user, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", "curl")
req.Response, err = http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer req.Response.Body.Close()
body, err := ioutil.ReadAll(req.Response.Body)
if err != nil {
log.Fatal(err)
}
type User struct {
Login string `json:"login"`
ID int `json:"id"`
NodeID string `json:"node_id"`
AvatarURL string `json:"avatar_url"`
GravatarID string `json:"gravatar_id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
FollowersURL string `json:"followers_url"`
FollowingURL string `json:"following_url"`
GistsURL string `json:"gists_url"`
StarredURL string `json:"starred_url"`
SubscriptionsURL string `json:"subscriptions_url"`
OrganizationsURL string `json:"organizations_url"`
ReposURL string `json:"repos_url"`
EventsURL string `json:"events_url"`
ReceivedEventsURL string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
Name string `json:"name"`
Company string `json:"company"`
Blog string `json:"blog"`
Location string `json:"location"`
Email string `json:"email"`
Hireable bool `json:"hireable"`
Bio string `json:"bio"`
TwitterUsername string `json:"twitter_username"`
PublicRepos int `json:"public_repos"`
PublicGists int `json:"public_gists"`
Followers int `json:"followers"`
Following int `json:"following"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
var data User
err = json.Unmarshal(body, &data)
if err != nil {
log.Fatal(err)
}
var fields = []*discordgo.MessageEmbedField{
{
Name: "Username",
Value: data.Login,
Inline: true,
},
{
Name: "ID",
Value: strconv.Itoa(data.ID),
Inline: true,
},
{
Name: "Public Repos",
Value: strconv.Itoa(data.PublicRepos),
Inline: true,
},
{
Name: "Public Gists",
Value: strconv.Itoa(data.PublicGists),
Inline: true,
},
{
Name: "Followers",
Value: strconv.Itoa(data.Followers),
Inline: true,
},
{
Name: "Following",
Value: strconv.Itoa(data.Following),
Inline: true,
},
{
Name: "Created At",
Value: data.CreatedAt,
Inline: true,
},
}
if data.Bio != "" {
fields = append(fields, &discordgo.MessageEmbedField{
Name: "Bio",
Value: data.Bio,
Inline: true,
})
}
if data.Company != "" {
fields = append(fields, &discordgo.MessageEmbedField{
Name: "Company",
Value: data.Company,
Inline: true,
})
}
if data.Location != "" {
fields = append(fields, &discordgo.MessageEmbedField{
Name: "Location",
Value: data.Location,
Inline: true,
})
}
if data.Email != "" {
fields = append(fields, &discordgo.MessageEmbedField{
Name: "Email",
Value: data.Email,
Inline: true,
})
}
if data.Blog != "" {
fields = append(fields, &discordgo.MessageEmbedField{
Name: "Blog",
Value: data.Blog,
Inline: true,
})
}
if data.TwitterUsername != "" {
fields = append(fields, &discordgo.MessageEmbedField{
Name: "Twitter",
Value: "https://twitter.com/" + data.TwitterUsername,
Inline: true,
})
}
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Embeds: []*discordgo.MessageEmbed{
{
Title: "Github: " + user,
Color: 0x24292D,
Description: "",
Provider: &discordgo.MessageEmbedProvider{
Name: "Github",
URL: "https://github.com",
},
Author: &discordgo.MessageEmbedAuthor{
Name: data.Name,
URL: data.HTMLURL,
IconURL: data.AvatarURL,
},
Timestamp: time.Now().Format(time.RFC3339),
Footer: &discordgo.MessageEmbedFooter{
Text: "Provided by Github",
IconURL: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
},
Fields: fields,
},
},
Flags: discordgo.MessageFlagsEphemeral,
},
})
}
}
func dcFox(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Flags: discordgo.MessageFlagsEphemeral,
Embeds: []*discordgo.MessageEmbed{
{
Author: &discordgo.MessageEmbedAuthor{
Name: "Random Fox",
URL: "https://randomfox.ca",
IconURL: "https://randomfox.ca/favicon.ico",
},
Color: 0xf48b00,
Image: &discordgo.MessageEmbedImage{
URL: "https://randomfox.ca/images/" + fmt.Sprint(rand.Intn(123)) + ".jpg",
},
Timestamp: time.Now().Format(time.RFC3339),
},
},
},
})
}
func dcMOTD(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "",
Flags: discordgo.MessageFlagsEphemeral,
Embeds: []*discordgo.MessageEmbed{
{
Color: 0xf1ff24,
Description: InfoMessages[rand.Intn(len(InfoMessages))],
},
},
},
})
}
/**
[XMPP] Commands
**/
func xmppPing(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: "Pong!"}
_ = s.Send(reply)
}
func xmppTrains(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: "🚅 I like trains! 🚅"}
_ = s.Send(reply)
}
func xmppPassword(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
args := strings.Split(msg.Body, " ")
if len(args) != 2 {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: "Usage: !password <length>"}
_ = s.Send(reply)
return
}
length, err := strconv.Atoi(args[1])
if err != nil {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: "Usage: !password <length>"}
_ = s.Send(reply)
return
}
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: gen(int64(length))}
_ = s.Send(reply)
}
func xmppWeather(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
args := strings.Split(msg.Body, " ")
if len(args) != 2 {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: "Usage: !weather <location>"}
_ = s.Send(reply)
return
}
// make http request
req, err := http.NewRequest("GET", "https://wttr.in/"+args[1]+"?0&T", nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", "curl")
req.Response, err = http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer req.Response.Body.Close()
body, err := ioutil.ReadAll(req.Response.Body)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: string(body)}
_ = s.Send(reply)
}
func xmppGhUser(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
args := strings.Split(msg.Body, " ")
if len(args) != 2 {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: "Usage: !ghuser <username>"}
_ = s.Send(reply)
return
}
req, err := http.NewRequest("GET", "https://api.github.com/users/"+args[1], nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", "curl")
req.Response, err = http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer req.Response.Body.Close()
body, err := ioutil.ReadAll(req.Response.Body)
if err != nil {
log.Fatal(err)
}
type User struct {
Login string `json:"login"`
ID int `json:"id"`
NodeID string `json:"node_id"`
AvatarURL string `json:"avatar_url"`
GravatarID string `json:"gravatar_id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
FollowersURL string `json:"followers_url"`
FollowingURL string `json:"following_url"`
GistsURL string `json:"gists_url"`
StarredURL string `json:"starred_url"`
SubscriptionsURL string `json:"subscriptions_url"`
OrganizationsURL string `json:"organizations_url"`
ReposURL string `json:"repos_url"`
EventsURL string `json:"events_url"`
ReceivedEventsURL string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
Name string `json:"name"`
Company string `json:"company"`
Blog string `json:"blog"`
Location string `json:"location"`
Email string `json:"email"`
Hireable bool `json:"hireable"`
Bio string `json:"bio"`
TwitterUsername string `json:"twitter_username"`
PublicRepos int `json:"public_repos"`
PublicGists int `json:"public_gists"`
Followers int `json:"followers"`
Following int `json:"following"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
var data User
err = json.Unmarshal(body, &data)
if err != nil {
log.Fatal(err)
}
msgBody := fmt.Sprintf(`
Username: %s
Name: %s
Bio: %s
Location: %s
Email: %s
Twitter: %s
Blog: %s
Followers: %d
Following: %d
Public Repos: %d
Public Gists: %d
Created at: %s
`, data.Login, data.Name, data.Bio, data.Location, data.Email, data.TwitterUsername, data.Blog, data.Followers, data.Following, data.PublicRepos, data.PublicGists, data.CreatedAt)
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: msgBody}
_ = s.Send(reply)
}
func xmppHelp(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
msgBody := `
!ping - Send a ping message
!trains - 🚄 I Like Trains 🚄
!ghuser <username> - Get Github profile infos
!weather <city> - Get the weather forecast
!motd - Get the message of the day
!help - this message
`
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: msgBody}
_ = s.Send(reply)
}
func xmppMOTD(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
_, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: InfoMessages[rand.Intn(len(InfoMessages))]}
_ = s.Send(reply)
}
/**
Handlers
**/
func init() {
s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
s.UpdateGameStatus(0, InfoMessages[rand.Intn(len(InfoMessages))])
if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok {
h(s, i)
}
})
}
func handleMessage(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
_, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
return
}
if strings.HasPrefix(msg.Body, "!") {
cmd := strings.Split(strings.TrimPrefix(msg.Body, "!"), " ")
switch cmd[0] {
case "ping":
xmppPing(s, msg)
case "trains":
xmppTrains(s, msg)
case "password":
xmppPassword(s, msg)
case "weather":
xmppWeather(s, msg)
case "ghuser":
xmppGhUser(s, msg)
case "help":
xmppHelp(s, msg)
case "motd":
xmppMOTD(s, msg)
}
}
}
func errorHandler(err error) {
fmt.Println(err.Error())
}
func dc(wg *sync.WaitGroup) {
defer wg.Done()
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
log.Printf("Logged in as: %v#%v", s.State.User.Username, s.State.User.Discriminator)
})
err := s.Open()
if err != nil {
log.Fatalf("Cannot open the session: %v", err)
}
log.Println("Adding commands...")
registeredCommands := make([]*discordgo.ApplicationCommand, len(commands))
if err != nil {
log.Fatalf("Cannot get guilds: %v", err)
}
for i, v := range commands {
cmd, err := s.ApplicationCommandCreate(s.State.User.ID, *GuildID, v)
if err != nil {
log.Panicf("Cannot create '%v' command: %v", v.Name, err)
}
registeredCommands[i] = cmd
}
s.UpdateGameStatus(0, InfoMessages[rand.Intn(len(InfoMessages))])
defer s.Close()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
log.Println("Press Ctrl+C to exit")
<-stop
if *RemoveCommands {
log.Println("Removing commands...")
for _, v := range registeredCommands {
err := s.ApplicationCommandDelete(s.State.User.ID, *GuildID, v.ID)
if err != nil {
log.Panicf("Cannot delete '%v' command: %v", v.Name, err)
}
}
}
log.Println("Gracefully shutting down.")
os.Exit(0)
}
func xmppBot(wg *sync.WaitGroup) {
defer wg.Done()
var (
host = os.Getenv("HOST")
user = os.Getenv("XMPP_USER")
pass = os.Getenv("PASS")
)
config := xmpp.Config{
TransportConfiguration: xmpp.TransportConfiguration{
Address: host,
},
Jid: user,
Credential: xmpp.Password(pass),
StreamLogger: nil, //os.Stdout,
Insecure: false,
}
router := xmpp.NewRouter()
router.HandleFunc("message", handleMessage)
client, err := xmpp.NewClient(&config, router, errorHandler)
if err != nil {
log.Fatalf("%+v", err)
}
cm := xmpp.NewStreamManager(client, nil)
fmt.Println(cm.Run())
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
log.Println("Press Ctrl+C to exit")
<-stop
cm.Stop()
}
func main() {
rand.Seed(time.Now().Unix())
runners := []func(wg *sync.WaitGroup){}
if os.Getenv("ENABLE_DC") == "true" {
runners = append(runners, dc)
}
if os.Getenv("ENABLE_XMPP") == "true" {
runners = append(runners, xmppBot)
}
var wg sync.WaitGroup
var err error
err = godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
wg.Add(len(runners))
for _, runner := range runners {
go runner(&wg)
}
wg.Wait()
}