mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-22 13:54:36 +00:00
Additions to BackgroundWorker
-Added Discord Bots reporting -Birthdays now properly processed asynchronously -Added an announcement count
This commit is contained in:
parent
4fb2ac3dee
commit
9f6ab5867a
3 changed files with 99 additions and 23 deletions
|
@ -1,4 +1,5 @@
|
||||||
Imports System.Text
|
Imports System.Net
|
||||||
|
Imports System.Text
|
||||||
Imports System.Threading
|
Imports System.Threading
|
||||||
Imports Discord.WebSocket
|
Imports Discord.WebSocket
|
||||||
Imports NodaTime
|
Imports NodaTime
|
||||||
|
@ -11,8 +12,7 @@ Class BackgroundWorker
|
||||||
Private ReadOnly _db As Database
|
Private ReadOnly _db As Database
|
||||||
Private ReadOnly Property WorkerCancel As New CancellationTokenSource
|
Private ReadOnly Property WorkerCancel As New CancellationTokenSource
|
||||||
Private _workerTask As Task
|
Private _workerTask As Task
|
||||||
' NOTE: Interval greatly lowered. Raise to 45 seconds if server count goes up.
|
Const Interval = 45 ' How often the worker wakes up, in seconds. Adjust as needed.
|
||||||
Const Interval = 15 ' How often the worker wakes up, in seconds
|
|
||||||
Private _clock As IClock
|
Private _clock As IClock
|
||||||
|
|
||||||
Sub New(instance As BirthdayBot, dbsettings As Database)
|
Sub New(instance As BirthdayBot, dbsettings As Database)
|
||||||
|
@ -31,19 +31,21 @@ Class BackgroundWorker
|
||||||
Await _workerTask
|
Await _workerTask
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Background task. Kicks off many other tasks.
|
||||||
|
''' </summary>
|
||||||
Private Async Function WorkerLoop() As Task
|
Private Async Function WorkerLoop() As Task
|
||||||
Try
|
Try
|
||||||
While Not WorkerCancel.IsCancellationRequested
|
While Not WorkerCancel.IsCancellationRequested
|
||||||
|
' Start background tasks.
|
||||||
|
Dim bgTasks As New List(Of Task) From {
|
||||||
|
ReportServerCount(),
|
||||||
|
BirthdayAsync()
|
||||||
|
}
|
||||||
|
Await Task.WhenAll(bgTasks)
|
||||||
|
|
||||||
|
' All done. Wait until we have to work again.
|
||||||
Await Task.Delay(Interval * 1000, WorkerCancel.Token)
|
Await Task.Delay(Interval * 1000, WorkerCancel.Token)
|
||||||
WorkerCancel.Token.ThrowIfCancellationRequested()
|
|
||||||
Try
|
|
||||||
For Each guild In _bot.DiscordClient.Guilds
|
|
||||||
Dim b = BirthdayWorkAsync(guild)
|
|
||||||
Await b
|
|
||||||
Next
|
|
||||||
Catch ex As Exception
|
|
||||||
Log("Error", ex.ToString())
|
|
||||||
End Try
|
|
||||||
End While
|
End While
|
||||||
Catch ex As TaskCanceledException
|
Catch ex As TaskCanceledException
|
||||||
Return
|
Return
|
||||||
|
@ -52,16 +54,50 @@ Class BackgroundWorker
|
||||||
|
|
||||||
#Region "Birthday handling"
|
#Region "Birthday handling"
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' All birthday checking happens here.
|
''' Birthday tasks processing. Sets up a task per guild and waits on them.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Async Function BirthdayWorkAsync(guild As SocketGuild) As Task
|
Private Async Function BirthdayAsync() As Task
|
||||||
|
Dim tasks As New List(Of Task(Of Integer))
|
||||||
|
For Each guild In _bot.DiscordClient.Guilds
|
||||||
|
Dim t = BirthdayGuildProcessAsync(guild)
|
||||||
|
tasks.Add(t)
|
||||||
|
Next
|
||||||
|
Try
|
||||||
|
Await Task.WhenAll(tasks)
|
||||||
|
Catch ex As Exception
|
||||||
|
Dim exs = From task In tasks
|
||||||
|
Where task.Exception IsNot Nothing
|
||||||
|
Select task.Exception
|
||||||
|
Log("Error", "Encountered one or more unhandled exceptions during birthday processing.")
|
||||||
|
For Each iex In exs
|
||||||
|
Log("Error", iex.ToString())
|
||||||
|
Next
|
||||||
|
End Try
|
||||||
|
|
||||||
|
' Usage report: Show how many announcements were done
|
||||||
|
Dim announces = 0
|
||||||
|
Dim guilds = 0
|
||||||
|
For Each task In tasks
|
||||||
|
If task.Result > 0 Then
|
||||||
|
announces += task.Result
|
||||||
|
guilds += 1
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
If announces > 0 Then Log("Background", $"Announcing {announces} birthday(s) in {guilds} guild(s).")
|
||||||
|
End Function
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Birthday processing for an individual guild.
|
||||||
|
''' </summary>
|
||||||
|
''' <returns>Number of birthdays announced.</returns>
|
||||||
|
Private Async Function BirthdayGuildProcessAsync(guild As SocketGuild) As Task(Of Integer)
|
||||||
' Gather required information
|
' Gather required information
|
||||||
Dim tz As String
|
Dim tz As String
|
||||||
Dim users As IEnumerable(Of GuildUserSettings)
|
Dim users As IEnumerable(Of GuildUserSettings)
|
||||||
Dim role As SocketRole = Nothing
|
Dim role As SocketRole = Nothing
|
||||||
Dim channel As SocketTextChannel = Nothing
|
Dim channel As SocketTextChannel = Nothing
|
||||||
SyncLock _bot.KnownGuilds
|
SyncLock _bot.KnownGuilds
|
||||||
If Not _bot.KnownGuilds.ContainsKey(guild.Id) Then Return
|
If Not _bot.KnownGuilds.ContainsKey(guild.Id) Then Return 0
|
||||||
Dim gs = _bot.KnownGuilds(guild.Id)
|
Dim gs = _bot.KnownGuilds(guild.Id)
|
||||||
tz = gs.TimeZone
|
tz = gs.TimeZone
|
||||||
users = gs.Users
|
users = gs.Users
|
||||||
|
@ -70,7 +106,7 @@ Class BackgroundWorker
|
||||||
If gs.RoleId.HasValue Then role = guild.GetRole(gs.RoleId.Value)
|
If gs.RoleId.HasValue Then role = guild.GetRole(gs.RoleId.Value)
|
||||||
If role Is Nothing Then
|
If role Is Nothing Then
|
||||||
gs.RoleWarning = True
|
gs.RoleWarning = True
|
||||||
Return
|
Return 0
|
||||||
End If
|
End If
|
||||||
End SyncLock
|
End SyncLock
|
||||||
|
|
||||||
|
@ -80,10 +116,12 @@ Class BackgroundWorker
|
||||||
|
|
||||||
' Set birthday role, get list of users now having birthdays
|
' Set birthday role, get list of users now having birthdays
|
||||||
Dim announceNames = Await BirthdayApplyAsync(guild, role, birthdays)
|
Dim announceNames = Await BirthdayApplyAsync(guild, role, birthdays)
|
||||||
If announceNames.Count = 0 Then Return
|
If announceNames.Count <> 0 Then
|
||||||
|
|
||||||
' Send out announcement message
|
' Send out announcement message
|
||||||
Await BirthdayAnnounceAsync(guild, channel, announceNames)
|
Await BirthdayAnnounceAsync(guild, channel, announceNames)
|
||||||
|
End If
|
||||||
|
|
||||||
|
Return announceNames.Count
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
|
@ -114,7 +152,7 @@ Class BackgroundWorker
|
||||||
|
|
||||||
Dim checkNow = _clock.GetCurrentInstant().InZone(tz)
|
Dim checkNow = _clock.GetCurrentInstant().InZone(tz)
|
||||||
' Special case: If birthday is February 29 and it's not a leap year, recognize it on March 1st
|
' Special case: If birthday is February 29 and it's not a leap year, recognize it on March 1st
|
||||||
If targetMonth = 2 And targetDay = 29 And Not DateTime.IsLeapYear(checkNow.Year) Then
|
If targetMonth = 2 And targetDay = 29 And Not Date.IsLeapYear(checkNow.Year) Then
|
||||||
targetMonth = 3
|
targetMonth = 3
|
||||||
targetDay = 1
|
targetDay = 1
|
||||||
End If
|
End If
|
||||||
|
@ -181,9 +219,9 @@ Class BackgroundWorker
|
||||||
Else
|
Else
|
||||||
name = item.Username
|
name = item.Username
|
||||||
End If
|
End If
|
||||||
namedisplay.Append(name)
|
namedisplay.Append("**" + name + "**")
|
||||||
Next
|
Next
|
||||||
result = $"Please wish our members a happy birthday!{vbLf}In no particular order: {namedisplay.ToString()}"
|
result = $"Please wish our esteemed members a happy birthday!{vbLf}In no particular order: {namedisplay.ToString()}"
|
||||||
End If
|
End If
|
||||||
|
|
||||||
Try
|
Try
|
||||||
|
@ -193,4 +231,34 @@ Class BackgroundWorker
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
#End Region
|
||||||
|
|
||||||
|
#Region "Activity reporting"
|
||||||
|
Private _activityCount As Integer = 0
|
||||||
|
Private Async Function ReportServerCount() As Task
|
||||||
|
' Once roughly every 6 hours, with an initial ~2 minute delay. Be mindful of the interval value.
|
||||||
|
_activityCount += 1
|
||||||
|
If _activityCount Mod 400 <> 2 Then Return
|
||||||
|
|
||||||
|
Dim count = _bot.DiscordClient.Guilds.Count
|
||||||
|
Log("Activity Report", $"Currently in {count} guild(s).")
|
||||||
|
|
||||||
|
Dim dtok = _bot._cfg.DBotsToken
|
||||||
|
If dtok IsNot Nothing Then
|
||||||
|
Const dUrl As String = "https://bots.discord.pw/api/bots/{0}/stats"
|
||||||
|
|
||||||
|
Using client As New WebClient()
|
||||||
|
Dim uri = New Uri(String.Format(dUrl, CType(_bot.DiscordClient.CurrentUser.Id, String)))
|
||||||
|
Dim data = "{ ""server_count"": " + CType(count, String) + " }"
|
||||||
|
client.Headers(HttpRequestHeader.Authorization) = dtok
|
||||||
|
client.Headers(HttpRequestHeader.ContentType) = "application/json"
|
||||||
|
Try
|
||||||
|
Await client.UploadStringTaskAsync(uri, data)
|
||||||
|
Log("Activity Report", "Count sent to Discord Bots.")
|
||||||
|
Catch ex As WebException
|
||||||
|
Log("Activity Report", "Encountered error on sending to Discord Bots: " + ex.Message)
|
||||||
|
End Try
|
||||||
|
End Using
|
||||||
|
End If
|
||||||
|
End Function
|
||||||
|
#End Region
|
||||||
End Class
|
End Class
|
||||||
|
|
|
@ -14,7 +14,7 @@ Class BirthdayBot
|
||||||
Private ReadOnly _cmdsMods As ManagerCommands
|
Private ReadOnly _cmdsMods As ManagerCommands
|
||||||
|
|
||||||
Private WithEvents _client As DiscordSocketClient
|
Private WithEvents _client As DiscordSocketClient
|
||||||
Private _cfg As Configuration
|
Friend _cfg As Configuration
|
||||||
Private ReadOnly _worker As BackgroundWorker
|
Private ReadOnly _worker As BackgroundWorker
|
||||||
|
|
||||||
Friend ReadOnly Property DiscordClient As DiscordSocketClient
|
Friend ReadOnly Property DiscordClient As DiscordSocketClient
|
||||||
|
|
|
@ -7,6 +7,7 @@ Imports System.IO
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Class Configuration
|
Class Configuration
|
||||||
Public ReadOnly Property BotToken As String
|
Public ReadOnly Property BotToken As String
|
||||||
|
Public ReadOnly Property DBotsToken As String
|
||||||
Public ReadOnly Property DatabaseSettings As Database
|
Public ReadOnly Property DatabaseSettings As Database
|
||||||
|
|
||||||
Sub New()
|
Sub New()
|
||||||
|
@ -25,6 +26,13 @@ Class Configuration
|
||||||
Throw New Exception("'BotToken' must be specified.")
|
Throw New Exception("'BotToken' must be specified.")
|
||||||
End If
|
End If
|
||||||
|
|
||||||
|
Dim dbj = jc("DBotsToken")
|
||||||
|
If dbj IsNot Nothing Then
|
||||||
|
DBotsToken = dbj.Value(Of String)()
|
||||||
|
Else
|
||||||
|
DBotsToken = Nothing
|
||||||
|
End If
|
||||||
|
|
||||||
Dim sqlcs = jc("SqlConnectionString").Value(Of String)()
|
Dim sqlcs = jc("SqlConnectionString").Value(Of String)()
|
||||||
If String.IsNullOrWhiteSpace(sqlcs) Then
|
If String.IsNullOrWhiteSpace(sqlcs) Then
|
||||||
Throw New Exception("'SqlConnectionString' must be specified.")
|
Throw New Exception("'SqlConnectionString' must be specified.")
|
||||||
|
|
Loading…
Reference in a new issue