Replaced background task; Cache now in guild state
Channel renewal is no longer a concept. Channels will automatically expire after they have been inactive for a set amount of time, regardless of the channel's age. This greatly simplifies things.
This commit is contained in:
parent
34ba1d9443
commit
b9cc41030c
4 changed files with 175 additions and 165 deletions
|
@ -1,7 +1,6 @@
|
||||||
using Discord.Rest;
|
using Discord.Rest;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -10,17 +9,11 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keeps track of existing channels and expiry information. Manages data persistence.
|
/// Keeps track of existing channels and expiry information. Manages data persistence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class ChannelManager : IDisposable
|
class ChannelManager
|
||||||
{
|
{
|
||||||
readonly VoteTempChannel _out;
|
readonly VoteTempChannel _out;
|
||||||
readonly DiscordSocketClient _client;
|
readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Key = guild, Value = expiry time
|
|
||||||
/// Must lock!
|
|
||||||
/// </summary>
|
|
||||||
readonly Dictionary<ulong, (DateTimeOffset, bool)> _trackedChannels;
|
|
||||||
|
|
||||||
readonly CancellationTokenSource _token;
|
readonly CancellationTokenSource _token;
|
||||||
readonly Task _bgTask;
|
readonly Task _bgTask;
|
||||||
|
|
||||||
|
@ -28,37 +21,8 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
{
|
{
|
||||||
_out = module;
|
_out = module;
|
||||||
_client = client;
|
_client = client;
|
||||||
_token = new CancellationTokenSource();
|
|
||||||
_bgTask = Task.Factory.StartNew(ChannelExpirationChecker, _token.Token,
|
|
||||||
TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
|
||||||
_trackedChannels = new Dictionary<ulong, (DateTimeOffset, bool)>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_token.Cancel();
|
|
||||||
_token.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Querying
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the given guild has a temporary channel that is up for a renewal vote.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsUpForRenewal(SocketGuild guild, Configuration info)
|
|
||||||
{
|
|
||||||
DateTimeOffset tcExp;
|
|
||||||
lock (_trackedChannels)
|
|
||||||
{
|
|
||||||
if (!_trackedChannels.TryGetValue(guild.Id, out var val)) return false;
|
|
||||||
tcExp = val.Item1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var renewThreshold = tcExp - info.KeepaliveVoteDuration;
|
|
||||||
return DateTimeOffset.UtcNow > renewThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Channel entry manipulation
|
#region Channel entry manipulation
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the temporary channel.
|
/// Creates the temporary channel.
|
||||||
|
@ -84,27 +48,8 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
throw new ApplicationException("Failed to create the channel. Internal error message: " + ex.Message);
|
throw new ApplicationException("Failed to create the channel. Internal error message: " + ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel creation succeeded. Regardless of persistent state, at least add it to in-memory cache.
|
|
||||||
lock (_trackedChannels) _trackedChannels.Add(guild.Id, (channelExpiryTime, false));
|
|
||||||
|
|
||||||
return newCh;
|
return newCh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For an existing temporary channel, extends its lifetime by a predetermined amount.
|
|
||||||
/// </summary>
|
|
||||||
public async Task ExtendChannelExpirationAsync(SocketGuild guild, Configuration info)
|
|
||||||
{
|
|
||||||
DateTimeOffset newExpiration;
|
|
||||||
lock (_trackedChannels)
|
|
||||||
{
|
|
||||||
if (!_trackedChannels.ContainsKey(guild.Id)) return; // how did we even get here?
|
|
||||||
|
|
||||||
newExpiration = _trackedChannels[guild.Id].Item1;
|
|
||||||
newExpiration+= info.ChannelExtendDuration;
|
|
||||||
_trackedChannels[guild.Id] = (newExpiration, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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.
|
||||||
|
@ -118,99 +63,7 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
_trackedChannels[guild.Id] = (DateTimeOffset.UtcNow, true);
|
_trackedChannels[guild.Id] = (DateTimeOffset.UtcNow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the given guild from the cache.
|
|
||||||
/// </summary>
|
|
||||||
public void DropCacheEntry(SocketGuild guild)
|
|
||||||
{
|
|
||||||
lock (_trackedChannels) _trackedChannels.Remove(guild.Id);
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Background task. Handles channel deletion on expiry.
|
|
||||||
/// </summary>
|
|
||||||
private async Task ChannelExpirationChecker()
|
|
||||||
{
|
|
||||||
while (!_token.Token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
lock (_trackedChannels)
|
|
||||||
{
|
|
||||||
var now = DateTimeOffset.UtcNow;
|
|
||||||
var cachePostRemove = new List<ulong>(); // list of items to remove; can't remove while iterating
|
|
||||||
var cacheWarnSet = new List<ulong>(); // list of items to update the announce flag; can't change while iterating
|
|
||||||
foreach (var item in _trackedChannels)
|
|
||||||
{
|
|
||||||
var g = _client.GetGuild(item.Key);
|
|
||||||
if (g == null)
|
|
||||||
{
|
|
||||||
// Cached guild is not known, somehow...
|
|
||||||
cachePostRemove.Add(item.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var conf = _out.GetConfig(item.Key);
|
|
||||||
if (conf == null)
|
|
||||||
{
|
|
||||||
// Cached guild has no config, somehow...
|
|
||||||
cachePostRemove.Add(item.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var ch = FindTemporaryChannel(g, conf);
|
|
||||||
if (ch == null)
|
|
||||||
{
|
|
||||||
// Temporary channel no longer exists.
|
|
||||||
// Assume it's been deleted early, but do not start a cooldown.
|
|
||||||
cachePostRemove.Add(item.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now > item.Value.Item1)
|
|
||||||
{
|
|
||||||
// Process channel removal
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ch.DeleteAsync().Wait();
|
|
||||||
_out._votes.SetCooldown(ch.Guild.Id);
|
|
||||||
}
|
|
||||||
catch (Discord.Net.HttpException)
|
|
||||||
{
|
|
||||||
// On deletion error, attempt to report the issue. Discard from cache.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ch.SendMessageAsync("Warning: Unable to remove temporary channel. It must now be done manually.");
|
|
||||||
}
|
|
||||||
catch (Discord.Net.HttpException) { }
|
|
||||||
cachePostRemove.Add(item.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cachePostRemove.Add(item.Key);
|
|
||||||
}
|
|
||||||
else if (item.Value.Item2 == false && IsUpForRenewal(ch.Guild, conf))
|
|
||||||
{
|
|
||||||
// Process channel renewal warning
|
|
||||||
ch.SendMessageAsync("This channel is nearing expiration! Vote to extend it by issuing " +
|
|
||||||
$"the `{conf.VoteCommand}` command.").Wait();
|
|
||||||
cacheWarnSet.Add(item.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var guildId in cachePostRemove)
|
|
||||||
{
|
|
||||||
_trackedChannels.Remove(guildId);
|
|
||||||
}
|
|
||||||
foreach (var id in cacheWarnSet)
|
|
||||||
{
|
|
||||||
var newdata = (_trackedChannels[id].Item1, true);
|
|
||||||
_trackedChannels.Remove(id);
|
|
||||||
_trackedChannels.Add(id, newdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try { await Task.Delay(12 * 1000, _token.Token); }
|
|
||||||
catch (TaskCanceledException) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,42 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
{
|
{
|
||||||
class Configuration
|
class Configuration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Command used to vote for the channel's creation.
|
||||||
|
/// </summary>
|
||||||
public string VoteCommand { get; }
|
public string VoteCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the temporary channel, without prefix.
|
||||||
|
/// </summary>
|
||||||
public string TempChannelName { get; }
|
public string TempChannelName { get; }
|
||||||
public TimeSpan ChannelBaseDuration { get; }
|
|
||||||
public TimeSpan ChannelExtendDuration { get; }
|
/// <summary>
|
||||||
|
/// Amount of time that the temporary channel can exist without activity before expiring and being deleted.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan ChannelDuration { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of votes needed to create the channel.
|
||||||
|
/// </summary>
|
||||||
public int VotePassThreshold { get; }
|
public int VotePassThreshold { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of time that a voting session can last starting from its initial vote.
|
||||||
|
/// </summary>
|
||||||
public TimeSpan VotingDuration { get; }
|
public TimeSpan VotingDuration { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of time to wait before another vote may be initiated, either after a failed vote
|
||||||
|
/// or from expiration of the temporary channel.
|
||||||
|
/// </summary>
|
||||||
public TimeSpan VotingCooldown { get; }
|
public TimeSpan VotingCooldown { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Channel name in which voting takes place.
|
||||||
|
/// </summary>
|
||||||
|
public string VotingChannel { get; }
|
||||||
|
|
||||||
public Configuration(JObject j)
|
public Configuration(JObject j)
|
||||||
{
|
{
|
||||||
VoteCommand = j["VoteCommand"]?.Value<string>();
|
VoteCommand = j["VoteCommand"]?.Value<string>();
|
||||||
|
@ -23,11 +51,8 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
if (VoteCommand.Contains(" "))
|
if (VoteCommand.Contains(" "))
|
||||||
throw new RuleImportException("'VoteCommand' must not contain spaces.");
|
throw new RuleImportException("'VoteCommand' must not contain spaces.");
|
||||||
|
|
||||||
TempChannelName = j["TempChannelName"]?.Value<string>();
|
TempChannelName = ParseChannelNameConfig(j, "TempChannelName");
|
||||||
if (string.IsNullOrWhiteSpace(TempChannelName))
|
VotingChannel = ParseChannelNameConfig(j, "VotingChannel");
|
||||||
throw new RuleImportException("'TempChannelName' must be specified.");
|
|
||||||
if (!Regex.IsMatch(TempChannelName, @"^([A-Za-z0-9]|[-_ ])+$"))
|
|
||||||
throw new RuleImportException("'TempChannelName' contains one or more invalid characters.");
|
|
||||||
|
|
||||||
var vptProp = j["VotePassThreshold"];
|
var vptProp = j["VotePassThreshold"];
|
||||||
if (vptProp == null)
|
if (vptProp == null)
|
||||||
|
@ -38,12 +63,21 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
if (VotePassThreshold <= 0)
|
if (VotePassThreshold <= 0)
|
||||||
throw new NotImplementedException("'VotePassThreshold' must be greater than zero.");
|
throw new NotImplementedException("'VotePassThreshold' must be greater than zero.");
|
||||||
|
|
||||||
ChannelBaseDuration = ParseTimeConfig(j, "ChannelBaseDuration");
|
ChannelDuration = ParseTimeConfig(j, "ChannelDuration");
|
||||||
ChannelExtendDuration = ParseTimeConfig(j, "ChannelExtendDuration");
|
|
||||||
VotingDuration = ParseTimeConfig(j, "VotingDuration");
|
VotingDuration = ParseTimeConfig(j, "VotingDuration");
|
||||||
VotingCooldown = ParseTimeConfig(j, "VotingCooldown");
|
VotingCooldown = ParseTimeConfig(j, "VotingCooldown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ParseChannelNameConfig(JObject conf, string valueName)
|
||||||
|
{
|
||||||
|
var value = j[valueName]?.Value<string>();
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
throw new RuleImportException($"'{valueName}' must be specified.");
|
||||||
|
if (!Regex.IsMatch(TempChannelName, @"^([A-Za-z0-9]|[-_ ])+$"))
|
||||||
|
throw new RuleImportException($"'{valueName}' contains one or more invalid characters.");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private TimeSpan ParseTimeConfig(JObject conf, string valueName)
|
private TimeSpan ParseTimeConfig(JObject conf, string valueName)
|
||||||
{
|
{
|
||||||
var inputstr = conf[valueName]?.Value<string>();
|
var inputstr = conf[valueName]?.Value<string>();
|
||||||
|
|
48
Module/VoteTempChannel/GuildInformation.cs
Normal file
48
Module/VoteTempChannel/GuildInformation.cs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Guild state object. Contains known information about the guild.
|
||||||
|
/// Contains helper functions that may involve usage of data contained within.
|
||||||
|
/// </summary>
|
||||||
|
class GuildInformation
|
||||||
|
{
|
||||||
|
public Configuration Config { get; }
|
||||||
|
public VotingSession Voting { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timestamp of last activity in the temporary channel.
|
||||||
|
/// Used to determine its expiration.
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset TempChannelLastActivity { get; set; }
|
||||||
|
|
||||||
|
public GuildInformation(JObject conf)
|
||||||
|
{
|
||||||
|
// In case temp channel exists as we (re)start, begin a new timer for it.
|
||||||
|
TempChannelLastActivity = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
Config = new Configuration(conf);
|
||||||
|
Voting = new VotingSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketTextChannel GetTemporaryChannel(SocketGuild guild)
|
||||||
|
{
|
||||||
|
foreach (var ch in guild.TextChannels)
|
||||||
|
{
|
||||||
|
if (string.Equals(ch.Name, Config.TempChannelName, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTempChannelExpired()
|
||||||
|
{
|
||||||
|
return DateTimeOffset.UtcNow > TempChannelLastActivity + Config.ChannelDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ using Discord.WebSocket;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Noikoio.RegexBot.ConfigItem;
|
using Noikoio.RegexBot.ConfigItem;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Noikoio.RegexBot.Module.VoteTempChannel
|
namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
|
@ -15,6 +16,8 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class VoteTempChannel : BotModule
|
class VoteTempChannel : BotModule
|
||||||
{
|
{
|
||||||
|
Task _backgroundWorker;
|
||||||
|
CancellationTokenSource _backgroundWorkerCancel;
|
||||||
ChannelManager _chMgr;
|
ChannelManager _chMgr;
|
||||||
internal VoteStore _votes;
|
internal VoteStore _votes;
|
||||||
|
|
||||||
|
@ -27,11 +30,15 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
client.GuildAvailable += GuildEnter;
|
client.GuildAvailable += GuildEnter;
|
||||||
client.LeftGuild += GuildLeave;
|
client.LeftGuild += GuildLeave;
|
||||||
client.MessageReceived += Client_MessageReceived;
|
client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
|
_backgroundWorkerCancel = new CancellationTokenSource();
|
||||||
|
_backgroundWorker = Task.Factory.StartNew(BackgroundCheckingTask, _backgroundWorkerCancel.Token,
|
||||||
|
TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GuildEnter(SocketGuild arg)
|
private async Task GuildEnter(SocketGuild arg)
|
||||||
{
|
{
|
||||||
var conf = GetState<GuildConfiguration>(arg.Id);
|
var conf = GetState<Configuration>(arg.Id);
|
||||||
if (conf != null) await _chMgr.RecheckExpiryInformation(arg, conf);
|
if (conf != null) await _chMgr.RecheckExpiryInformation(arg, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +95,7 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleVote_TempChannelNotExists(SocketMessage arg, SocketGuild guild, GuildConfiguration conf, int voteCount)
|
private async Task HandleVote_TempChannelNotExists(SocketMessage arg, SocketGuild guild, Configuration conf, int voteCount)
|
||||||
{
|
{
|
||||||
bool threshold = voteCount >= conf.VotePassThreshold;
|
bool threshold = voteCount >= conf.VotePassThreshold;
|
||||||
RestTextChannel newCh = null;
|
RestTextChannel newCh = null;
|
||||||
|
@ -106,7 +113,7 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
+ "\nPlease note that this channel is temporary and *will* be deleted at a later time.");
|
+ "\nPlease note that this channel is temporary and *will* be deleted at a later time.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleVote_TempChannelExists(SocketMessage arg, SocketGuild guild, GuildConfiguration conf, int voteCount)
|
private async Task HandleVote_TempChannelExists(SocketMessage arg, SocketGuild guild, Configuration conf, int voteCount)
|
||||||
{
|
{
|
||||||
// It's been checked that the incoming message originated from the temporary channel itself before coming here.
|
// It's been checked that the incoming message originated from the temporary channel itself before coming here.
|
||||||
if (!_chMgr.IsUpForRenewal(guild, conf))
|
if (!_chMgr.IsUpForRenewal(guild, conf))
|
||||||
|
@ -136,15 +143,83 @@ namespace Noikoio.RegexBot.Module.VoteTempChannel
|
||||||
if (configSection == null) return Task.FromResult<object>(null);
|
if (configSection == null) return Task.FromResult<object>(null);
|
||||||
if (configSection.Type == JTokenType.Object)
|
if (configSection.Type == JTokenType.Object)
|
||||||
{
|
{
|
||||||
return Task.FromResult<object>(new GuildConfiguration((JObject)configSection));
|
return Task.FromResult<object>(new GuildInformation((JObject)configSection));
|
||||||
}
|
}
|
||||||
throw new RuleImportException("Configuration not of a valid type.");
|
throw new RuleImportException("Configuration not of a valid type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Background tasks
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Publicly accessible method for fetching config. Used by <see cref="ChannelManager"/>.
|
/// Two functions: Removes expired channels, and announces expired votes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GuildConfiguration GetConfig(ulong guildId) => GetState<GuildConfiguration>(guildId);
|
private async Task BackgroundCheckingTask()
|
||||||
// TODO check if used ^. attempt to not use.
|
{
|
||||||
|
while (!_backgroundWorkerCancel.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try { await Task.Delay(12000, _backgroundWorkerCancel.Token); }
|
||||||
|
catch (TaskCanceledException) { return; }
|
||||||
|
|
||||||
|
foreach (var g in Client.Guilds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var conf = GetState<GuildInformation>(g.Id);
|
||||||
|
if (conf == null) continue;
|
||||||
|
|
||||||
|
await BackgroundTempChannelExpiryCheck(g, conf);
|
||||||
|
await BackgroundVoteSessionExpiryCheck(g, conf);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log("Unhandled exception in background task when processing a single guild.").Wait();
|
||||||
|
Log(ex.ToString()).Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task BackgroundTempChannelExpiryCheck(SocketGuild g, GuildInformation conf)
|
||||||
|
{
|
||||||
|
SocketGuildChannel ch = null;
|
||||||
|
lock (conf)
|
||||||
|
{
|
||||||
|
ch = conf.GetTemporaryChannel(g);
|
||||||
|
if (ch == null) return; // No temporary channel. Nothing to do.
|
||||||
|
if (!conf.IsTempChannelExpired()) return;
|
||||||
|
|
||||||
|
// If we got this far, the channel's expiring. Start the voting cooldown.
|
||||||
|
conf.Voting.StartCooldown();
|
||||||
|
}
|
||||||
|
await ch.DeleteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task BackgroundVoteSessionExpiryCheck(SocketGuild g, GuildInformation conf)
|
||||||
|
{
|
||||||
|
bool act;
|
||||||
|
string nameTest;
|
||||||
|
lock (conf) {
|
||||||
|
act = conf.Voting.IsSessionExpired();
|
||||||
|
nameTest = conf.Config.VotingChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!act) return;
|
||||||
|
// Determine the voting channel; will send announcement there.
|
||||||
|
SocketTextChannel outCh = null;
|
||||||
|
foreach (var ch in g.TextChannels)
|
||||||
|
{
|
||||||
|
if (string.Equals(ch.Name, nameTest, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
outCh = ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outCh == null)
|
||||||
|
{
|
||||||
|
// Huh. Bad config?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await outCh.SendMessageAsync(":x: Not enough votes were placed for channel creation.");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue