'First' commit; add most of the initialization routine
This commit is contained in:
parent
3bf509c5d4
commit
ea4d7b0a29
7 changed files with 299 additions and 0 deletions
72
Kerobot/InstanceConfig.cs
Normal file
72
Kerobot/InstanceConfig.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Kerobot
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains instance configuration for this bot,
|
||||
/// including Discord connection settings and service configuration.
|
||||
/// </summary>
|
||||
class InstanceConfig
|
||||
{
|
||||
const string JBotToken = "BotToken";
|
||||
readonly string _botToken;
|
||||
/// <summary>
|
||||
/// Token used for Discord authentication.
|
||||
/// </summary>
|
||||
internal string BotToken => _botToken;
|
||||
|
||||
const string JPgSqlConnectionString = "SqlConnectionString";
|
||||
readonly string _pgSqlConnectionString;
|
||||
/// <summary>
|
||||
/// Connection string for accessing the PostgreSQL database.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// That's right, the user can specify the -entire- thing.
|
||||
/// Should problems arise, this will be replaced by a full section within configuration.
|
||||
/// </remarks>
|
||||
internal string PostgresConnString => _pgSqlConnectionString;
|
||||
|
||||
// TODO add fields for services to be configurable: DMRelay, InstanceLog
|
||||
|
||||
/// <summary>
|
||||
/// Sets up instance configuration object from file and command line parameters.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to file from which to load configuration. If null, uses default path.</param>
|
||||
internal InstanceConfig(Options options)
|
||||
{
|
||||
string path = options.ConfigFile;
|
||||
if (path == null) // default: config.json in working directory
|
||||
{
|
||||
path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
|
||||
+ "." + Path.DirectorySeparatorChar + "config.json";
|
||||
}
|
||||
|
||||
JObject conf;
|
||||
try
|
||||
{
|
||||
var conftxt = File.ReadAllText(path);
|
||||
conf = JObject.Parse(conftxt);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string pfx;
|
||||
if (ex is JsonException) pfx = "Unable to parse configuration: ";
|
||||
else pfx = "Unable to access configuration: ";
|
||||
|
||||
throw new Exception(pfx + ex.Message, ex);
|
||||
}
|
||||
|
||||
// Input validation - throw exception on errors. Exception messages printed as-is.
|
||||
_botToken = conf[JBotToken]?.Value<string>();
|
||||
if (string.IsNullOrEmpty(_botToken))
|
||||
throw new Exception($"'{JBotToken}' was not properly specified in configuration.");
|
||||
_pgSqlConnectionString = conf[JPgSqlConnectionString]?.Value<string>();
|
||||
if (string.IsNullOrEmpty(_pgSqlConnectionString))
|
||||
throw new Exception($"'{JPgSqlConnectionString}' was not properly specified in configuration.");
|
||||
}
|
||||
}
|
||||
}
|
63
Kerobot/Kerobot.cs
Normal file
63
Kerobot/Kerobot.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Kerobot.Services;
|
||||
using Npgsql;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kerobot
|
||||
{
|
||||
/// <summary>
|
||||
/// Kerobot main class, and the most accessible and useful class in the whole program.
|
||||
/// Provides an interface for any part of the program to call into all existing services.
|
||||
/// </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 many different and unrelated features.
|
||||
|
||||
private readonly InstanceConfig _icfg;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
/// <summary>
|
||||
/// Gets application instance configuration.
|
||||
/// </summary>
|
||||
internal InstanceConfig Config => _icfg;
|
||||
/// <summary>
|
||||
/// Gets the Discord client instance.
|
||||
/// </summary>
|
||||
public DiscordSocketClient DiscordClient => _client;
|
||||
|
||||
internal Kerobot(InstanceConfig conf, DiscordSocketClient client)
|
||||
{
|
||||
_icfg = conf;
|
||||
_client = client;
|
||||
|
||||
InitializeServices();
|
||||
|
||||
// and prepare modules here
|
||||
}
|
||||
|
||||
private void InitializeServices()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an open NpgsqlConnection instance.
|
||||
/// </summary>
|
||||
/// <param name="guild">
|
||||
/// If manipulating guild-specific information, this parameter sets the database connection's search path.
|
||||
/// </param>
|
||||
internal async Task<NpgsqlConnection> GetOpenNpgsqlConnectionAsync(ulong? guild)
|
||||
{
|
||||
string cs = _icfg.PostgresConnString;
|
||||
if (guild.HasValue) cs += ";searchpath=guild_" + guild.Value;
|
||||
|
||||
var db = new NpgsqlConnection(cs);
|
||||
await db.OpenAsync();
|
||||
return db;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
<Description>Advanced and flexible Discord moderation bot.</Description>
|
||||
<FileVersion>0.0.1</FileVersion>
|
||||
<Version>0.0.1</Version>
|
||||
<LangVersion>7.2</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
38
Kerobot/Options.cs
Normal file
38
Kerobot/Options.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
using System;
|
||||
|
||||
namespace Kerobot
|
||||
{
|
||||
/// <summary>
|
||||
/// Command line options
|
||||
/// </summary>
|
||||
class Options
|
||||
{
|
||||
[Option('c', "config", Default = null,
|
||||
HelpText = "Custom path to instance configuration. Defaults to config.json in bot directory.")]
|
||||
public string ConfigFile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Command line arguments parsed here. Depending on inputs, the program can exit here.
|
||||
/// </summary>
|
||||
public static Options ParseOptions(string[] args)
|
||||
{
|
||||
// Parser will not write out to console by itself
|
||||
var parser = new Parser(config => config.HelpWriter = null);
|
||||
Options opts = null;
|
||||
|
||||
var result = parser.ParseArguments<Options>(args);
|
||||
result.WithParsed(p => opts = p);
|
||||
result.WithNotParsed(p =>
|
||||
{
|
||||
// Taking some extra steps to modify the header to make it resemble our welcome message.
|
||||
var ht = HelpText.AutoBuild(result);
|
||||
ht.Heading = ht.Heading += " - https://github.com/Noikoio/Kerobot";
|
||||
Console.WriteLine(ht.ToString());
|
||||
Environment.Exit(1);
|
||||
});
|
||||
return opts;
|
||||
}
|
||||
}
|
||||
}
|
90
Kerobot/Program.cs
Normal file
90
Kerobot/Program.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kerobot
|
||||
{
|
||||
/// <summary>
|
||||
/// Program startup class. Does initialization before starting the Discord client.
|
||||
/// </summary>
|
||||
class Program
|
||||
{
|
||||
static DateTimeOffset _startTime;
|
||||
/// <summary>
|
||||
/// Timestamp specifying the date and time that the program began running.
|
||||
/// </summary>
|
||||
public static DateTimeOffset StartTime => _startTime;
|
||||
|
||||
static Kerobot _main;
|
||||
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
_startTime = DateTimeOffset.UtcNow;
|
||||
Console.WriteLine("Bot start time: " + _startTime.ToString("u"));
|
||||
|
||||
// Get instance config figured out
|
||||
var opts = Options.ParseOptions(args); // Program can exit here.
|
||||
InstanceConfig cfg;
|
||||
try
|
||||
{
|
||||
cfg = new InstanceConfig(opts);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Quick test if database configuration works
|
||||
try
|
||||
{
|
||||
using (var d = new Npgsql.NpgsqlConnection(cfg.PostgresConnString))
|
||||
{
|
||||
await d.OpenAsync();
|
||||
d.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Could not establish a database connection! Check your settings and try again.");
|
||||
Console.WriteLine($"Error: {ex.GetType().FullName}: {ex.Message}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
// Configure Discord client
|
||||
var client = new DiscordSocketClient(new DiscordSocketConfig()
|
||||
{
|
||||
DefaultRetryMode = RetryMode.AlwaysRetry,
|
||||
MessageCacheSize = 0 // using our own
|
||||
});
|
||||
|
||||
// Kerobot class initialization - will set up services and modules
|
||||
_main = new Kerobot(cfg, client);
|
||||
|
||||
// Set up application close handler
|
||||
Console.CancelKeyPress += Console_CancelKeyPress;
|
||||
|
||||
// TODO Set up unhandled exception handler
|
||||
// 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.StartAsync();
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
|
||||
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
|
||||
{
|
||||
// TODO finish implementation when logging is set up
|
||||
e.Cancel = true;
|
||||
// _main.Log("Received Cancel event. Application will shut down...");
|
||||
// stop periodic task processing - wait for current run to finish if executing (handled by service?)
|
||||
// notify services of shutdown
|
||||
bool success = _main.DiscordClient.LogoutAsync().Wait(10000);
|
||||
// if (!success) _main.Log("Failed to disconnect cleanly from Discord. Will force shut down.");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
10
Kerobot/Services/GuildStateManager/Manager.cs
Normal file
10
Kerobot/Services/GuildStateManager/Manager.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Kerobot.Services.GuildStateManager
|
||||
{
|
||||
class Manager
|
||||
{
|
||||
}
|
||||
}
|
25
Kerobot/Services/Service.cs
Normal file
25
Kerobot/Services/Service.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Kerobot.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for Kerobot service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Services provide the core functionality of this program. Modules are expected to call into methods
|
||||
/// provided by services for the times when processor-intensive or shared functionality needs to be utilized.
|
||||
/// </remarks>
|
||||
internal class Service
|
||||
{
|
||||
private readonly Kerobot _kb;
|
||||
|
||||
public Kerobot Kerobot => _kb;
|
||||
|
||||
protected internal Service(Kerobot kb)
|
||||
{
|
||||
_kb = kb;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue