Add sharding support

This commit is contained in:
Noikoio 2019-09-06 18:07:03 -07:00
parent a88f666cc8
commit d06afbd510
7 changed files with 43 additions and 27 deletions

View file

@ -15,11 +15,14 @@ Class Heartbeat
Log($"Tick {tick:00000} - Bot uptime: {BotUptime()}") Log($"Tick {tick:00000} - Bot uptime: {BotUptime()}")
End If End If
If (BotInstance.DiscordClient.ConnectionState = Discord.ConnectionState.Disconnected) Then ' Disconnection warn
Log("Client is disconnected! Restart the app if this persists.") For Each shard In BotInstance.DiscordClient.Shards
' The library alone cannot be restarted as it is in an unknown state. It was not designed to be restarted. If shard.ConnectionState = Discord.ConnectionState.Disconnected Then
' This is the part where we'd signal something to restart us if we were fancy. Log($"Shard {shard.ShardId} is disconnected! Restart the app if this persists.")
End If ' The library alone cannot be restarted as it is in an unknown state. It was not designed to be restarted.
' This is the part where we'd signal something to restart us if we were fancy.
End If
Next
Return Task.CompletedTask Return Task.CompletedTask
End Function End Function

View file

@ -15,22 +15,22 @@ Class BirthdayBot
Private ReadOnly _cmdsHelp As HelpInfoCommands Private ReadOnly _cmdsHelp As HelpInfoCommands
Private ReadOnly _cmdsMods As ManagerCommands Private ReadOnly _cmdsMods As ManagerCommands
Private WithEvents _client As DiscordSocketClient Private WithEvents Client As DiscordShardedClient
Private ReadOnly _worker As BackgroundServiceRunner Private ReadOnly _worker As BackgroundServiceRunner
Friend ReadOnly Property Config As Configuration Friend ReadOnly Property Config As Configuration
Friend ReadOnly Property DiscordClient As DiscordSocketClient Friend ReadOnly Property DiscordClient As DiscordShardedClient
Get Get
Return _client Return Client
End Get End Get
End Property End Property
Friend ReadOnly Property GuildCache As ConcurrentDictionary(Of ULong, GuildStateInformation) Friend ReadOnly Property GuildCache As ConcurrentDictionary(Of ULong, GuildStateInformation)
Public Sub New(conf As Configuration, dc As DiscordSocketClient) Public Sub New(conf As Configuration, dc As DiscordShardedClient)
Config = conf Config = conf
_client = dc Client = dc
GuildCache = New ConcurrentDictionary(Of ULong, GuildStateInformation) GuildCache = New ConcurrentDictionary(Of ULong, GuildStateInformation)
_worker = New BackgroundServiceRunner(Me) _worker = New BackgroundServiceRunner(Me)
@ -56,8 +56,8 @@ Class BirthdayBot
End Sub End Sub
Public Async Function Start() As Task Public Async Function Start() As Task
Await _client.LoginAsync(TokenType.Bot, Config.BotToken) Await Client.LoginAsync(TokenType.Bot, Config.BotToken)
Await _client.StartAsync() Await Client.StartAsync()
_worker.Start() _worker.Start()
Await Task.Delay(-1) Await Task.Delay(-1)
@ -68,28 +68,28 @@ Class BirthdayBot
''' </summary> ''' </summary>
Public Async Function Shutdown() As Task Public Async Function Shutdown() As Task
Await _worker.Cancel() Await _worker.Cancel()
Await _client.LogoutAsync() Await Client.LogoutAsync()
_client.Dispose() Client.Dispose()
End Function End Function
Private Async Function LoadGuild(g As SocketGuild) As Task Handles _client.JoinedGuild, _client.GuildAvailable Private Async Function LoadGuild(g As SocketGuild) As Task Handles Client.JoinedGuild, Client.GuildAvailable
If Not GuildCache.ContainsKey(g.Id) Then If Not GuildCache.ContainsKey(g.Id) Then
Dim gi = Await GuildStateInformation.LoadSettingsAsync(Config.DatabaseSettings, g.Id) Dim gi = Await GuildStateInformation.LoadSettingsAsync(Config.DatabaseSettings, g.Id)
GuildCache.TryAdd(g.Id, gi) GuildCache.TryAdd(g.Id, gi)
End If End If
End Function End Function
Private Function DiscardGuild(g As SocketGuild) As Task Handles _client.LeftGuild Private Function DiscardGuild(g As SocketGuild) As Task Handles Client.LeftGuild
Dim rm As GuildStateInformation = Nothing Dim rm As GuildStateInformation = Nothing
GuildCache.TryRemove(g.Id, rm) GuildCache.TryRemove(g.Id, rm)
Return Task.CompletedTask Return Task.CompletedTask
End Function End Function
Private Async Function SetStatus() As Task Handles _client.Connected Private Async Function SetStatus() As Task Handles Client.ShardConnected
Await _client.SetGameAsync(CommandPrefix + "help") Await Client.SetGameAsync(CommandPrefix + "help")
End Function End Function
Private Async Function Dispatch(msg As SocketMessage) As Task Handles _client.MessageReceived Private Async Function Dispatch(msg As SocketMessage) As Task Handles Client.MessageReceived
If TypeOf msg.Channel Is IDMChannel Then Return If TypeOf msg.Channel Is IDMChannel Then Return
If msg.Author.IsBot Then Return If msg.Author.IsBot Then Return

View file

@ -4,7 +4,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>BirthdayBot</RootNamespace> <RootNamespace>BirthdayBot</RootNamespace>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<Version>1.2.0</Version> <Version>1.3.0</Version>
<Authors>Noiiko</Authors> <Authors>Noiiko</Authors>
<Company /> <Company />
<Description>Discord bot for birthday reminders.</Description> <Description>Discord bot for birthday reminders.</Description>

View file

@ -10,6 +10,8 @@ Class Configuration
Public ReadOnly Property DBotsToken As String Public ReadOnly Property DBotsToken As String
Public ReadOnly Property DatabaseSettings As Database Public ReadOnly Property DatabaseSettings As Database
Public ReadOnly Property ShardCount As Integer
Sub New() Sub New()
' Looks for settings.json in the executable directory. ' Looks for settings.json in the executable directory.
Dim confPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) Dim confPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
@ -38,5 +40,15 @@ Class Configuration
Throw New Exception("'SqlConnectionString' must be specified.") Throw New Exception("'SqlConnectionString' must be specified.")
End If End If
DatabaseSettings = New Database(sqlcs) DatabaseSettings = New Database(sqlcs)
Dim sc? = jc("ShardCount")?.Value(Of Integer)()
If Not sc.HasValue Then
ShardCount = 1
Else
ShardCount = sc.Value
If ShardCount <= 0 Then
Throw New Exception("'ShardCount' must be a positive integer.")
End If
End If
End Sub End Sub
End Class End Class

View file

@ -25,9 +25,11 @@ Module Program
.AlwaysDownloadUsers = True .AlwaysDownloadUsers = True
.DefaultRetryMode = Discord.RetryMode.RetryRatelimit .DefaultRetryMode = Discord.RetryMode.RetryRatelimit
.MessageCacheSize = 0 .MessageCacheSize = 0
.TotalShards = cfg.ShardCount
.ExclusiveBulkDelete = True
End With End With
Dim client As New DiscordSocketClient(dc) Dim client As New DiscordShardedClient(dc)
AddHandler client.Log, AddressOf DNetLog AddHandler client.Log, AddressOf DNetLog
_bot = New BirthdayBot(cfg, client) _bot = New BirthdayBot(cfg, client)
@ -50,6 +52,7 @@ Module Program
End Sub End Sub
Private Function DNetLog(arg As LogMessage) As Task Private Function DNetLog(arg As LogMessage) As Task
If arg.Severity <= LogSeverity.Info Then If arg.Severity <= LogSeverity.Info Then
Log("Discord.Net", $"{arg.Severity}: {arg.Message}") Log("Discord.Net", $"{arg.Severity}: {arg.Message}")
End If End If

View file

@ -38,7 +38,7 @@ Friend MustInherit Class CommandsCommon
Protected ReadOnly Instance As BirthdayBot Protected ReadOnly Instance As BirthdayBot
Protected ReadOnly BotConfig As Configuration Protected ReadOnly BotConfig As Configuration
Protected ReadOnly Discord As DiscordSocketClient Protected ReadOnly Discord As DiscordShardedClient
Sub New(inst As BirthdayBot, db As Configuration) Sub New(inst As BirthdayBot, db As Configuration)
Instance = inst Instance = inst

View file

@ -7,11 +7,9 @@ Friend Class HelpInfoCommands
Private ReadOnly _helpEmbed As Embed Private ReadOnly _helpEmbed As Embed
Private ReadOnly _helpConfigEmbed As Embed Private ReadOnly _helpConfigEmbed As Embed
Private ReadOnly _discordClient As DiscordSocketClient
Sub New(inst As BirthdayBot, db As Configuration, client As DiscordSocketClient) Sub New(inst As BirthdayBot, db As Configuration, client As DiscordShardedClient)
MyBase.New(inst, db) MyBase.New(inst, db)
_discordClient = client
Dim embeds = BuildHelpEmbeds() Dim embeds = BuildHelpEmbeds()
_helpEmbed = embeds.Item1 _helpEmbed = embeds.Item1
_helpConfigEmbed = embeds.Item2 _helpConfigEmbed = embeds.Item2
@ -146,7 +144,7 @@ Friend Class HelpInfoCommands
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 v" + 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: " + Discord.Guilds.Count.ToString())
strStatus.AppendLine("Uptime: " + BotUptime()) strStatus.AppendLine("Uptime: " + BotUptime())
' TODO fun stats ' TODO fun stats
@ -155,7 +153,7 @@ Friend Class HelpInfoCommands
Dim embed As New EmbedBuilder With { Dim embed As New EmbedBuilder With {
.Author = New EmbedAuthorBuilder() With { .Author = New EmbedAuthorBuilder() With {
.Name = "Thank you for using Birthday Bot!", .Name = "Thank you for using Birthday Bot!",
.IconUrl = _discordClient.CurrentUser.GetAvatarUrl() .IconUrl = Discord.CurrentUser.GetAvatarUrl()
}, },
.Description = "Suggestions and feedback are always welcome. Please refer to the listing on Discord Bots " + .Description = "Suggestions and feedback are always welcome. Please refer to the listing on Discord Bots " +
"(discord.bots.gg) for information on reaching my personal server. I may not be available often, but I am happy to " + "(discord.bots.gg) for information on reaching my personal server. I may not be available often, but I am happy to " +