Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactoring and user request improvements #344

Merged
merged 5 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading