diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f84d2d5 --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module github.com/jesperbakhandskemager/csgo-hub-discord + +go 1.19 + +require ( + github.com/bwmarrin/discordgo v0.26.1 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/gorilla/websocket v1.4.2 // indirect + golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect + golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e40ca29 --- /dev/null +++ b/go.sum @@ -0,0 +1,15 @@ +github.com/bwmarrin/discordgo v0.26.1 h1:AIrM+g3cl+iYBr4yBxCBp9tD9jR3K7upEjl0d89FRkE= +github.com/bwmarrin/discordgo v0.26.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d8eb105 --- /dev/null +++ b/main.go @@ -0,0 +1,259 @@ +package main + +import ( + "bytes" + "encoding/json" + "flag" + "io" + "log" + "net/http" + "os" + "os/signal" + "strings" + + "github.com/bwmarrin/discordgo" + "gopkg.in/yaml.v3" +) + +const API string = "https://steam.csgohub.xyz/" + +var BotID string + +var s *discordgo.Session + +type YAMLFile struct { + Config Config `yaml:"config"` +} + +type Config struct { + STEAM_KEY string `yaml:"STEAM_KEY"` + DISCORD_TOKEN string `yaml:"DISCORD_TOKEN"` +} + +func ReadConfig() (*Config, error) { + config := &YAMLFile{} + cfgFile, err := os.ReadFile("./config.yaml") + if err != nil { + return nil, err + } + err = yaml.Unmarshal(cfgFile, config) + return &config.Config, err +} + +var ( + GuildID = flag.String("guild", "", "Test guild ID. If not passed - bot registers commands globally") + RemoveCommands = flag.Bool("rmcmd", true, "Remove all commands after shutdowning or not") +) + +func init() { + config, err := ReadConfig() + if err != nil { + panic(err) + } + s, err = discordgo.New("Bot " + config.DISCORD_TOKEN) + if err != nil { + log.Fatalf("Invalid bot parameters: %v", err) + } + u, err := s.User("@me") + if err != nil { + log.Fatal(err) + return + } + + BotID = u.ID +} + +var ( + commands = []*discordgo.ApplicationCommand{ + { + Name: "link-steam", + Description: "Link your steam account", + Type: discordgo.ChatApplicationCommand, + }, + { + Name: "show-team", + Description: "Shows the CS:GO friend codes of the other users in VC", + Type: discordgo.ChatApplicationCommand, + }, + } + + commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ + "link-steam": func(s *discordgo.Session, i *discordgo.InteractionCreate) { + if i.Member == nil { + token := GetToken(i.User.ID) + + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "Your verification link:", + }, + }) + s.ChannelMessageSend(i.ChannelID, API+token) + return + } + sender := i.Member.User.ID + token := GetToken(sender) + userDM, err := s.UserChannelCreate(sender) + if err != nil { + log.Fatal(err) + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "Couldn't send you verification link", + }, + }) + return + } + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "A verification link has been send to your DM's", + }, + }) + s.ChannelMessageSend(userDM.ID, API+token) + + }, + "show-team": func(s *discordgo.Session, i *discordgo.InteractionCreate) { + // Find the guild for that channel. + g, err := s.State.Guild(i.GuildID) + if err != nil { + // Could not find guild. + log.Println("couldn't find guild") + return + } + + var vcChannelId string + var vcUsers []string + + // Look for the message sender in that guild's current voice states. + for _, vs := range g.VoiceStates { + if vs.UserID == i.Member.User.ID { + vcChannelId = vs.ChannelID + } + } + + for _, vs := range g.VoiceStates { + if vs.ChannelID == vcChannelId { + vcUsers = append(vcUsers, vs.UserID) + } + } + var returnString strings.Builder + friends := GetFriendCodes(vcUsers) + for _, friend := range friends { + if friend.DiscordId != "" { + returnString.WriteString("<@" + friend.DiscordId + ">: " + friend.FriendCode + "\n") + } + } + if returnString.String() == "" { + returnString.WriteString("No friend codes found") + } + + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: returnString.String(), + }, + }) + }, + } +) + +type userStruct struct { + Id int `json:"id"` + CreatedAt string `json:"created_at"` + DiscordId string `json:"discord_id"` + FriendCode string `json:"friend_code"` +} + +func GetFriendCode(users []string) []userStruct { + var userArr []userStruct + for _, u := range users { + resp, err := http.Get("http://localhost:8383/api/v1/user/" + u) + if err != nil { + log.Println(err) + log.Println("quiting") + return userArr + } + var userTemp userStruct + bodyBytes, _ := io.ReadAll(resp.Body) + resp.Body.Close() + json.Unmarshal(bodyBytes, &userTemp) + userArr = append(userArr, userTemp) + } + return userArr +} + +func GetFriendCodes(users []string) []userStruct { + var userArr []userStruct + + for _, u := range users { + var us userStruct + us.DiscordId = u + userArr = append(userArr, us) + } + jsonReq, err := json.Marshal(userArr) + if err != nil { + log.Println(err) + return userArr + } + userArr = nil + + resp, err := http.Post("http://localhost:8383/api/v1/users", "application/json; charset=utf-8", bytes.NewBuffer(jsonReq)) + if err != nil { + log.Fatalln(err) + } + + defer resp.Body.Close() + bodyBytes, _ := io.ReadAll(resp.Body) + json.Unmarshal(bodyBytes, &userArr) + + return userArr +} + +func GetToken(discordId string) string { + resp, err := http.Get("http://localhost:8383/api/v1/token/" + discordId) + if err != nil { + log.Println(err) + return "" + } + defer resp.Body.Close() + bodyBytes, _ := io.ReadAll(resp.Body) + bodyString := strings.Replace(string(bodyBytes), "\"", "", -1) + println(bodyString) + return bodyString +} + +func main() { + s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) { log.Println("Bot is up!") }) + s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) { + if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok { + h(s, i) + } + }) + s.Identify.Intents = discordgo.IntentsGuildVoiceStates + err := s.Open() + if err != nil { + log.Fatalf("Cannot open the session: %v", err) + } + defer s.Close() + + createdCommands, err := s.ApplicationCommandBulkOverwrite(s.State.User.ID, *GuildID, commands) + + if err != nil { + log.Fatalf("Cannot register commands: %v", err) + } + + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt) + <-stop + log.Println("Gracefully shutting down") + + if *RemoveCommands { + for _, cmd := range createdCommands { + err := s.ApplicationCommandDelete(s.State.User.ID, *GuildID, cmd.ID) + if err != nil { + log.Fatalf("Cannot delete %q command: %v", cmd.Name, err) + } + } + } +}