Skip to content

Latest commit

 

History

History
50 lines (27 loc) · 3.81 KB

readme.md

File metadata and controls

50 lines (27 loc) · 3.81 KB

RPCS3 Compatibility Bot

Configuration

Currently all configurable tunables are stored in the Config static class that is initialized once on startup. This is mostly done like this because it's very easy to implement and is enough for current needs.

Some settings are grouped in additional static classes for easier use (e.g. Reactions and Colors).

Everything is initialized with default values that correspond to the main bot instance (except for sensitive tokens), and require overriding through configuration for any test instance.

Currently, configuration is possible through the $ dotnet user-secrets command. Configuration through the environment variables was disabled as it had some unintended consequences between bot restarts (preserved values; require complete manual shutdown and restart to update configuration).

Be careful with input validation during configuration, as unhandled exceptions in static constructor will lead to TypeInitializationException and program termination that might be tricky to debug.

In addition to the configuration variables, Config contains the Log instance and the global CancellationTokenSource.

We're using NLog for logging, configured to mimic the default Log4Net layout (mostly because I already have the syntax highlighter for Sublime Text 3 for it). It is also configured to ignore TaskCancelledExceptions that occur when CancellationTokens are being cancelled to reduce spam in logs.

Do log exceptions as an argument to log methods, instead of calling .ToString() on them

Global CancellationTokenSource (Config.Cts) is used to signal the program shutdown.

Do check it and abort whenever possible to reduce the restart time and prevent infinite code execution.

Program entry point

On startup we check for other instances. We wait a bit for their shutdown, or shutdown ourselves otherwise. This is done through spinning a separate thread and using global mutex. Unlike semaphores, mutex must be released in the same thread it was acquired, which is impossible to do in asynchronous code, thus the dedicated thread.

Note that Config initialization will happen on first call to the class.

Next we open the databases and run migrations to upgrade their structure if needed. Currently we have two of them:

  • BotDb is used to store all the settings and custom data for the bot.
  • ThumbsDb is used to store PSN metadata and game thumbnail links.

When databases are ready, we immediately restore bot runtime statistics.

Next we start all the background tasks that will run periodically while the bot is up and running. This includes thumbnail scraping, AppVeyor build history scraper, AMD Driver version updater, etc.

Next we configure the discord client. This includes registering all the commands and event handlers. We use the built-in help formatter and hook up the built-in discord client logging to our own logger.

Of particular note is the GuildAvailable event, where we check and make sure the bot is running in the configured guild. There was one time when bot wasn't configured properly and someone quietly added it to their own private server, which caused crash on startup. That was fun.

We also fun backlog checks where it makes sense for moderation, in case something slipped past while the bot was unavailable.

On restart we try to gracefully wait for a bit to let any outstanding task to complete, but not too long. This is why it is important to check Config.Cts cancellation status whenever possible.