mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-22 05:54:36 +00:00
Split BackgroundWorker into various components
This commit is contained in:
parent
9608a29a8a
commit
fe5bdb53f9
10 changed files with 188 additions and 133 deletions
58
BirthdayBot/BackgroundServiceRunner.vb
Normal file
58
BirthdayBot/BackgroundServiceRunner.vb
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
Imports System.Threading
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Handles the execution of periodic background tasks.
|
||||||
|
''' </summary>
|
||||||
|
Class BackgroundServiceRunner
|
||||||
|
Const Interval = 45 ' Tick interval in seconds. Adjust as needed.
|
||||||
|
|
||||||
|
Private ReadOnly Property Workers As List(Of BackgroundService)
|
||||||
|
Private ReadOnly Property WorkerCancel As New CancellationTokenSource
|
||||||
|
|
||||||
|
Private _workerTask As Task
|
||||||
|
Private _tickCount As Integer
|
||||||
|
|
||||||
|
Sub New(instance As BirthdayBot)
|
||||||
|
Workers = New List(Of BackgroundService) From {
|
||||||
|
{New GuildStatistics(instance)},
|
||||||
|
{New Heartbeat(instance)},
|
||||||
|
{New BirthdayRoleUpdate(instance)}
|
||||||
|
}
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Sub Start()
|
||||||
|
_tickCount = 0
|
||||||
|
_workerTask = Task.Factory.StartNew(AddressOf WorkerLoop, WorkerCancel.Token,
|
||||||
|
TaskCreationOptions.LongRunning, TaskScheduler.Default)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Async Function Cancel() As Task
|
||||||
|
WorkerCancel.Cancel()
|
||||||
|
Await _workerTask
|
||||||
|
End Function
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' *The* background task. Executes service tasks and handles errors.
|
||||||
|
''' </summary>
|
||||||
|
Private Async Function WorkerLoop() As Task
|
||||||
|
While Not WorkerCancel.IsCancellationRequested
|
||||||
|
Try
|
||||||
|
' Delay a bit before we start (or continue) work.
|
||||||
|
Await Task.Delay(Interval * 1000, WorkerCancel.Token)
|
||||||
|
|
||||||
|
' Start background tasks.
|
||||||
|
Dim tasks As New List(Of Task)
|
||||||
|
For Each service In Workers
|
||||||
|
tasks.Add(service.OnTick(_tickCount))
|
||||||
|
Next
|
||||||
|
Await Task.WhenAll(tasks)
|
||||||
|
Catch ex As TaskCanceledException
|
||||||
|
Return
|
||||||
|
Catch ex As Exception
|
||||||
|
Log("Background task", "Unhandled exception in background task thread:")
|
||||||
|
Log("Background task", ex.ToString())
|
||||||
|
End Try
|
||||||
|
_tickCount += 1
|
||||||
|
End While
|
||||||
|
End Function
|
||||||
|
End Class
|
17
BirthdayBot/BackgroundServices/BackgroundService.vb
Normal file
17
BirthdayBot/BackgroundServices/BackgroundService.vb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
''' <summary>
|
||||||
|
''' Base class for background services.
|
||||||
|
''' Background services are called periodically by another class.
|
||||||
|
''' </summary>
|
||||||
|
MustInherit Class BackgroundService
|
||||||
|
Protected ReadOnly Property BotInstance As BirthdayBot
|
||||||
|
|
||||||
|
Sub New(instance As BirthdayBot)
|
||||||
|
BotInstance = instance
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Sub Log(message As String)
|
||||||
|
Program.Log(Me.GetType().Name, message)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
MustOverride Function OnTick(tick As Integer) As Task
|
||||||
|
End Class
|
|
@ -1,77 +1,40 @@
|
||||||
Imports System.Net
|
Imports System.Net
|
||||||
Imports System.Text
|
Imports System.Text
|
||||||
Imports System.Threading
|
|
||||||
Imports Discord.WebSocket
|
Imports Discord.WebSocket
|
||||||
Imports NodaTime
|
Imports NodaTime
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' BirthdayBot's periodic task. Frequently wakes up to take various actions.
|
''' Periodically scans all known guilds and adjusts birthday role membership as necessary.
|
||||||
|
''' Also handles birthday announcements.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Class BackgroundWorker
|
Class BirthdayRoleUpdate
|
||||||
Private ReadOnly _bot As BirthdayBot
|
Inherits BackgroundService
|
||||||
Private ReadOnly Property WorkerCancel As New CancellationTokenSource
|
Private ReadOnly Property Clock As IClock
|
||||||
Private _workerTask As Task
|
|
||||||
Const Interval = 45 ' How often the worker wakes up, in seconds. Adjust as needed.
|
|
||||||
Private ReadOnly _clock As IClock
|
|
||||||
|
|
||||||
Sub New(instance As BirthdayBot)
|
Public Sub New(instance As BirthdayBot)
|
||||||
_bot = instance
|
MyBase.New(instance)
|
||||||
_clock = SystemClock.Instance ' can replace with FakeClock here when testing
|
Clock = SystemClock.Instance ' can be replaced with FakeClock during testing
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Sub Start()
|
|
||||||
_workerTask = Task.Factory.StartNew(AddressOf WorkerLoop, WorkerCancel.Token,
|
|
||||||
TaskCreationOptions.LongRunning, TaskScheduler.Default)
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
Public Async Function Cancel() As Task
|
|
||||||
WorkerCancel.Cancel()
|
|
||||||
Await _workerTask
|
|
||||||
End Function
|
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' Background task. Kicks off many other tasks.
|
''' Initial processing: Sets up a task per guild and waits on all.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Async Function WorkerLoop() As Task
|
Public Overrides Async Function OnTick(tick As Integer) As Task
|
||||||
While Not WorkerCancel.IsCancellationRequested
|
|
||||||
Try
|
|
||||||
' Delay a bit before we start (or continue) work.
|
|
||||||
Await Task.Delay(Interval * 1000, WorkerCancel.Token)
|
|
||||||
|
|
||||||
' Start background tasks.
|
|
||||||
Dim bgTasks As New List(Of Task) From {
|
|
||||||
ReportAsync(),
|
|
||||||
BirthdayAsync()
|
|
||||||
}
|
|
||||||
Await Task.WhenAll(bgTasks)
|
|
||||||
Catch ex As TaskCanceledException
|
|
||||||
Return
|
|
||||||
Catch ex As Exception
|
|
||||||
Log("Background task", "Unhandled exception in background task thread:")
|
|
||||||
Log("Background task", ex.ToString())
|
|
||||||
End Try
|
|
||||||
End While
|
|
||||||
End Function
|
|
||||||
|
|
||||||
#Region "Birthday handling"
|
|
||||||
''' <summary>
|
|
||||||
''' Birthday tasks processing. Sets up a task per guild and waits on them.
|
|
||||||
''' </summary>
|
|
||||||
Private Async Function BirthdayAsync() As Task
|
|
||||||
Dim tasks As New List(Of Task(Of Integer))
|
Dim tasks As New List(Of Task(Of Integer))
|
||||||
For Each guild In _bot.DiscordClient.Guilds
|
For Each guild In BotInstance.DiscordClient.Guilds
|
||||||
Dim t = BirthdayGuildProcessAsync(guild)
|
Dim t = ProcessGuildAsync(guild)
|
||||||
tasks.Add(t)
|
tasks.Add(t)
|
||||||
Next
|
Next
|
||||||
|
|
||||||
Try
|
Try
|
||||||
Await Task.WhenAll(tasks)
|
Await Task.WhenAll(tasks)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
Dim exs = From task In tasks
|
Dim exs = From task In tasks
|
||||||
Where task.Exception IsNot Nothing
|
Where task.Exception IsNot Nothing
|
||||||
Select task.Exception
|
Select task.Exception
|
||||||
Log("Error", "Encountered one or more unhandled exceptions during birthday processing.")
|
Log($"Encountered {exs.Count} errors during bulk guild processing.")
|
||||||
For Each iex In exs
|
For Each iex In exs
|
||||||
Log("Error", iex.ToString())
|
Log(iex.ToString())
|
||||||
Next
|
Next
|
||||||
End Try
|
End Try
|
||||||
|
|
||||||
|
@ -84,14 +47,10 @@ Class BackgroundWorker
|
||||||
guilds += 1
|
guilds += 1
|
||||||
End If
|
End If
|
||||||
Next
|
Next
|
||||||
If announces > 0 Then Log("Birthday task", $"Announcing {announces} birthday(s) in {guilds} guild(s).")
|
If announces > 0 Then Log($"Announcing {announces} birthday(s) in {guilds} guild(s).")
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
''' <summary>
|
Async Function ProcessGuildAsync(guild As SocketGuild) As Task(Of Integer)
|
||||||
''' 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)
|
||||||
|
@ -99,9 +58,9 @@ Class BackgroundWorker
|
||||||
Dim channel As SocketTextChannel = Nothing
|
Dim channel As SocketTextChannel = Nothing
|
||||||
Dim announce As (String, String)
|
Dim announce As (String, String)
|
||||||
Dim announceping As Boolean
|
Dim announceping As Boolean
|
||||||
SyncLock _bot.KnownGuilds
|
SyncLock BotInstance.KnownGuilds
|
||||||
If Not _bot.KnownGuilds.ContainsKey(guild.Id) Then Return 0
|
If Not BotInstance.KnownGuilds.ContainsKey(guild.Id) Then Return 0
|
||||||
Dim gs = _bot.KnownGuilds(guild.Id)
|
Dim gs = BotInstance.KnownGuilds(guild.Id)
|
||||||
tz = gs.TimeZone
|
tz = gs.TimeZone
|
||||||
users = gs.Users
|
users = gs.Users
|
||||||
announce = gs.AnnounceMessages
|
announce = gs.AnnounceMessages
|
||||||
|
@ -117,15 +76,15 @@ Class BackgroundWorker
|
||||||
End SyncLock
|
End SyncLock
|
||||||
|
|
||||||
' Determine who's currently having a birthday
|
' Determine who's currently having a birthday
|
||||||
Dim birthdays = BirthdayCalculate(users, tz)
|
Dim birthdays = GetGuildCurrentBirthdays(users, tz)
|
||||||
' Note: Don't quit here if zero people are having birthdays. Roles may still need to be removed by BirthdayApply.
|
' Note: Don't quit here if zero people are having birthdays. Roles may still need to be removed by BirthdayApply.
|
||||||
|
|
||||||
' Set birthday roles, get list of users that had the role added
|
' Set birthday roles, get list of users that had the role added
|
||||||
' But first check if we are able to do so. Letting all requests fail instead will lead to rate limiting.
|
' But first check if we are able to do so. Letting all requests fail instead will lead to rate limiting.
|
||||||
Dim announceNames As IEnumerable(Of SocketGuildUser)
|
Dim announceNames As IEnumerable(Of SocketGuildUser)
|
||||||
If BirthdayHasGoodRolePermissions(guild, role) Then
|
If HasCorrectRolePermissions(guild, role) Then
|
||||||
Try
|
Try
|
||||||
announceNames = Await BirthdayApplyAsync(guild, role, birthdays)
|
announceNames = Await UpdateGuildBirthdayRoles(guild, role, birthdays)
|
||||||
Catch ex As Discord.Net.HttpException
|
Catch ex As Discord.Net.HttpException
|
||||||
If ex.HttpCode = HttpStatusCode.Forbidden Then
|
If ex.HttpCode = HttpStatusCode.Forbidden Then
|
||||||
announceNames = Nothing
|
announceNames = Nothing
|
||||||
|
@ -138,16 +97,16 @@ Class BackgroundWorker
|
||||||
End If
|
End If
|
||||||
|
|
||||||
If announceNames Is Nothing Then
|
If announceNames Is Nothing Then
|
||||||
SyncLock _bot.KnownGuilds
|
SyncLock BotInstance.KnownGuilds
|
||||||
' Nothing on announceNAmes signals failure to apply roles. Set the warning message.
|
' Nothing on announceNAmes signals failure to apply roles. Set the warning message.
|
||||||
_bot.KnownGuilds(guild.Id).RoleWarning = True
|
BotInstance.KnownGuilds(guild.Id).RoleWarning = True
|
||||||
End SyncLock
|
End SyncLock
|
||||||
Return 0
|
Return 0
|
||||||
End If
|
End If
|
||||||
|
|
||||||
If announceNames.Count <> 0 Then
|
If announceNames.Count <> 0 Then
|
||||||
' Send out announcement message
|
' Send out announcement message
|
||||||
Await BirthdayAnnounceAsync(announce, announceping, channel, announceNames)
|
Await AnnounceBirthdaysAsync(announce, announceping, channel, announceNames)
|
||||||
End If
|
End If
|
||||||
Return announceNames.Count
|
Return announceNames.Count
|
||||||
End Function
|
End Function
|
||||||
|
@ -155,7 +114,7 @@ Class BackgroundWorker
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' Checks if the bot may be allowed to alter roles.
|
''' Checks if the bot may be allowed to alter roles.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Function BirthdayHasGoodRolePermissions(guild As SocketGuild, role As SocketRole) As Boolean
|
Private Function HasCorrectRolePermissions(guild As SocketGuild, role As SocketRole) As Boolean
|
||||||
If Not guild.CurrentUser.GuildPermissions.ManageRoles Then
|
If Not guild.CurrentUser.GuildPermissions.ManageRoles Then
|
||||||
' Bot user cannot manage roles
|
' Bot user cannot manage roles
|
||||||
Return False
|
Return False
|
||||||
|
@ -174,7 +133,8 @@ Class BackgroundWorker
|
||||||
''' Gets all known users from the given guild and returns a list including only those who are
|
''' Gets all known users from the given guild and returns a list including only those who are
|
||||||
''' currently experiencing a birthday in the respective time zone.
|
''' currently experiencing a birthday in the respective time zone.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Function BirthdayCalculate(guildUsers As IEnumerable(Of GuildUserSettings), defaultTzStr As String) As HashSet(Of ULong)
|
Private Function GetGuildCurrentBirthdays(guildUsers As IEnumerable(Of GuildUserSettings),
|
||||||
|
defaultTzStr As String) As HashSet(Of ULong)
|
||||||
Dim birthdayUsers As New HashSet(Of ULong)
|
Dim birthdayUsers As New HashSet(Of ULong)
|
||||||
|
|
||||||
Dim defaultTz As DateTimeZone = Nothing
|
Dim defaultTz As DateTimeZone = Nothing
|
||||||
|
@ -196,7 +156,7 @@ Class BackgroundWorker
|
||||||
Dim targetMonth = item.BirthMonth
|
Dim targetMonth = item.BirthMonth
|
||||||
Dim targetDay = item.BirthDay
|
Dim targetDay = item.BirthDay
|
||||||
|
|
||||||
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 Date.IsLeapYear(checkNow.Year) Then
|
If targetMonth = 2 And targetDay = 29 And Not Date.IsLeapYear(checkNow.Year) Then
|
||||||
targetMonth = 3
|
targetMonth = 3
|
||||||
|
@ -214,7 +174,7 @@ Class BackgroundWorker
|
||||||
''' Sets the birthday role to all applicable users. Unsets it from all others who may have it.
|
''' Sets the birthday role to all applicable users. Unsets it from all others who may have it.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
''' <returns>A list of users who had the birthday role applied. Use for the announcement message.</returns>
|
''' <returns>A list of users who had the birthday role applied. Use for the announcement message.</returns>
|
||||||
Private Async Function BirthdayApplyAsync(g As SocketGuild,
|
Private Async Function UpdateGuildBirthdayRoles(g As SocketGuild,
|
||||||
r As SocketRole,
|
r As SocketRole,
|
||||||
names As HashSet(Of ULong)) As Task(Of IEnumerable(Of SocketGuildUser))
|
names As HashSet(Of ULong)) As Task(Of IEnumerable(Of SocketGuildUser))
|
||||||
' Check members currently with the role. Figure out which users to remove it from.
|
' Check members currently with the role. Figure out which users to remove it from.
|
||||||
|
@ -255,7 +215,7 @@ Class BackgroundWorker
|
||||||
''' Makes (or attempts to make) an announcement in the specified channel that includes all users
|
''' Makes (or attempts to make) an announcement in the specified channel that includes all users
|
||||||
''' who have just had their birthday role added.
|
''' who have just had their birthday role added.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Private Async Function BirthdayAnnounceAsync(announce As (String, String),
|
Private Async Function AnnounceBirthdaysAsync(announce As (String, String),
|
||||||
announcePing As Boolean,
|
announcePing As Boolean,
|
||||||
c As SocketTextChannel,
|
c As SocketTextChannel,
|
||||||
names As IEnumerable(Of SocketGuildUser)) As Task
|
names As IEnumerable(Of SocketGuildUser)) As Task
|
||||||
|
@ -294,56 +254,4 @@ Class BackgroundWorker
|
||||||
' TODO keep tabs on this somehow for troubleshooting purposes
|
' TODO keep tabs on this somehow for troubleshooting purposes
|
||||||
End Try
|
End Try
|
||||||
End Function
|
End Function
|
||||||
#End Region
|
|
||||||
|
|
||||||
#Region "Activity reporting"
|
|
||||||
''' <summary>
|
|
||||||
''' Increasing value for regulating how often certain tasks are done.
|
|
||||||
''' For anything relying on this value, also be mindful of the interval value.
|
|
||||||
''' </summary>
|
|
||||||
Private _reportTick As Integer = 0
|
|
||||||
|
|
||||||
''' <summary>
|
|
||||||
''' Handles various periodic reporting tasks.
|
|
||||||
''' </summary>
|
|
||||||
Private Async Function ReportAsync() As Task
|
|
||||||
ReportHeartbeat(_reportTick)
|
|
||||||
Await ReportGuildCount(_reportTick)
|
|
||||||
|
|
||||||
_reportTick += 1
|
|
||||||
End Function
|
|
||||||
|
|
||||||
Private Sub ReportHeartbeat(tick As Integer)
|
|
||||||
' Roughly every 15 minutes (interval: 45)
|
|
||||||
If tick Mod 20 = 0 Then
|
|
||||||
Log("Background task", $"Still alive! Tick: {_reportTick}.")
|
|
||||||
End If
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
Private Async Function ReportGuildCount(tick As Integer) As Task
|
|
||||||
' Roughly every 5 hours (interval: 45)
|
|
||||||
If tick Mod 400 <> 2 Then Return
|
|
||||||
|
|
||||||
Dim count = _bot.DiscordClient.Guilds.Count
|
|
||||||
Log("Report", $"Currently in {count} guild(s).")
|
|
||||||
|
|
||||||
Dim dtok = _bot.Config.DBotsToken
|
|
||||||
If dtok IsNot Nothing Then
|
|
||||||
Const dUrl As String = "https://discord.bots.gg/api/v1/bots/{0}/stats"
|
|
||||||
|
|
||||||
Using client As New WebClient()
|
|
||||||
Dim uri = New Uri(String.Format(dUrl, CType(_bot.DiscordClient.CurrentUser.Id, String)))
|
|
||||||
Dim data = "{ ""guildCount"": " + CType(count, String) + " }"
|
|
||||||
client.Headers(HttpRequestHeader.Authorization) = dtok
|
|
||||||
client.Headers(HttpRequestHeader.ContentType) = "application/json"
|
|
||||||
Try
|
|
||||||
Await client.UploadStringTaskAsync(uri, data)
|
|
||||||
Log("Server Count", "Count sent to Discord Bots.")
|
|
||||||
Catch ex As WebException
|
|
||||||
Log("Server Count", "Encountered error on sending to Discord Bots: " + ex.Message)
|
|
||||||
End Try
|
|
||||||
End Using
|
|
||||||
End If
|
|
||||||
End Function
|
|
||||||
#End Region
|
|
||||||
End Class
|
End Class
|
47
BirthdayBot/BackgroundServices/GuildStatistics.vb
Normal file
47
BirthdayBot/BackgroundServices/GuildStatistics.vb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
Imports System.Net
|
||||||
|
|
||||||
|
Class GuildStatistics
|
||||||
|
Inherits BackgroundService
|
||||||
|
|
||||||
|
Private ReadOnly Property DBotsToken As String
|
||||||
|
|
||||||
|
Public Sub New(instance As BirthdayBot)
|
||||||
|
MyBase.New(instance)
|
||||||
|
DBotsToken = instance.Config.DBotsToken
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Overrides Async Function OnTick(tick As Integer) As Task
|
||||||
|
' Activate roughly every 5 hours (interval: 45)
|
||||||
|
If tick Mod 400 <> 2 Then Return
|
||||||
|
|
||||||
|
Dim count = BotInstance.DiscordClient.Guilds.Count
|
||||||
|
Log($"Currently in {count} guild(s).")
|
||||||
|
|
||||||
|
Await SendExternalStatistics(count)
|
||||||
|
End Function
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Send statistical information to external services.
|
||||||
|
''' </summary>
|
||||||
|
''' <remarks>
|
||||||
|
''' Only Discord Bots is currently supported. No plans to support others any time soon.
|
||||||
|
''' </remarks>
|
||||||
|
Async Function SendExternalStatistics(guildCount As Integer) As Task
|
||||||
|
Dim rptToken = BotInstance.Config.DBotsToken
|
||||||
|
If rptToken Is Nothing Then Return
|
||||||
|
|
||||||
|
Const apiUrl As String = "https://discord.bots.gg/api/v1/bots/{0}/stats"
|
||||||
|
Using client As New WebClient()
|
||||||
|
Dim uri = New Uri(String.Format(apiUrl, CType(BotInstance.DiscordClient.CurrentUser.Id, String)))
|
||||||
|
Dim data = "{ ""guildCount"": " + CType(guildCount, String) + " }"
|
||||||
|
client.Headers(HttpRequestHeader.Authorization) = rptToken
|
||||||
|
client.Headers(HttpRequestHeader.ContentType) = "application/json"
|
||||||
|
Try
|
||||||
|
Await client.UploadStringTaskAsync(uri, data)
|
||||||
|
Log("Discord Bots: Report sent successfully.")
|
||||||
|
Catch ex As WebException
|
||||||
|
Log("Discord Bots: Encountered an error. " + ex.Message)
|
||||||
|
End Try
|
||||||
|
End Using
|
||||||
|
End Function
|
||||||
|
End Class
|
20
BirthdayBot/BackgroundServices/Heartbeat.vb
Normal file
20
BirthdayBot/BackgroundServices/Heartbeat.vb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
''' <summary>
|
||||||
|
''' Basic heartbeat function - indicates that the background task is still functioning.
|
||||||
|
''' </summary>
|
||||||
|
Class Heartbeat
|
||||||
|
Inherits BackgroundService
|
||||||
|
|
||||||
|
Public Sub New(instance As BirthdayBot)
|
||||||
|
MyBase.New(instance)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Public Overrides Function OnTick(tick As Integer) As Task
|
||||||
|
' Print a message roughly every 15 minutes (assuming 45s per tick).
|
||||||
|
If tick Mod 20 = 0 Then
|
||||||
|
Dim uptime = DateTimeOffset.UtcNow - Program.BotStartTime
|
||||||
|
Log($"Tick {tick:00000} - Bot uptime: {BotUptime()}")
|
||||||
|
End If
|
||||||
|
|
||||||
|
Return Task.CompletedTask
|
||||||
|
End Function
|
||||||
|
End Class
|
|
@ -15,7 +15,7 @@ Class BirthdayBot
|
||||||
Private ReadOnly _cmdsMods As ManagerCommands
|
Private ReadOnly _cmdsMods As ManagerCommands
|
||||||
|
|
||||||
Private WithEvents _client As DiscordSocketClient
|
Private WithEvents _client As DiscordSocketClient
|
||||||
Private ReadOnly _worker As BackgroundWorker
|
Private ReadOnly _worker As BackgroundServiceRunner
|
||||||
|
|
||||||
Friend ReadOnly Property Config As Configuration
|
Friend ReadOnly Property Config As Configuration
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ Class BirthdayBot
|
||||||
_client = dc
|
_client = dc
|
||||||
KnownGuilds = New Dictionary(Of ULong, GuildSettings)
|
KnownGuilds = New Dictionary(Of ULong, GuildSettings)
|
||||||
|
|
||||||
_worker = New BackgroundWorker(Me)
|
_worker = New BackgroundServiceRunner(Me)
|
||||||
|
|
||||||
' Command dispatch set-up
|
' Command dispatch set-up
|
||||||
_dispatchCommands = New Dictionary(Of String, CommandHandler)(StringComparer.InvariantCultureIgnoreCase)
|
_dispatchCommands = New Dictionary(Of String, CommandHandler)(StringComparer.InvariantCultureIgnoreCase)
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>BirthdayBot</RootNamespace>
|
<RootNamespace>BirthdayBot</RootNamespace>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
<Version>1.0.5</Version>
|
<Version>1.1.0</Version>
|
||||||
<AssemblyVersion>1.0.4.0</AssemblyVersion>
|
<AssemblyVersion>1.1.0.0</AssemblyVersion>
|
||||||
<Authors>Noiiko</Authors>
|
<Authors>Noiiko</Authors>
|
||||||
<Company />
|
<Company />
|
||||||
<Description>Discord bot for birthday reminders.</Description>
|
<Description>Discord bot for birthday reminders.</Description>
|
||||||
|
|
|
@ -30,4 +30,8 @@ Module Common
|
||||||
{1, "Jan"}, {2, "Feb"}, {3, "Mar"}, {4, "Apr"}, {5, "May"}, {6, "Jun"},
|
{1, "Jan"}, {2, "Feb"}, {3, "Mar"}, {4, "Apr"}, {5, "May"}, {6, "Jun"},
|
||||||
{7, "Jul"}, {8, "Aug"}, {9, "Sep"}, {10, "Oct"}, {11, "Nov"}, {12, "Dec"}
|
{7, "Jul"}, {8, "Aug"}, {9, "Sep"}, {10, "Oct"}, {11, "Nov"}, {12, "Dec"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Public Function BotUptime() As String
|
||||||
|
BotUptime = (DateTimeOffset.UtcNow - BotStartTime).ToString("d' days, 'hh':'mm':'ss")
|
||||||
|
End Function
|
||||||
End Module
|
End Module
|
||||||
|
|
|
@ -14,7 +14,9 @@ Module Program
|
||||||
End Set
|
End Set
|
||||||
End Property
|
End Property
|
||||||
|
|
||||||
Sub Main(args As String())
|
Sub Main()
|
||||||
|
Log("Birthday Bot", $"Version {System.Reflection.Assembly.GetExecutingAssembly().GetName.Version.ToString(3)} is starting.")
|
||||||
|
|
||||||
BotStartTime = DateTimeOffset.UtcNow
|
BotStartTime = DateTimeOffset.UtcNow
|
||||||
Dim cfg As New Configuration()
|
Dim cfg As New Configuration()
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ Friend Class HelpInfoCommands
|
||||||
})
|
})
|
||||||
embed.AddField(New EmbedFieldBuilder() With {
|
embed.AddField(New EmbedFieldBuilder() With {
|
||||||
.Name = "Examples",
|
.Name = "Examples",
|
||||||
.Value = String.Format(msghelp2, BackgroundWorker.DefaultAnnounce, BackgroundWorker.DefaultAnnouncePl)
|
.Value = String.Format(msghelp2, BirthdayRoleUpdate.DefaultAnnounce, BirthdayRoleUpdate.DefaultAnnouncePl)
|
||||||
})
|
})
|
||||||
Await reqChannel.SendMessageAsync(embed:=embed.Build())
|
Await reqChannel.SendMessageAsync(embed:=embed.Build())
|
||||||
End Function
|
End Function
|
||||||
|
@ -145,10 +145,9 @@ Friend Class HelpInfoCommands
|
||||||
' Bot status field
|
' Bot status field
|
||||||
Dim strStatus As New StringBuilder
|
Dim strStatus As New StringBuilder
|
||||||
Dim asmnm = Reflection.Assembly.GetExecutingAssembly.GetName()
|
Dim asmnm = Reflection.Assembly.GetExecutingAssembly.GetName()
|
||||||
strStatus.AppendLine("Birthday Bot version " + asmnm.Version.ToString(3))
|
strStatus.AppendLine("Birthday Bot v" + asmnm.Version.ToString(3))
|
||||||
strStatus.AppendLine("Server count: " + _discordClient.Guilds.Count.ToString())
|
strStatus.AppendLine("Server count: " + _discordClient.Guilds.Count.ToString())
|
||||||
strStatus.AppendLine("Uptime: " + (DateTimeOffset.UtcNow - Program.BotStartTime).ToString("d' days, 'hh':'mm':'ss"))
|
strStatus.AppendLine("Uptime: " + BotUptime())
|
||||||
strStatus.Append("More info will be shown here soon.")
|
|
||||||
|
|
||||||
' TODO fun stats
|
' TODO fun stats
|
||||||
' current birthdays, total names registered, unique time zones
|
' current birthdays, total names registered, unique time zones
|
||||||
|
|
Loading…
Reference in a new issue