Minor improvements throughout
This commit is contained in:
parent
4ca38fa881
commit
9bd9a21531
6 changed files with 65 additions and 58 deletions
|
@ -12,47 +12,36 @@ namespace Kerobot
|
|||
/// </summary>
|
||||
public partial class Kerobot
|
||||
{
|
||||
// Partial class: Services are able to add their own methods and properties to this class.
|
||||
// This is to prevent this file from having too many references to different and unrelated features.
|
||||
|
||||
private readonly InstanceConfig _icfg;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private IReadOnlyCollection<Service> _services;
|
||||
private IReadOnlyCollection<ModuleBase> _modules;
|
||||
|
||||
/// <summary>
|
||||
/// Gets application instance configuration.
|
||||
/// </summary>
|
||||
internal InstanceConfig Config => _icfg;
|
||||
internal InstanceConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Discord client instance.
|
||||
/// </summary>
|
||||
public DiscordSocketClient DiscordClient => _client;
|
||||
public DiscordSocketClient DiscordClient { get; }
|
||||
|
||||
/// <summary>
|
||||
/// All loaded services in an iterable form.
|
||||
/// Gets all loaded services in an iterable form.
|
||||
/// </summary>
|
||||
internal IReadOnlyCollection<Service> Services => _services;
|
||||
internal IReadOnlyCollection<Service> Services { get; }
|
||||
|
||||
/// <summary>
|
||||
/// All loaded modules in an iterable form.
|
||||
/// Gets all loaded modules in an iterable form.
|
||||
/// </summary>
|
||||
internal IReadOnlyCollection<ModuleBase> Modules => _modules;
|
||||
internal IReadOnlyCollection<ModuleBase> Modules { get; }
|
||||
|
||||
internal Kerobot(InstanceConfig conf, DiscordSocketClient client)
|
||||
{
|
||||
_icfg = conf;
|
||||
_client = client;
|
||||
|
||||
// 'Ready' event handler. Because there's no other place for it.
|
||||
_client.Ready += async delegate
|
||||
{
|
||||
await InstanceLogAsync(true, "Kerobot", "Connected and ready.");
|
||||
};
|
||||
Config = conf;
|
||||
DiscordClient = client;
|
||||
|
||||
// Get all services started up
|
||||
_services = InitializeServices();
|
||||
Services = InitializeServices();
|
||||
|
||||
// Load externally defined functionality
|
||||
_modules = ModuleLoader.Load(_icfg, this);
|
||||
Modules = ModuleLoader.Load(Config, this);
|
||||
|
||||
// Everything's ready to go. Print the welcome message here.
|
||||
var ver = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
||||
|
@ -81,7 +70,7 @@ namespace Kerobot
|
|||
/// </param>
|
||||
internal async Task<NpgsqlConnection> GetOpenNpgsqlConnectionAsync(ulong? guild)
|
||||
{
|
||||
string cs = _icfg.PostgresConnString;
|
||||
string cs = Config.PostgresConnString;
|
||||
if (guild.HasValue) cs += ";searchpath=guild_" + guild.Value;
|
||||
|
||||
var db = new NpgsqlConnection(cs);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Discord.WebSocket;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -9,23 +10,26 @@ namespace Kerobot
|
|||
/// user input (both by means of configuration and incoming Discord events) and process it accordingly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementing classes should not rely on local/instance variables to store data. Make use of
|
||||
/// <see cref="CreateGuildStateAsync(JToken)"/> and <see cref="GetGuildState{T}(ulong)"/>.
|
||||
/// Implementing classes should not rely on local variables to store runtime data regarding guilds.
|
||||
/// Use <see cref="CreateGuildStateAsync(JToken)"/> and <see cref="GetGuildState{T}(ulong)"/>.
|
||||
/// </remarks>
|
||||
public abstract class ModuleBase
|
||||
{
|
||||
private readonly Kerobot _kb;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the Kerobot instance.
|
||||
/// </summary>
|
||||
public Kerobot Kerobot => _kb;
|
||||
public Kerobot Kerobot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the Discord client instance.
|
||||
/// </summary>
|
||||
public DiscordSocketClient DiscordClient { get => Kerobot.DiscordClient; }
|
||||
|
||||
/// <summary>
|
||||
/// When a module is loaded, this constructor is called.
|
||||
/// Services are available at this point. Do not attempt to communicate to Discord within the constructor.
|
||||
/// </summary>
|
||||
public ModuleBase(Kerobot kb) => _kb = kb;
|
||||
public ModuleBase(Kerobot kb) => Kerobot = kb;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the module name.
|
||||
|
@ -53,6 +57,20 @@ namespace Kerobot
|
|||
/// Thrown if the stored state object cannot be cast as specified.
|
||||
/// </exception>
|
||||
protected T GetGuildState<T>(ulong guildId) => Kerobot.GetGuildState<T>(guildId, GetType());
|
||||
|
||||
/// <summary>
|
||||
/// Appends a message to the global instance log. Use sparingly.
|
||||
/// </summary>
|
||||
/// <param name="report">
|
||||
/// Specifies if the log message should be sent to the reporting channel.
|
||||
/// Only messages of very high importance should use this option.
|
||||
/// </param>
|
||||
protected Task LogAsync(string message, bool report = false) => Kerobot.InstanceLogAsync(report, Name, message);
|
||||
|
||||
/// <summary>
|
||||
/// Appends a message to the log for the specified guild.
|
||||
/// </summary>
|
||||
protected Task LogAsync(ulong guild, string message) => Kerobot.GuildLogAsync(guild, Name, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -10,11 +10,10 @@ namespace Kerobot
|
|||
/// </summary>
|
||||
class Program
|
||||
{
|
||||
static DateTimeOffset _startTime;
|
||||
/// <summary>
|
||||
/// Timestamp specifying the date and time that the program began running.
|
||||
/// </summary>
|
||||
public static DateTimeOffset StartTime => _startTime;
|
||||
public static DateTimeOffset StartTime { get; private set; }
|
||||
|
||||
static Kerobot _main;
|
||||
|
||||
|
@ -23,8 +22,8 @@ namespace Kerobot
|
|||
/// </summary>
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
_startTime = DateTimeOffset.UtcNow;
|
||||
Console.WriteLine("Bot start time: " + _startTime.ToString("u"));
|
||||
StartTime = DateTimeOffset.UtcNow;
|
||||
Console.WriteLine("Bot start time: " + StartTime.ToString("u"));
|
||||
|
||||
// Get instance configuration from file and parameters
|
||||
var opts = Options.ParseOptions(args); // Program can exit here.
|
||||
|
@ -73,7 +72,7 @@ namespace Kerobot
|
|||
// send error notification to instance log channel, if possible
|
||||
|
||||
// And off we go.
|
||||
await _main.DiscordClient.LoginAsync(Discord.TokenType.Bot, cfg.BotToken);
|
||||
await _main.DiscordClient.LoginAsync(TokenType.Bot, cfg.BotToken);
|
||||
await _main.DiscordClient.StartAsync();
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,10 @@ namespace Kerobot.Services.GuildState
|
|||
{
|
||||
static readonly TimeSpan TimeUntilStale = new TimeSpan(0, 15, 0);
|
||||
|
||||
private readonly object _data;
|
||||
/// <summary>
|
||||
/// Module-provided data.
|
||||
/// </summary>
|
||||
public object Data => _data;
|
||||
public object Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Hash of the JToken used to generate the data. In certain casaes, it is used to check
|
||||
|
@ -22,28 +21,29 @@ namespace Kerobot.Services.GuildState
|
|||
/// </summary>
|
||||
private readonly int _configHash;
|
||||
|
||||
private readonly DateTimeOffset _creationTs;
|
||||
private DateTimeOffset _lastStaleCheck;
|
||||
|
||||
public StateInfo(object data, int configHash)
|
||||
{
|
||||
_data = data;
|
||||
Data = data;
|
||||
_configHash = configHash;
|
||||
_creationTs = DateTimeOffset.UtcNow;
|
||||
_lastStaleCheck = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_data is IDisposable dd) { dd.Dispose(); }
|
||||
if (Data is IDisposable dd) { dd.Dispose(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the current data may be stale, based on the data's age or
|
||||
/// through comparison with incoming configuration.
|
||||
/// Checks if the current data may be stale, based on the last staleness check or
|
||||
/// if the underlying configuration has changed.
|
||||
/// </summary>
|
||||
public bool IsStale(JToken comparison)
|
||||
{
|
||||
if (DateTimeOffset.UtcNow - _creationTs > TimeUntilStale) return true;
|
||||
if (DateTimeOffset.UtcNow - _lastStaleCheck > TimeUntilStale) return true;
|
||||
if (comparison.GetHashCode() != _configHash) return true;
|
||||
_lastStaleCheck = DateTimeOffset.UtcNow;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ namespace Kerobot.Services.Logging
|
|||
|
||||
// Discord.Net log handling (client logging option is specified in Program.cs)
|
||||
kb.DiscordClient.Log += DiscordClient_Log;
|
||||
|
||||
// Ready message too
|
||||
kb.DiscordClient.Ready +=
|
||||
async delegate { await DoInstanceLogAsync(true, "Kerobot", "Connected and ready."); };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Kerobot.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for Kerobot service.
|
||||
/// Base class for Kerobot services.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Services provide the core functionality of this program. Modules are expected to call into methods
|
||||
|
@ -11,18 +11,15 @@ namespace Kerobot.Services
|
|||
/// </remarks>
|
||||
internal abstract class Service
|
||||
{
|
||||
private readonly Kerobot _kb;
|
||||
public Kerobot Kerobot => _kb;
|
||||
public Kerobot Kerobot { get; }
|
||||
|
||||
public string Name => this.GetType().Name;
|
||||
|
||||
public Service(Kerobot kb)
|
||||
{
|
||||
_kb = kb;
|
||||
}
|
||||
public Service(Kerobot kb) => Kerobot = kb;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes database tables per-guild. Called when entering a guild.
|
||||
/// Initializes database tables per-guild.
|
||||
/// This method is called by GuildStateService when entering a guild.
|
||||
/// </summary>
|
||||
/// <param name="db">An opened database connection with the appropriate schema option set.</param>
|
||||
/// <remarks>If overriding, calling the base method is not necessary.</remarks>
|
||||
|
|
Loading…
Reference in a new issue