Skip to content

Commit

Permalink
refactoring and user request improvements (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
h3mmy authored Jun 3, 2024
2 parents 7b39692 + ccb7a33 commit b0b4da3
Show file tree
Hide file tree
Showing 15 changed files with 321 additions and 238 deletions.
110 changes: 110 additions & 0 deletions bot/arr/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package arr

import (
"fmt"
"strings"

"github.com/h3mmy/bloopyboi/bot/internal/config"
"github.com/h3mmy/bloopyboi/bot/internal/log"
"github.com/h3mmy/bloopyboi/bot/internal/models"
"go.uber.org/zap"
"golift.io/starr"
"golift.io/starr/lidarr"
"golift.io/starr/prowlarr"
"golift.io/starr/radarr"
"golift.io/starr/readarr"
"golift.io/starr/sonarr"
)

type ArrClientMap map[string]starr.APIer
type ArrClientRegister map[starr.App]ArrClientMap

type ArrClientRegistry struct {
meta models.BloopyMeta
logger *zap.Logger
registry ArrClientRegister
}

type ArrClientSet struct {
meta models.BloopyMeta
logger *zap.Logger
clientMap map[string]starr.APIer
}

func NewArrClientSet(clients map[string]starr.APIer) *ArrClientSet {
mta := models.NewBloopyMeta()
lgr := log.NewZapLogger()
return &ArrClientSet{
meta: mta,
logger: lgr,
clientMap: clients,
}
}

func NewArrClientRegistry(controllerName string) *ArrClientRegistry {
mta := models.NewBloopyMeta(controllerName)
lgr := log.NewZapLogger().Named("arr_client_registry")
return &ArrClientRegistry{
meta: mta,
logger: lgr,
registry: make(map[starr.App]ArrClientMap),
}
}

func BuildArrClient(cfg *config.ArrClientConfig) (starr.APIer, error) {
params := cfg.ToParams()
starrConfig := starr.New(
params[config.ApiKey],
params[config.AppURL],
starr.DefaultTimeout,
)
switch strings.ToLower(cfg.Type) {
case starr.Sonarr.Lower():
return sonarr.New(starrConfig), nil
case starr.Radarr.Lower():
return radarr.New(starrConfig), nil
case starr.Readarr.Lower():
return readarr.New(starrConfig), nil
case starr.Prowlarr.Lower():
return prowlarr.New(starrConfig), nil
case starr.Lidarr.Lower():
return lidarr.New(starrConfig), nil
}
return nil, fmt.Errorf("Could not build client %s of type: %s", cfg.Name, cfg.Type)
}

func (s *ArrClientRegistry) AddClient(cfg *config.ArrClientConfig) error {
logger := s.logger.With(zap.String("clientName", cfg.Name)).With(zap.String("clientType", cfg.Type))
key := starr.App(cfg.Type)
if val, ok := s.registry[key]; ok {
logger.Debug("register exists for client type.")
client, err := BuildArrClient(cfg)
if err != nil {
logger.Error("error building client", zap.Error(err))
return err
}
if _, ok := val[cfg.Name]; ok {
logger.Warn("entry already exists with client Name. Existing entry will be overwritten.")
}
val[cfg.Name] = client
logger.Debug("added client to register")
} else {
logger.Debug("no existing entries for client type. adding new entry")
cMap := make(map[string]starr.APIer)
client, err := BuildArrClient(cfg)
if err != nil {
logger.Error("error building client", zap.Error(err))
return err
}
cMap[cfg.Name] = client
logger.Debug("added client to registry")
s.registry[key] = cMap
logger.Debug("Added new type to register")
}

return nil
}

// func (s *ArrClientRegistry) GetClientSet(starr.App) (starr.APIer, error) {
// if cMap, ok := s.
// }
File renamed without changes.
13 changes: 11 additions & 2 deletions bot/handlers/user_requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,22 @@ func (c *UserRequestCommand) GetAppCommandHandler() func(s *discordgo.Session, i
}
} else {
c.logger.Info("got book requests for user", zap.Int("count", len(allBookReqs)), zap.String("username", discordUser.Username))
bookEmbeds := []*discordgo.MessageEmbed{}
embedLimit := 3
for i, req := range allBookReqs {
if i<embedLimit {
bookEmbeds = append(bookEmbeds, c.bookSvc.BuildBookRequestStatusAsEmbed(context.TODO(), req))
} else {
break
}
}
err = s.InteractionRespond(i.Interaction,
&discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("Here are your book requests: %s", allBookReqs),
Content: fmt.Sprintf("You have %d total book requests. I can only show %d at a time", len(allBookReqs), embedLimit),
Flags: discordgo.MessageFlagsEphemeral, // only show to user who requested it
Embeds: nil,
Embeds: bookEmbeds,
},
})
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions bot/internal/config/arr_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package config

type ArrClientParam string

const ApiKey = "apiKey"
const AppURL = "appUrl"

type ArrClientConfig struct {
Name string
Type string
URL string
ApiKey string
}

func (cfg *ArrClientConfig) ToParams() map[ArrClientParam]string {
params := make(map[ArrClientParam]string, 2)
params[ApiKey] = cfg.ApiKey
params[AppURL] = cfg.URL
return params
}
60 changes: 1 addition & 59 deletions bot/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,65 +23,7 @@ type AppConfig struct {
LogLevel string `mapstructure:"logLevel"`
DBConfig *PostgresConfig `mapstructure:"db"`
FeatureMap map[string]FeatureConfig
}

type DiscordConfig struct {
Token string `mapstructure:"token"`
AppName string `mapstructure:"name"`
AppID int64 `mapstructure:"appId"`
GuildConfigs []DiscordGuildConfig `mapstructure:"guilds"`
}

// Guild Specific Config
type DiscordGuildConfig struct {
GuildId string `mapstructure:"id"`
// Channel to be used for bot-specific announcements. If empty, no announcement will be sent.
Announcement *AnnouncementConfig `mapstructure:"announcement"`
GuildCommandConfig []GuildCommandConfig `mapstructure:"commands"`
}

// Config for dedicated announcement channel. If empty, no announcement will be sent.
// the bot MUST have MANAGE_CHANNEL permissions
// This will be a GUILD_ANNOUNCEMENT type channel https://discord.com/developers/docs/resources/channel
type AnnouncementConfig struct {
// Channel to be used for bot-specific announcements.
Channel struct {
Name string `mapstructure:"name"`
ID string `mapstructure:"id"`
}
NSFW bool `mapstructure:"nsfw"`
}

type GuildCommandConfig struct {
Name string `mapstructure:"name"`
Enabled bool `mapstructure:"enabled"`
// Allowed channels for command to be used in. If empty, command can be used in any channel.
// If not empty, command can only be used in channels listed here.
// Channels are case sensitive.
// Example:
// "channels": [
// "#general",
// "#random"
// ]
// This command can only be used in #general and #random channels.
// If empty, command can be used in any channel.
// If not empty, command can only be used in channels listed here.
// Channels are case sensitive.
// Example:
// "channels": [
// "#general",
// "#random"
// ]
// This command can only be used in #general and #random channels.
// If empty, command can be used in any channel.
// If not empty, command can only be used in channels listed here.
// Channels are case sensitive.
// Example:
// "channels": [
// "#general",
Channels []int64 `mapstructure:"channels"`
// Roles allowed to use command. If empty, command can be used by anyone.
Roles []int64 `mapstructure:"roles"`
Arrs *[]ArrClientConfig `mapstructure:"arrs"`
}

// Feature Specific Config
Expand Down
60 changes: 60 additions & 0 deletions bot/internal/config/discord_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package config

type DiscordConfig struct {
Token string `mapstructure:"token"`
AppName string `mapstructure:"name"`
AppID int64 `mapstructure:"appId"`
GuildConfigs []DiscordGuildConfig `mapstructure:"guilds"`
}

// Guild Specific Config
type DiscordGuildConfig struct {
GuildId string `mapstructure:"id"`
// Channel to be used for bot-specific announcements. If empty, no announcement will be sent.
Announcement *AnnouncementConfig `mapstructure:"announcement"`
GuildCommandConfig []GuildCommandConfig `mapstructure:"commands"`
}

// Config for dedicated announcement channel. If empty, no announcement will be sent.
// the bot MUST have MANAGE_CHANNEL permissions
// This will be a GUILD_ANNOUNCEMENT type channel https://discord.com/developers/docs/resources/channel
type AnnouncementConfig struct {
// Channel to be used for bot-specific announcements.
Channel struct {
Name string `mapstructure:"name"`
ID string `mapstructure:"id"`
}
NSFW bool `mapstructure:"nsfw"`
}

type GuildCommandConfig struct {
Name string `mapstructure:"name"`
Enabled bool `mapstructure:"enabled"`
// Allowed channels for command to be used in. If empty, command can be used in any channel.
// If not empty, command can only be used in channels listed here.
// Channels are case sensitive.
// Example:
// "channels": [
// "#general",
// "#random"
// ]
// This command can only be used in #general and #random channels.
// If empty, command can be used in any channel.
// If not empty, command can only be used in channels listed here.
// Channels are case sensitive.
// Example:
// "channels": [
// "#general",
// "#random"
// ]
// This command can only be used in #general and #random channels.
// If empty, command can be used in any channel.
// If not empty, command can only be used in channels listed here.
// Channels are case sensitive.
// Example:
// "channels": [
// "#general",
Channels []int64 `mapstructure:"channels"`
// Roles allowed to use command. If empty, command can be used by anyone.
Roles []int64 `mapstructure:"roles"`
}
Loading

0 comments on commit b0b4da3

Please sign in to comment.