Removed channel expiry data persistence
Some leftover references here and there. Will remove soon.
This commit is contained in:
parent
0a2acf6ed6
commit
d97bdfafce
1 changed files with 8 additions and 152 deletions
|
@ -1,7 +1,5 @@
|
||||||
using Discord.Rest;
|
using Discord.Rest;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using Npgsql;
|
|
||||||
using NpgsqlTypes;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -18,7 +16,7 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
readonly DiscordSocketClient _client;
|
readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Key = guild, Value = expiry time, notify flag.
|
/// Key = guild, Value = expiry time
|
||||||
/// Must lock!
|
/// Must lock!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
readonly Dictionary<ulong, (DateTimeOffset, bool)> _trackedChannels;
|
readonly Dictionary<ulong, (DateTimeOffset, bool)> _trackedChannels;
|
||||||
|
@ -34,7 +32,6 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
_bgTask = Task.Factory.StartNew(ChannelExpirationChecker, _token.Token,
|
_bgTask = Task.Factory.StartNew(ChannelExpirationChecker, _token.Token,
|
||||||
TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||||
_trackedChannels = new Dictionary<ulong, (DateTimeOffset, bool)>();
|
_trackedChannels = new Dictionary<ulong, (DateTimeOffset, bool)>();
|
||||||
SetUpPersistenceTableAsync().Wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -42,92 +39,12 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
_token.Cancel();
|
_token.Cancel();
|
||||||
_token.Dispose();
|
_token.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Data persistence
|
|
||||||
private const string PersistTable = "votetemp_persist";
|
|
||||||
private async Task SetUpPersistenceTableAsync()
|
|
||||||
{
|
|
||||||
using (var db = await RegexBot.Config.GetOpenDatabaseConnectionAsync())
|
|
||||||
{
|
|
||||||
using (var c = db.CreateCommand())
|
|
||||||
{
|
|
||||||
c.CommandText = $"create table if not exists {PersistTable} (" +
|
|
||||||
"guild_id bigint primary key, " +
|
|
||||||
"expiration_time timestamptz not null" +
|
|
||||||
")";
|
|
||||||
await c.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<DateTimeOffset?> GetPersistData(ulong guildId)
|
|
||||||
{
|
|
||||||
using (var db = await RegexBot.Config.GetOpenDatabaseConnectionAsync())
|
|
||||||
{
|
|
||||||
using (var c = db.CreateCommand())
|
|
||||||
{
|
|
||||||
c.CommandText = $"select expiration_time from {PersistTable} where guild_id = @Gid";
|
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = guildId;
|
|
||||||
c.Prepare();
|
|
||||||
using (var r = await c.ExecuteReaderAsync())
|
|
||||||
{
|
|
||||||
if (await r.ReadAsync()) return r.GetDateTime(0);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InsertOrUpdatePersistData(ulong guildId, DateTimeOffset expiration)
|
|
||||||
{
|
|
||||||
using (var db = await RegexBot.Config.GetOpenDatabaseConnectionAsync())
|
|
||||||
{
|
|
||||||
using (var c = db.CreateCommand())
|
|
||||||
{
|
|
||||||
c.CommandText = $"delete from {PersistTable} where guild_id = @Gid";
|
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = guildId;
|
|
||||||
await c.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var c = db.CreateCommand())
|
|
||||||
{
|
|
||||||
c.CommandText = $"insert into {PersistTable} values (@Gid, @Exp)";
|
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = guildId;
|
|
||||||
c.Parameters.Add("@Exp", NpgsqlDbType.TimestampTZ).Value = expiration;
|
|
||||||
c.Prepare();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await c.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
catch (NpgsqlException ex)
|
|
||||||
{
|
|
||||||
// TODO should log this instead of throwing an exception...
|
|
||||||
throw new ApplicationException("A database error occurred. Internal error message: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DeletePersistData(ulong guildId)
|
|
||||||
{
|
|
||||||
using (var db = await RegexBot.Config.GetOpenDatabaseConnectionAsync())
|
|
||||||
{
|
|
||||||
using (var c = db.CreateCommand())
|
|
||||||
{
|
|
||||||
c.CommandText = $"delete from {PersistTable} where guild_id = @Gid";
|
|
||||||
c.Parameters.Add("@Gid", NpgsqlDbType.Bigint).Value = guildId;
|
|
||||||
c.Prepare();
|
|
||||||
await c.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Querying
|
#region Querying
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the given guild has a temporary channel that is up for a renewal vote.
|
/// Determines if the given guild has a temporary channel that is up for a renewal vote.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsUpForRenewal(SocketGuild guild, GuildConfiguration info)
|
public bool IsUpForRenewal(SocketGuild guild, Configuration info)
|
||||||
{
|
{
|
||||||
DateTimeOffset tcExp;
|
DateTimeOffset tcExp;
|
||||||
lock (_trackedChannels)
|
lock (_trackedChannels)
|
||||||
|
@ -139,14 +56,7 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
var renewThreshold = tcExp - info.KeepaliveVoteDuration;
|
var renewThreshold = tcExp - info.KeepaliveVoteDuration;
|
||||||
return DateTimeOffset.UtcNow > renewThreshold;
|
return DateTimeOffset.UtcNow > renewThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SocketTextChannel FindTemporaryChannel(SocketGuild guild, GuildConfiguration conf)
|
|
||||||
=> System.Linq.Enumerable.SingleOrDefault(guild.TextChannels, c => c.Name == conf.TempChannelName);
|
|
||||||
|
|
||||||
public bool HasExistingTemporaryChannel(SocketGuild guild, GuildConfiguration info)
|
|
||||||
{
|
|
||||||
return FindTemporaryChannel(guild, info) != null;
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Channel entry manipulation
|
#region Channel entry manipulation
|
||||||
|
@ -156,7 +66,7 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
/// <exception cref="ApplicationException">
|
/// <exception cref="ApplicationException">
|
||||||
/// Various causes. Send exception message to log and channel if thrown.
|
/// Various causes. Send exception message to log and channel if thrown.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public async Task<RestTextChannel> CreateChannelAndEntryAsync(SocketGuild guild, GuildConfiguration info)
|
public async Task<RestTextChannel> CreateChannelAndEntryAsync(SocketGuild guild, Configuration info)
|
||||||
{
|
{
|
||||||
lock (_trackedChannels)
|
lock (_trackedChannels)
|
||||||
{
|
{
|
||||||
|
@ -164,8 +74,6 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
if (_trackedChannels.ContainsKey(guild.Id)) return null;
|
if (_trackedChannels.ContainsKey(guild.Id)) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var channelExpiryTime = DateTimeOffset.UtcNow + info.ChannelBaseDuration;
|
|
||||||
|
|
||||||
RestTextChannel newCh = null;
|
RestTextChannel newCh = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -179,19 +87,13 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
// Channel creation succeeded. Regardless of persistent state, at least add it to in-memory cache.
|
// Channel creation succeeded. Regardless of persistent state, at least add it to in-memory cache.
|
||||||
lock (_trackedChannels) _trackedChannels.Add(guild.Id, (channelExpiryTime, false));
|
lock (_trackedChannels) _trackedChannels.Add(guild.Id, (channelExpiryTime, false));
|
||||||
|
|
||||||
// Create persistent entry.
|
|
||||||
await InsertOrUpdatePersistData(guild.Id, channelExpiryTime);
|
|
||||||
|
|
||||||
return newCh;
|
return newCh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For an existing temporary channel, extends its lifetime by a predetermined amount.
|
/// For an existing temporary channel, extends its lifetime by a predetermined amount.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="ApplicationException">
|
public async Task ExtendChannelExpirationAsync(SocketGuild guild, Configuration info)
|
||||||
/// SQL. Send exception message to log and channel if thrown.
|
|
||||||
/// </exception>
|
|
||||||
public async Task ExtendChannelExpirationAsync(SocketGuild guild, GuildConfiguration info)
|
|
||||||
{
|
{
|
||||||
DateTimeOffset newExpiration;
|
DateTimeOffset newExpiration;
|
||||||
lock (_trackedChannels)
|
lock (_trackedChannels)
|
||||||
|
@ -202,52 +104,8 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
newExpiration+= info.ChannelExtendDuration;
|
newExpiration+= info.ChannelExtendDuration;
|
||||||
_trackedChannels[guild.Id] = (newExpiration, false);
|
_trackedChannels[guild.Id] = (newExpiration, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await InsertOrUpdatePersistData(guild.Id, newExpiration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when becoming aware of a new guild. Checks and acts on persistence data.
|
|
||||||
/// </summary>
|
|
||||||
public async Task RecheckExpiryInformation(SocketGuild guild, GuildConfiguration info)
|
|
||||||
{
|
|
||||||
var ch = FindTemporaryChannel(guild, info);
|
|
||||||
var persist = await GetPersistData(guild.Id);
|
|
||||||
|
|
||||||
if (persist.HasValue)
|
|
||||||
{
|
|
||||||
// Found persistence data and...
|
|
||||||
if (ch == null)
|
|
||||||
{
|
|
||||||
// ...there is no existing corresponding channel. Delete persistence data.
|
|
||||||
await DeletePersistData(guild.Id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// ...the channel exists. Add to in-memory cache.
|
|
||||||
// Cached persistence should extend to at least 5 minutes if needed.
|
|
||||||
// Should allow for enough time for users to vote for an extension.
|
|
||||||
DateTimeOffset toCache;
|
|
||||||
if ((DateTimeOffset.UtcNow - persist.Value).Duration().TotalMinutes > 5)
|
|
||||||
toCache = persist.Value;
|
|
||||||
else
|
|
||||||
toCache = DateTimeOffset.UtcNow.AddMinutes(5);
|
|
||||||
lock (_trackedChannels) { _trackedChannels.Add(guild.Id, (toCache, false)); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No persistence data.
|
|
||||||
if (ch != null)
|
|
||||||
{
|
|
||||||
// But we have a channel. Add new value to cache.
|
|
||||||
var exp = DateTimeOffset.UtcNow + info.ChannelBaseDuration;
|
|
||||||
lock (_trackedChannels) { _trackedChannels.Add(guild.Id, (exp, false)); }
|
|
||||||
await InsertOrUpdatePersistData(guild.Id, exp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the given guild's temporary channel as up for immediate expiration.
|
/// Sets the given guild's temporary channel as up for immediate expiration.
|
||||||
/// Use this to properly remove a temporary channel.
|
/// Use this to properly remove a temporary channel.
|
||||||
|
@ -259,11 +117,10 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
if (!_trackedChannels.ContainsKey(guild.Id)) return; // how did we even get here?
|
if (!_trackedChannels.ContainsKey(guild.Id)) return; // how did we even get here?
|
||||||
_trackedChannels[guild.Id] = (DateTimeOffset.UtcNow, true);
|
_trackedChannels[guild.Id] = (DateTimeOffset.UtcNow, true);
|
||||||
}
|
}
|
||||||
await DeletePersistData(guild.Id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes the given guild from the cache. Does not alter persistence data.
|
/// Removes the given guild from the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void DropCacheEntry(SocketGuild guild)
|
public void DropCacheEntry(SocketGuild guild)
|
||||||
{
|
{
|
||||||
|
@ -329,7 +186,6 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
cachePostRemove.Add(item.Key);
|
cachePostRemove.Add(item.Key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DeletePersistData(item.Key).Wait();
|
|
||||||
cachePostRemove.Add(item.Key);
|
cachePostRemove.Add(item.Key);
|
||||||
}
|
}
|
||||||
else if (item.Value.Item2 == false && IsUpForRenewal(ch.Guild, conf))
|
else if (item.Value.Item2 == false && IsUpForRenewal(ch.Guild, conf))
|
||||||
|
|
Loading…
Reference in a new issue