More rearranging, add basic API server

This commit is contained in:
denverquane
2023-02-13 16:58:51 -05:00
parent ff595e8acb
commit 42ad27fe66
24 changed files with 88 additions and 212 deletions

View File

@ -44,6 +44,8 @@ COPY --from=builder /app /app
COPY ./locales/ /app/locales
COPY ./storage/postgres.sql /app/storage/postgres.sql
# Port used for AMU API
EXPOSE 5000
# Port used for health/liveliness checks
EXPOSE 8080
# Port used for prometheus metrics

12
TODO.md
View File

@ -1,12 +0,0 @@
- [ ] Search for unused functions/code relating to old command processing
- [X] Reintegrate Redis-based user rate limiting on fast command invocation
- [X] Restrict premium invites viewing to admins only
- [X] Search for (and update) commands with higher guild permissions needed for invocation
- [ ] Unit tests where appropriate (such as complex control flow for premium)
- [X] Integrate subcommands where helpful (/link colors for starters)
- [ ] Make commands package-private
- [ ] Localization and i18n keys
- [ ] Integrate concise/minimal responses (using emojis) to minimize translation efforts and increase readability
- [X] Refactor `/privacy` to use command options and subcommands
- [ ] Add galactus endpoints to allow website to fetch current command list
- [ ] Migrate link/unlink functionality to right-click User context menu actions

29
discord/api.go Normal file
View File

@ -0,0 +1,29 @@
package discord
import (
"encoding/json"
"github.com/gorilla/mux"
"net/http"
)
func (bot *Bot) StartAPIServer(port string) {
r := mux.NewRouter()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// TODO For any higher-sensitivity info in the future, this should properly identify the origin specifically
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length")
info := bot.getInfo()
data, err := json.Marshal(info)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
} else {
w.Write(data)
}
})
http.ListenAndServe(":"+port, r)
}

View File

@ -4,10 +4,10 @@ import (
"context"
"errors"
"fmt"
"github.com/automuteus/automuteus/v7/amongus"
"github.com/automuteus/automuteus/v7/discord/command"
"github.com/automuteus/automuteus/v7/discord/tokenprovider"
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/amongus"
"github.com/automuteus/automuteus/v7/pkg/discord"
"github.com/automuteus/automuteus/v7/pkg/game"
"github.com/automuteus/automuteus/v7/pkg/premium"
@ -149,25 +149,7 @@ func (bot *Bot) InitTokenProvider(tp *tokenprovider.TokenProvider) {
}
func (bot *Bot) StartMetricsServer(nodeID string) error {
return metrics.PrometheusMetricsServer(bot.RedisInterface.client, nodeID, "2112")
}
func (bot *Bot) StatsRefreshWorker(dur time.Duration) {
for {
users := rediskey.GetTotalUsers(context.Background(), bot.RedisInterface.client)
if users == rediskey.NotFound {
log.Println("Refreshing user stats with worker")
rediskey.RefreshTotalUsers(context.Background(), bot.RedisInterface.client, bot.PostgresInterface.Pool)
}
games := rediskey.GetTotalGames(context.Background(), bot.RedisInterface.client)
if games == rediskey.NotFound {
log.Println("Refreshing game stats with worker")
rediskey.RefreshTotalGames(context.Background(), bot.RedisInterface.client, bot.PostgresInterface.Pool)
}
time.Sleep(dur)
}
return server.PrometheusMetricsServer(bot.RedisInterface.client, nodeID, "2112")
}
func (bot *Bot) Close() {
@ -272,7 +254,7 @@ func (bot *Bot) forceEndGame(gsr GameStateRequest) {
deleted := dgs.DeleteGameStateMsg(bot.PrimarySession, true)
if deleted {
go metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 1)
go server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 1)
}
bot.RedisInterface.SetDiscordGameState(dgs, lock)
@ -311,9 +293,9 @@ func (bot *Bot) RefreshGameStateMessage(gsr GameStateRequest, sett *settings.Gui
created := dgs.CreateMessage(bot.PrimarySession, bot.gameStateResponse(dgs, sett), dgs.GameStateMsg.MessageChannelID, dgs.GameStateMsg.LeaderID)
if deleted && created {
go metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 2)
go server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 2)
} else if deleted || created {
go metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 1)
go server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 1)
}
bot.RedisInterface.SetDiscordGameState(dgs, lock)

View File

@ -2,7 +2,7 @@ package discord
import (
"fmt"
"github.com/automuteus/automuteus/v7/amongus"
"github.com/automuteus/automuteus/v7/pkg/amongus"
"github.com/automuteus/automuteus/v7/pkg/settings"
"github.com/bwmarrin/discordgo"
"github.com/nicksnyder/go-i18n/v2/i18n"

View File

@ -5,8 +5,8 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/automuteus/automuteus/v7/amongus"
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/amongus"
"github.com/automuteus/automuteus/v7/pkg/discord"
"github.com/automuteus/automuteus/v7/pkg/game"
"github.com/automuteus/automuteus/v7/pkg/settings"
@ -127,7 +127,7 @@ func (bot *Bot) SubscribeToGameByConnectCode(guildID, connectCode string, endGam
"VoiceChannel": discord.MentionByChannelID(readOnlyDgs.VoiceChannel),
},
))
metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 1)
server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 1)
}
correlatedUserID = userID
case task.GameOverJob:
@ -166,10 +166,10 @@ func (bot *Bot) SubscribeToGameByConnectCode(guildID, connectCode string, endGam
}
msg, err := bot.PrimarySession.ChannelMessageSendEmbed(channelID, embed)
if delTime > 0 && err == nil {
metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 2)
server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 2)
go MessageDeleteWorker(bot.PrimarySession, msg.ChannelID, msg.ID, time.Minute*time.Duration(delTime))
} else if err == nil {
metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 1)
server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 1)
}
}
go dumpGameToPostgres(*dgs, bot.PostgresInterface, gameOverResult)

View File

@ -1,7 +1,7 @@
package discord
import (
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/settings"
"sync"
"time"
@ -134,7 +134,7 @@ func (bot *Bot) DispatchRefreshOrEdit(readOnlyDgs *GameState, dgsRequest GameSta
} else {
edited := readOnlyDgs.dispatchEdit(bot.PrimarySession, bot.gameStateResponse(readOnlyDgs, sett))
if edited {
metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageEdit, 1)
server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageEdit, 1)
}
}
}

View File

@ -5,7 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/rediskey"
"github.com/automuteus/automuteus/v7/storage"
"github.com/bsm/redislock"
@ -57,7 +57,7 @@ func (bot *Bot) refreshGameLiveness(code string) {
func (bot *Bot) rateLimitEventCallback(_ *discordgo.Session, rl *discordgo.RateLimit) {
log.Println(rl.Message)
metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.InvalidRequest, 1)
server.RecordDiscordRequests(bot.RedisInterface.client, server.InvalidRequest, 1)
}
func (redisInterface *RedisInterface) AddUniqueGuildCounter(guildID string) {

View File

@ -4,13 +4,13 @@ import (
"bytes"
"fmt"
"github.com/automuteus/automuteus/v7/discord/command"
"github.com/automuteus/automuteus/v7/pkg/amongus"
"github.com/automuteus/automuteus/v7/pkg/discord"
"github.com/automuteus/automuteus/v7/pkg/settings"
"os"
"strings"
"time"
"github.com/automuteus/automuteus/v7/amongus"
"github.com/automuteus/automuteus/v7/discord/setting"
"github.com/automuteus/automuteus/v7/pkg/game"
"github.com/bwmarrin/discordgo"

View File

@ -3,6 +3,7 @@ package discord
import (
"encoding/json"
"fmt"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/storage"
"log"
"regexp"
@ -13,7 +14,6 @@ import (
redis_common "github.com/automuteus/automuteus/v7/common"
"github.com/automuteus/automuteus/v7/discord/command"
"github.com/automuteus/automuteus/v7/discord/setting"
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/pkg/discord"
"github.com/automuteus/automuteus/v7/pkg/premium"
"github.com/automuteus/automuteus/v7/pkg/settings"
@ -133,7 +133,7 @@ func (bot *Bot) slashCommandHandler(s *discordgo.Session, i *discordgo.Interacti
if interactionLock == nil {
return nil
}
defer metrics.RecordDiscordRequests(bot.RedisInterface.client, metrics.MessageCreateDelete, 1)
defer server.RecordDiscordRequests(bot.RedisInterface.client, server.MessageCreateDelete, 1)
defer interactionLock.Release(ctx)
sett := bot.StorageInterface.GetGuildSettings(i.GuildID)

View File

@ -3,7 +3,7 @@ package tokenprovider
import (
"context"
"encoding/json"
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/rediskey"
"github.com/automuteus/automuteus/v7/pkg/task"
"github.com/go-redis/redis/v8"
@ -11,10 +11,10 @@ import (
)
func RecordDiscordRequestsByCounts(client *redis.Client, counts task.MuteDeafenSuccessCounts) {
metrics.RecordDiscordRequests(client, metrics.MuteDeafenOfficial, counts.Official)
metrics.RecordDiscordRequests(client, metrics.MuteDeafenWorker, counts.Worker)
metrics.RecordDiscordRequests(client, metrics.MuteDeafenCapture, counts.Capture)
metrics.RecordDiscordRequests(client, metrics.InvalidRequest, counts.RateLimit)
server.RecordDiscordRequests(client, server.MuteDeafenOfficial, counts.Official)
server.RecordDiscordRequests(client, server.MuteDeafenWorker, counts.Worker)
server.RecordDiscordRequests(client, server.MuteDeafenCapture, counts.Capture)
server.RecordDiscordRequests(client, server.InvalidRequest, counts.RateLimit)
}
func (tokenProvider *TokenProvider) attemptOnSecondaryTokens(guildID, userID string, tokenSubset map[string]struct{}, request task.UserModify) string {

View File

@ -1,7 +1,7 @@
package discord
import (
"github.com/automuteus/automuteus/v7/amongus"
"github.com/automuteus/automuteus/v7/pkg/amongus"
"github.com/bwmarrin/discordgo"
)

View File

@ -2,9 +2,8 @@ package discord
import (
"fmt"
"github.com/automuteus/automuteus/v7/pkg/amongus"
"strings"
"github.com/automuteus/automuteus/v7/amongus"
)
type UserDataSet map[string]UserData

View File

@ -1,4 +1,4 @@
package metrics
package server
import (
"github.com/gorilla/mux"

View File

@ -1,4 +1,4 @@
package metrics
package server
import (
"context"

View File

@ -3,18 +3,18 @@
"commands.debug.clear.user.success" = "Successfully cleared cached usernames for {{.User}}"
"commands.debug.view.error" = "Encountered an error trying to view debug information: {{.Error}}"
"commands.debug.view.user.empty" = "I don't have any saved usernames for {{.User}}"
"commands.debug.view.user.success" = "I have the following cached usernames for {{.User}}:\n```\n{{.Cached}}\n```"
"commands.debug.view.user.success" = "I have the following cached usernames for {{.User}}:\\n```\\n{{.Cached}}\\n```"
"commands.dm" = "Sorry, I don't respond to DMs. Please execute the command in a text channel instead."
"commands.download.cooldown" = "Sorry, `{{.Category}}` data can only downloaded once every 24 hours!\n\nPlease wait {{.Duration}} and then try again"
"commands.download.cooldown" = "Sorry, `{{.Category}}` data can only downloaded once every 24 hours!\\n\\nPlease wait {{.Duration}} and then try again"
"commands.download.file.success" = "Here's that file for you!"
"commands.download.guild.confirmation" = "⚠️**Are you sure?**⚠️\nIf you download the `{{.Category}}` data now, it will not be downloadable again for 24 hours!"
"commands.download.guild.confirmation" = "⚠️**Are you sure?**⚠️\\nIf you download the `{{.Category}}` data now, it will not be downloadable again for 24 hours!"
"commands.download.guild.error" = "I encountered an error fetching your stats for download: {{.Error}}"
"commands.download.nogold" = "Downloading AutoMuteUs data is reserved for Gold subscribers only!"
"commands.error" = "Error executing `{{.Command}}`: `{{.Error}}`"
"commands.error.nogame" = "No game is currently running."
"commands.error.reinvite" = "I'm missing the following required permissions to function properly in this server or channel:\n```\n{{.Perm}}```\nCheck the permissions for the Text/Voice channel {{.Channel}}, but you may also need to re-invite me [here](https://add.automute.us)"
"commands.help.subtitle" = "[View the Github Project](https://github.com/automuteus/automuteus) or [Join our Discord](https://discord.gg/ZkqZSWF)\n\nType `/help <command>` to see more details on a command!"
"commands.help.title" = "AutoMuteUs Bot Commands:\n"
"commands.error.reinvite" = "I'm missing the following required permissions to function properly in this server or channel:\\n```\\n{{.Perm}}```\\nCheck the permissions for the Text/Voice channel {{.Channel}}, but you may also need to re-invite me [here](https://add.automute.us)"
"commands.help.subtitle" = "[View the Github Project](https://github.com/automuteus/automuteus) or [Join our Discord](https://discord.gg/ZkqZSWF)\\n\\nType `/help <command>` to see more details on a command!"
"commands.help.title" = "AutoMuteUs Bot Commands:\\n"
"commands.info.activegames" = "Active Games"
"commands.info.creator" = "Creator"
"commands.info.footer" = "{{.Version}}-{{.Commit}} | Shard {{.ID}}/{{.Num}}"
@ -30,26 +30,26 @@
"commands.link.nogamedata" = "No game data found for the color `{{.Color}}`"
"commands.link.noplayer" = "No player in the current game was detected for {{.UserMention}}"
"commands.link.success" = "Successfully linked {{.UserMention}} to an in-game player with the color: `{{.Color}}`"
"commands.new.lockout" = "If I start any more games, Discord will lock me out, or throttle the games I'm running! 😦\nPlease try again in a few minutes, or consider AutoMuteUs Premium (`/premium info`)\nCurrent Games: {{.Games}}"
"commands.new.lockout" = "If I start any more games, Discord will lock me out, or throttle the games I'm running! 😦\\nPlease try again in a few minutes, or consider AutoMuteUs Premium (`/premium info`)\\nCurrent Games: {{.Games}}"
"commands.new.nochannel" = "Please join a voice channel before starting a match!"
"commands.new.success" = "Click the following link to link your capture: \n <{{.hyperlink}}>\n\nDon't have the capture installed? Latest version [here]({{.downloadURL}})\n\nTo link your capture manually:"
"commands.new.success" = "Click the following link to link your capture: \\n <{{.hyperlink}}>\\n\\nDon't have the capture installed? Latest version [here]({{.downloadURL}})\\n\\nTo link your capture manually:"
"commands.new.success.code" = "Code"
"commands.new.success.url" = "URL"
"commands.no_permissions" = "Sorry, you don't have the required permissions to issue that command."
"commands.privacy.info" = "AutoMuteUs privacy and data collection details.\nMore details [here](https://github.com/automuteus/automuteus/blob/master/PRIVACY.md)"
"commands.privacy.opt.error" = "❌ I encountered an error changing your opt in/out status:\n`{{.Error}}`"
"commands.privacy.info" = "AutoMuteUs privacy and data collection details.\\nMore details [here](https://github.com/automuteus/automuteus/v7/blob/master/PRIVACY.md)"
"commands.privacy.opt.error" = "❌ I encountered an error changing your opt in/out status:\\n`{{.Error}}`"
"commands.privacy.opt.success" = "✅ I successfully changed your opt in/out status"
"commands.privacy.showme.cache" = "❗ Here's your cached in-game names:"
"commands.privacy.showme.nocache" = "❌ I don't have any cached player names stored for you!"
"commands.privacy.showme.optin" = "❗ You are opted **in** to data collection for game statistics"
"commands.privacy.showme.optout" = "❌ You are opted **out** of data collection for game statistics, or you haven't played a game yet"
"commands.stats.guild.reset.confirmation" = "⚠️**Are you sure?**⚠️\nDo you really want to reset the stats for **{{.Guild}}**?\nThis process cannot be undone!"
"commands.stats.guild.reset.confirmation" = "⚠️**Are you sure?**⚠️\\nDo you really want to reset the stats for **{{.Guild}}**?\\nThis process cannot be undone!"
"commands.stats.guild.reset.error" = "Encountered an error resetting the stats for this guild: {{.Error}}"
"commands.stats.guild.reset.success" = "Successfully reset the stats for **{{.Guild}}**!"
"commands.stats.reset.button.cancel" = "Cancel"
"commands.stats.reset.button.proceed" = "Confirm"
"commands.stats.reset.canceled" = "Operation has been canceled"
"commands.stats.user.reset.confirmation" = "⚠️**Are you sure?**⚠️\nDo you really want to reset the stats for {{.User}}?\nThis process cannot be undone!"
"commands.stats.user.reset.confirmation" = "⚠️**Are you sure?**⚠️\\nDo you really want to reset the stats for {{.User}}?\\nThis process cannot be undone!"
"commands.stats.user.reset.error" = "Encountered an error resetting the stats for {{.User}}: {{.Error}}"
"commands.stats.user.reset.notfound" = "Failed to gather user from message!"
"commands.stats.user.reset.success" = "Successfully reset the stats for {{.User}}!"
@ -57,7 +57,7 @@
"commands.unlink.success" = "Successfully unlinked {{.UserMention}}"
"discordGameState.ToEmojiEmbedFields.Unlinked" = "Unlinked"
"eventHandler.gameOver.deleteMessageFooter" = "Deleting message {{.Mins}} mins from:"
"eventHandler.gameOver.matchID" = "Game Over! View the match's stats using Match ID: `{{.MatchID}}`\n{{.Winners}}"
"eventHandler.gameOver.matchID" = "Game Over! View the match's stats using Match ID: `{{.MatchID}}`\\n{{.Winners}}"
"locale.language.name" = "English"
"processplayer.error" = "Error in muting or deafening {{.User}}. Does the bot have permissions to mute/deafen users in {{.VoiceChannel}}?"
"responses.gameStatsEmbed.NoPremium" = "Detailed match stats are only available for AutoMuteUs Premium users; type `/premium` to learn more"
@ -79,7 +79,7 @@
"responses.lobbyMetaEmbedFields.Region" = "🌎 REGION"
"responses.lobbyMetaEmbedFields.RoomCode" = "🔒 ROOM CODE"
"responses.lobbyMetaEmbedFields.VoiceChannel" = "Voice Channel"
"responses.makeDescription.GameNotRunning" = "\n⚠ **Bot is Paused!** ⚠\n\n"
"responses.makeDescription.GameNotRunning" = "\\n⚠ **Bot is Paused!** ⚠\\n\\n"
"responses.matchStatsEmbed.Title" = "Game `{{.MatchID}}`"
"responses.menuMessage.Linked.FooterText" = "(Enter a game lobby in Among Us to start the match)"
"responses.menuMessage.Title" = "Main Menu"
@ -87,14 +87,14 @@
"responses.nonPremiumSetting.Desc" = "Sorry, but that setting is reserved for AutoMuteUs Premium users! See `/premium` for details"
"responses.premiumInviteResponse.Title" = "Premium Bot Invites"
"responses.premiumInviteResponse.desc" = "{{.Tier}} users have access to {{.Count}} Priority mute bots: invites provided below!"
"responses.premiumInviteResponseNoAccess.desc" = "{{.Tier}} users don't have access to Priority mute bots!\nPlease type `/premium` to see more details about AutoMuteUs Premium"
"responses.premiumInviteResponseNoAccess.desc" = "{{.Tier}} users don't have access to Priority mute bots!\\nPlease type `/premium` to see more details about AutoMuteUs Premium"
"responses.premiumResponse.FastMute" = "🙊 Fast Mute/Deafen"
"responses.premiumResponse.FastMuteDesc" = "Premium users get access to \"helper\" bots that make sure muting is fast!"
"responses.premiumResponse.FreeDescription" = "Check out the cool things that Premium AutoMuteUs has to offer!\n\n[Get AutoMuteUs Premium]({{.BaseURL}}{{.GuildID}})\n"
"responses.premiumResponse.FreeDescription" = "Check out the cool things that Premium AutoMuteUs has to offer!\\n\\n[Get AutoMuteUs Premium]({{.BaseURL}}{{.GuildID}})\\n"
"responses.premiumResponse.Invites" = "View a list of Premium bots you can invite with `/premium invites`!"
"responses.premiumResponse.PremiumDescription" = "Looks like you have AutoMuteUs **{{.Tier}}**{{.DaysString}}! Thanks for the support!\n\nBelow are some of the benefits you can customize with your Premium status!"
"responses.premiumResponse.PremiumDescription" = "Looks like you have AutoMuteUs **{{.Tier}}**{{.DaysString}}! Thanks for the support!\\n\\nBelow are some of the benefits you can customize with your Premium status!"
"responses.premiumResponse.PremiumDescriptionDaysRemaining" = " for another {{.Days}} days"
"responses.premiumResponse.PremiumDescriptionExpired" = "Oh no! It looks like you used to have AutoMuteUs **{{.Tier}}**, but it **expired {{.Days}} days ago**! 😦\n\nPlease consider re-subscribing here: [Get AutoMuteUs Premium]({{.BaseURL}}{{.GuildID}})"
"responses.premiumResponse.PremiumDescriptionExpired" = "Oh no! It looks like you used to have AutoMuteUs **{{.Tier}}**, but it **expired {{.Days}} days ago**! 😦\\n\\nPlease consider re-subscribing here: [Get AutoMuteUs Premium]({{.BaseURL}}{{.GuildID}})"
"responses.premiumResponse.PriorityGameAccess" = "👑 Priority Game Access"
"responses.premiumResponse.PriorityGameAccessDesc" = "If the Bot is under heavy load, Premium users will always be able to make new games!"
"responses.premiumResponse.Settings" = "🛠 Special Settings"
@ -103,10 +103,10 @@
"responses.premiumResponse.Stats" = "📊 Game Stats and Leaderboards"
"responses.premiumResponse.StatsDesc" = "Premium users have access to a full suite of player stats and leaderboards!"
"responses.premiumResponse.Title" = "💎 AutoMuteUs Premium 💎"
"responses.premiumResponse.TopGG" = "or\n[Vote for the Bot on top.gg](https://top.gg/bot/753795015830011944) for 12 Hours of Free Premium!\n(One time per user)\n\n"
"responses.premiumResponse.Trial" = "You're currently on a TRIAL of AutoMuteUs Premium\n\n"
"responses.premiumResponse.TopGG" = "or\\n[Vote for the Bot on top.gg](https://top.gg/bot/753795015830011944) for 12 Hours of Free Premium!\\n(One time per user)\\n\\n"
"responses.premiumResponse.Trial" = "You're currently on a TRIAL of AutoMuteUs Premium\\n\\n"
"responses.settingResponse.Description" = "Type `/settings <setting>` to change a setting from those listed below"
"responses.settingResponse.PremiumNoThanks" = "The following settings are only for AutoMuteUs premium users.\nType `/premium` to learn more!"
"responses.settingResponse.PremiumNoThanks" = "The following settings are only for AutoMuteUs premium users.\\nType `/premium` to learn more!"
"responses.settingResponse.PremiumThanks" = "Thanks for being an AutoMuteUs Premium user!"
"responses.settingResponse.Title" = "Settings"
"responses.stats.Exiled" = "Exiled"
@ -142,7 +142,7 @@
"responses.userStatsEmbed.WorstTeammateServerCrewmate" = "Worst Crewmate Team"
"responses.userStatsEmbed.WorstTeammateServerImpostor" = "Worst Impostor Team"
"settings.ConstructEmbedForSetting.Fields.CurrentValue" = "Current Value"
"settings.ConstructEmbedForSetting.StarterDesc" = "Type `/settings {{.Command}}` to view or change this setting.\n\n"
"settings.ConstructEmbedForSetting.StarterDesc" = "Type `/settings {{.Command}}` to view or change this setting.\\n\\n"
"settings.SettingAdminUserIDs.alreadyBotAdmin" = "{{.User}} was already a bot admin!"
"settings.SettingAdminUserIDs.clearAdmins" = "Clearing all AdminUserIDs!"
"settings.SettingAdminUserIDs.newBotAdmin" = "{{.User}} is now a bot admin!"
@ -154,7 +154,7 @@
"settings.SettingAutoRefresh.Unrecognized" = "{{.Arg}} is not a true/false value. See `/settings auto-refresh` for usage"
"settings.SettingDelays.Phase.UNINITIALIZED" = "I don't know what `{{.PhaseName}}` is. The list of game phases are `Lobby`, `Tasks` and `Discussion`."
"settings.SettingDelays.delayBetweenPhases" = "Currently, the delay when passing from `{{.PhaseA}}` to `{{.PhaseB}}` is {{.OldDelay}}."
"settings.SettingDelays.missingPhases" = "The list of game phases are `Lobby`, `Tasks` and `Discussion`.\nYou need to type both phases the game is transitioning from and to to change the delay."
"settings.SettingDelays.missingPhases" = "The list of game phases are `Lobby`, `Tasks` and `Discussion`.\\nYou need to type both phases the game is transitioning from and to to change the delay."
"settings.SettingDelays.setDelayBetweenPhases" = "The delay when passing from `{{.PhaseA}}` to `{{.PhaseB}}` changed from {{.OldDelay}} to {{.NewDelay}}."
"settings.SettingDelays.wrongNumber" = "`{{.Number}}` is not a valid number! Please try again"
"settings.SettingDisplayRoomCode.AlwaysOrNever" = "From now on, I will {{.Arg}} display the room code in the message"
@ -163,7 +163,7 @@
"settings.SettingLanguage.notFound" = "Language not found! Available language codes: {{.Langs}}"
"settings.SettingLanguage.notLoaded" = "Localization files were not loaded! {{.Langs}}"
"settings.SettingLanguage.set" = "Localization is set to `{{.LangCode}}`"
"settings.SettingLanguage.set.needsTranslations" = "Localization is set to `{{.LangCode}}`, but it looks like the translations aren't complete!\n\nHelp us translate the bot [here](https://automuteus.crowdin.com/)!"
"settings.SettingLanguage.set.needsTranslations" = "Localization is set to `{{.LangCode}}`, but it looks like the translations aren't complete!\\n\\nHelp us translate the bot [here](https://automuteus.crowdin.com/)!"
"settings.SettingLanguage.tooShort" = "Sorry, the language code is short. Available language codes: {{.Langs}}."
"settings.SettingLeaderboardMention.False" = "From now on, I'll use player nicknames/usernames in the leaderboard"
"settings.SettingLeaderboardMention.True" = "From now on, I'll mention players directly in the leaderboard"
@ -182,7 +182,7 @@
"settings.SettingMatchSummaryChannel.invalidChannelID" = "{{.channelID}} is not a valid text channel ID or mention!"
"settings.SettingMatchSummaryChannel.withChannelID" = "Match Summary text channel ID changed to {{.channelID}}!"
"settings.SettingMuteSpectators.false_muteSpectators" = "I will no longer mute spectators like dead players"
"settings.SettingMuteSpectators.true_noMuteSpectators" = "I will now mute spectators just like dead players. \n**Note, this can cause delays or slowdowns when not self-hosting, or using a Premium worker bot!**"
"settings.SettingMuteSpectators.true_noMuteSpectators" = "I will now mute spectators just like dead players. \\n**Note, this can cause delays or slowdowns when not self-hosting, or using a Premium worker bot!**"
"settings.SettingPermissionRoleIDs.alreadyBotOperator" = "That role was already a bot operator!"
"settings.SettingPermissionRoleIDs.clearRoles" = "Clearing all PermissionRoleIDs!"
"settings.SettingPermissionRoleIDs.newBotOperator" = "I successfully added that role as bot operators!"

44
main.go
View File

@ -5,10 +5,9 @@ import (
"fmt"
"github.com/automuteus/automuteus/v7/discord/command"
"github.com/automuteus/automuteus/v7/discord/tokenprovider"
"github.com/automuteus/automuteus/v7/metrics"
"github.com/automuteus/automuteus/v7/internal/server"
"github.com/automuteus/automuteus/v7/pkg/capture"
"github.com/automuteus/automuteus/v7/pkg/locale"
"github.com/automuteus/automuteus/v7/pkg/rediskey"
storage2 "github.com/automuteus/automuteus/v7/pkg/storage"
"github.com/bwmarrin/discordgo"
"io"
@ -181,7 +180,7 @@ func discordMainWrapper() error {
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
go metrics.StartHealthCheckServer("8080")
go server.StartHealthCheckServer("8080")
topGGToken := os.Getenv("TOP_GG_TOKEN")
@ -223,14 +222,13 @@ func discordMainWrapper() error {
}
tokenProvider.PopulateAndStartSessions(extraTokens)
// indicate to Kubernetes that we're ready to start receiving traffic
metrics.GlobalReady = true
server.GlobalReady = true
go bots[0].SetVersionAndCommit(version, commit)
go bots[0].StartMetricsServer(os.Getenv("SCW_NODE_ID"))
// TODO this is ugly. Should make a proper cronjob to refresh the stats regularly
go bots[0].StatsRefreshWorker(rediskey.TotalUsersExpiration)
go bots[0].StartAPIServer("5000")
// empty string entry = global
slashCommandGuildIds := []string{""}
@ -321,37 +319,3 @@ func parseShards(str string, maxShards int) (shards, error) {
}
return shards, nil
}
//router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// // TODO For any higher-sensitivity info in the future, this should properly identify the origin specifically
// w.Header().Set("Access-Control-Allow-Origin", "*")
// w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
// w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length")
//
// broker.connectionsLock.RLock()
// activeConns := len(broker.connections)
// broker.connectionsLock.RUnlock()
//
// // default to listing active games in the last 15 mins
// activeGames := rediskey.GetActiveGames(context.Background(), broker.client, 900)
// version, commit := rediskey.GetVersionAndCommit(context.Background(), broker.client)
// totalGuilds := rediskey.GetGuildCounter(context.Background(), broker.client)
// totalUsers := rediskey.GetTotalUsers(context.Background(), broker.client)
// totalGames := rediskey.GetTotalGames(context.Background(), broker.client)
//
// data := map[string]interface{}{
// "version": version,
// "commit": commit,
// "totalGuilds": totalGuilds,
// "activeConnections": activeConns,
// "activeGames": activeGames,
// "totalUsers": totalUsers,
// "totalGames": totalGames,
// }
//
// jsonBytes, err := json.Marshal(data)
// if err != nil {
// log.Println(err)
// }
// w.Write(jsonBytes)
//})

View File

@ -1,66 +0,0 @@
package discord
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/automuteus/automuteus/v7/pkg/premium"
"github.com/bwmarrin/discordgo"
"time"
)
type UserModify struct {
UserID uint64 `json:"userID"`
Mute bool `json:"mute"`
Deaf bool `json:"deaf"`
}
type UserModifyRequest struct {
Premium premium.Tier `json:"premium"`
Users []UserModify `json:"users"`
}
type ModifyTask struct {
GuildID uint64 `json:"guildID"`
UserID uint64 `json:"userID"`
Parameters PatchParams `json:"parameters"`
TaskID string `json:"taskID"`
}
const IDLength = 10
func NewModifyTask(guildID, userID uint64, params PatchParams) ModifyTask {
h := sha256.New()
h.Write([]byte(fmt.Sprintf("%d", guildID)))
h.Write([]byte(fmt.Sprintf("%d", userID)))
h.Write([]byte(fmt.Sprintf("%d", time.Now().Unix())))
return ModifyTask{
GuildID: guildID,
UserID: userID,
Parameters: params,
TaskID: hex.EncodeToString(h.Sum(nil))[0:IDLength],
}
}
type PatchParams struct {
Deaf bool `json:"deaf"`
Mute bool `json:"mute"`
}
func ApplyMuteDeaf(sess *discordgo.Session, guildID, userID string, mute, deaf bool) error {
p := PatchParams{
Deaf: deaf,
Mute: mute,
}
_, err := sess.RequestWithBucketID("PATCH", discordgo.EndpointGuildMember(guildID, userID), p, discordgo.EndpointGuildMember(guildID, ""))
return err
}
// a response indicating how the mutes/deafens were issued, and if ratelimits occurred
type MuteDeafenSuccessCounts struct {
Worker int64 `json:"worker"`
Capture int64 `json:"capture"`
Official int64 `json:"official"`
RateLimit int64 `json:"ratelimit"`
}

View File

@ -40,21 +40,3 @@ func RefreshTotalGames(ctx context.Context, client *redis.Client, pool *pgxpool.
}
return v
}
func IsGameInVoiceChannel(ctx context.Context, client *redis.Client, guildID, voiceChannelID string) (bool, error) {
res, err := client.Exists(ctx, VoiceChannelPtr(guildID, voiceChannelID)).Result()
if err != nil {
return false, err
}
return res == 1, nil
}
func IsGameInTextChannel(ctx context.Context, client *redis.Client, guildID, textChannelID string) (bool, error) {
res, err := client.Exists(ctx, TextChannelPtr(guildID, textChannelID)).Result()
if err != nil {
return false, err
}
return res == 1, nil
}

View File

@ -67,10 +67,6 @@ func GuildTokenLock(guildID, hToken string) string {
return "automuteus:muterequest:lock:" + hToken + ":" + guildID
}
func RoomCodesForConnCode(connCode string) string {
return "automuteus:roomcode:" + connCode
}
func CachedUserInfoOnGuild(userID, guildID string) string {
return "automuteus:cache:userinfo:" + guildID + ":" + userID
}