Skip to content

Commit

Permalink
Add discord bot feature
Browse files Browse the repository at this point in the history
  • Loading branch information
tr4cks committed May 18, 2024
1 parent 83b642d commit 48cabc4
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 0 deletions.
182 changes: 182 additions & 0 deletions discordbot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package main

import (
"fmt"
"io"
"log"
"os"
"time"

"github.com/bwmarrin/discordgo"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog"
"github.com/tr4cks/power/modules"
)

type DiscordBot struct {
config *DiscordBotConfig
module modules.Module

logger zerolog.Logger
session *discordgo.Session
registeredCommands []*discordgo.ApplicationCommand
}

type DiscordBotConfig struct {
BotToken string `yaml:"bot-token" validate:"required"`
GuildId string `yaml:"guild-id"`
}

func (d *DiscordBot) Start() error {
err := d.session.Open()
if err != nil {
return fmt.Errorf("cannot open the session: %w", err)
}

d.logger.Info().Msg("Adding commands...")
registeredCommands := make([]*discordgo.ApplicationCommand, len(commands))
for i, v := range commands {
cmd, err := d.session.ApplicationCommandCreate(d.session.State.User.ID, d.config.GuildId, v)
if err != nil {
d.logger.Panic().Err(err).Msg(fmt.Sprintf("Cannot create '%v' command: %v", v.Name, err))
}
registeredCommands[i] = cmd
}
d.registeredCommands = registeredCommands

return nil
}

func (d *DiscordBot) Stop() {
d.logger.Info().Msg("Removing commands...")

for _, v := range d.registeredCommands {
err := d.session.ApplicationCommandDelete(d.session.State.User.ID, d.config.GuildId, v.ID)

if err != nil {
log.Panicf("Cannot delete '%v' command: %v", v.Name, err)
}
}

err := d.session.Close()
if err != nil {
d.logger.Error().Err(err).Msg("Unable to close the session")
}

d.logger.Info().Msg("Gracefully shutting down")
}

func (d *DiscordBot) powerOnHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
logger := d.logger.With().Str("username", i.Member.User.Username).Logger()
logger.Info().Msg("A user attempts to switch on the server")

powerState, ledState := d.module.State()

defer func() {
time.Sleep(10 * time.Second)
s.InteractionResponseDelete(i.Interaction)
}()

if powerState.Err != nil {
logger.Error().Err(powerState.Err).Msg("Failed to retrieve POWER state")
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "A problem occurred when switching on the server",
},
})
return
}
if ledState.Err != nil {
logger.Error().Err(ledState.Err).Msg("Failed to retrieve LED state")
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "A problem occurred when switching on the server",
},
})
return
}

if powerState.Value || ledState.Value {
logger.Info().Msg("The server is already switched on")
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "The server is already switched on",
},
})
return
}

err := d.module.PowerOn()
if err != nil {
logger.Error().Err(err).Msg("A problem occurred when switching on the server")
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "A problem occurred when switching on the server",
},
})
return
}
logger.Info().Msg("Server switched on")

s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "The server turns on, give it some time...",
},
})
}

var commands = []*discordgo.ApplicationCommand{
{
Name: "power-on",
Description: "Turns the server on",
},
}

func NewDiscordBot(config *DiscordBotConfig, module modules.Module) (*DiscordBot, error) {
var outputWriter io.Writer = os.Stderr
if gin.Mode() != "release" {
outputWriter = zerolog.ConsoleWriter{Out: os.Stderr}
}
logger := zerolog.
New(outputWriter).
With().
Timestamp().
Str("scope", "discord").
Logger()

session, err := discordgo.New("Bot " + config.BotToken)
if err != nil {
return nil, fmt.Errorf("invalid bot parameters: %w", err)
}

bot := &DiscordBot{config, module, logger, session, nil}

commandHandlers := map[string]func(*discordgo.Session, *discordgo.InteractionCreate){
"power-on": bot.powerOnHandler,
}

session.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok {
h(s, i)
}
})

session.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
logger.Info().
Str("discriminator", s.State.User.Discriminator).
Str("username", s.State.User.Username).
Msg(fmt.Sprintf("Logged in as: %v#%v", s.State.User.Username, s.State.User.Discriminator))
})

return bot, nil
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/tr4cks/power
go 1.20

require (
github.com/bwmarrin/discordgo v0.28.1
github.com/gin-gonic/gin v1.10.0
github.com/go-playground/validator/v10 v10.20.0
github.com/linde12/gowol v0.0.0-20180926075039-797e4d01634c
Expand All @@ -24,6 +25,7 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4=
github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
Expand Down Expand Up @@ -31,6 +33,8 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
Expand Down Expand Up @@ -90,20 +94,26 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
Expand Down
13 changes: 13 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type Config struct {
Username string `validate:"required"`
Password string `validate:"required"`
Module map[string]interface{}
Discord *DiscordBotConfig
}

func parseYAMLFile(filePath string) (*Config, error) {
Expand Down Expand Up @@ -125,6 +126,18 @@ func run(cmd *cobra.Command, args []string) {

srv := runHttpServer(config, module)

if config.Discord != nil {
discordBot, err := NewDiscordBot(config.Discord, module)
if err != nil {
mainLogger.Fatal().Err(err).Msg("Unable to create discord bot")
}
err = discordBot.Start()
if err != nil {
mainLogger.Fatal().Err(err).Msg("Unable to start discord bot")
}
defer discordBot.Stop()
}

// Listen for the interrupt signal.
<-ctx.Done()

Expand Down

0 comments on commit 48cabc4

Please sign in to comment.