65.9K
CodeProject 正在变化。 阅读更多。
Home

使用微服务在 Azure 中构建 Discord 机器人

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2019年8月27日

CPOL

9分钟阅读

viewsIcon

13092

在接下来的几篇文章中,我将介绍如何使用微服务架构设计和构建 Discord 机器人应用程序,并在 Azure 中实现各种服务。

引言

这是关于使用 Discord.Net 库构建 Discord 机器人的系列文章中的第一篇,最初发布在我的博客/网站上。该机器人的当前版本可以在此处的 GitHub 项目找到,后续文章将更新此存储库。

使用微服务架构构建服务具有许多优势,特别是与云提供商可以提供的无服务器选项结合使用时。这种组合使您能够构建各种小型服务,成本非常低,但可以几乎毫不费力地进行扩展,并能很好地处理突发性流量。在接下来的几篇文章中,我将介绍如何使用 Azure 中的各种服务设计和构建微服务应用程序。我将创建的应用程序是为了帮助更深入地了解这个聊天机器人,用于实时聊天应用程序 Discord,并集成了一些服务来提供基本功能。这与其他许多微服务应用程序示例有所不同,因为 Discord 机器人使用 Webhook 来建立一个会话,该会话接收连续的消息流。

**注意**: 我假设您过去已经了解过 Discord 机器人,对其有所了解,甚至可能已经创建了一个 Discord 应用程序。如果您还没有,我建议您快速查看此设置应用程序的指南,然后先阅读一些Discord 文档

话不多说,让我们来看看我们在这里要实现的最初的整体架构。

我们将构建的第一个组件是 Discord 机器人代理,使用 Discord .Net 库将消息代理到存储队列以供以后处理。这减轻了前端机器人在高负载情况下处理队列的压力。一旦消息进入消息队列,我们就可以使用函数按需监视、拆分和处理单个消息。接下来,我们可以获取这些消息并对它们执行内部和外部操作,例如将它们持久化到数据库或表存储、使用机器学习工具、访问 CDN 内容、调用外部 API 等等。

让我们从本篇文章开始创建 Discord 机器人代理。

步骤 1 - 创建项目

我们将使用 Dot Net Core 控制台应用程序来创建基本的 Discord 机器人代理。这将使我们能够创建一个精简的应用程序,我们可以用最少的资源在 Web 服务上运行它。

启动 Visual Studio 2019(我使用的是社区版)并创建一个新的控制台应用程序(.NET Core)应用程序。这将启动一个相当基本的控制台应用程序,里面没有任何内容。虽然不激动人心,但控制台应用程序允许您创建一个不包含任何我们不需要的额外组件的包。

步骤 2 - 添加依赖项

>

首先,让我们向控制台应用程序添加几个我们将在此应用程序中使用的包。双击项目文件,确保它包含以下包/代码:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <LangVersion>latest</LangVersion>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Discord.Net" Version="2.0.1" />
    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine"
                               Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables"
                               Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="**\*.json" Exclude="bin\**\*;obj\**\*" 
     CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

  <ItemGroup>
    <None Remove="Config\appsettings.Development.json" />
    <None Remove="Config\appsettings.json" />
    <None Remove="Config\appsettings.Production.json" />
    <None Remove="Config\hostsettings.json" />
  </ItemGroup>
  
</Project>

具体来说,我们将把以下四个组件添加到我们的控制台应用程序中:

  • Discord.Net - 这提供了连接和访问 Discord 服务器的 SDK。
  • 配置扩展 - 这提供了一个配置提供程序,用于在代码外部配置应用程序。
  • 托管扩展 - 这允许我们优雅地启动和停止服务,并在启动和停止时提供设置的任务。
  • 日志记录扩展 - 这允许我们使用不同的调试级别记录事件,以帮助捕获和排除故障。

在这些包引用声明之后,我们还有两组内容,它们告诉 Visual Studio 将 JSON 配置文件复制到输出目录,并防止删除一些非常特定的配置文件。您可以在 dot net core 文档的配置基础知识页面上阅读更多关于此的信息。

步骤 3 - 配置日志记录和配置

现在我们已经添加了依赖项,让我们编写基本的配置和日志记录系统。首先,通过更改程序中 Main 方法的签名,使我们的程序异步化:

public static async Task Main(string[] args)

接下来,我们创建一个新的主机构建器,并使用以下代码将配置系统注入到主机和应用程序中:

.ConfigureHostConfiguration(configHost =>
{
    configHost.SetBasePath(Directory.GetCurrentDirectory());
    configHost.AddJsonFile("Config/hostsettings.json", optional: true);
    configHost.AddEnvironmentVariables(prefix: "BOT_");
    configHost.AddCommandLine(args);
})
.ConfigureAppConfiguration((hostContext, configApp) =>
{
    configApp.AddJsonFile("Config/appsettings.json", optional: true);
    configApp.AddJsonFile(
        $"Config/appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json",
        optional: true);
    configApp.AddEnvironmentVariables(prefix: "BOT_");
    configApp.AddCommandLine(args);
})

这段代码首先通过使用Config目录中的hostsettings.json文件注入一种控制主机级别应用程序配置的方式,使用带有 BOT_ 前缀的环境变量检索配置设置,最后使用通过命令行传递的任何命令。其次,这段代码然后通过使用Config目录中的appsettings.jsonappsettings..json文件来注入一种控制应用程序级别应用程序配置的方式,使用带有 BOT_ 前缀的环境变量检索配置设置,最后使用通过命令行传递的任何命令。

接下来,我们添加日志记录,它可以利用我们的配置系统来指定日志级别,使用以下代码:

.ConfigureLogging((hostContext, configLogging) =>
{
    configLogging.AddConfiguration(hostContext.Configuration.GetSection("Logging"));
    configLogging.AddConsole();
    configLogging.AddDebug();
})

最后,我们通过构建主机并异步运行类来结束程序类。现在运行我们的程序,我们应该会看到以下控制台输出:

很无聊,对吧?您会注意到该应用程序还认为它处于生产托管环境中,所以让我们向项目中添加一些config文件,以便我们可以更好地控制应用程序。

首先,在项目根目录下创建一个Config文件夹,然后添加一个名为appsettings.json的新 JSON 文件。此文件应包含以下代码,并设置应用程序的默认值:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

接下来,创建另外两个 JSON 文件,appsettings.Development.jsonappsettings.Production.json,用于保存开发环境和生产环境的设置。这两个文件将设置应用程序的日志记录选项。appsettings.Development.json如下所示:

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

这为开发设置了日志记录,您希望获得更多信息。对于生产环境,可以根据需要将其更改为警告、错误或关键。我们可以设置环境的方法有很多,目前最简单的方法是创建一个hostsettings.json文件,并添加环境:Development 的键值对。

如果我们运行控制台应用程序,现在会看到环境设置为 Development,这是我们在此阶段想要的结果。

步骤 4 - 添加 Discord Socket 服务

现在我们已经设置了基本环境、配置和日志记录系统,让我们创建核心 Discord Socket 服务,它将连接到 Discord 服务器并捕获机器人加入的服务器的事件。

添加一个名为 DiscordSocketService 的新类。此类将是 Discord 和我们的机器人应用程序之间的主要接口。要在后台运行此类,它需要实现 IHostedService 接口。此接口有两个需要实现的方法:StartAsyncStopAsync。目前将 StopAsync 方法留空,因为我们此时不需要进行任何清理。

首先,我们将声明几个将被注入到服务中的本地变量:

  • 一个 ILogger 变量,用于记录不同的消息。
  • 一个 IApplicationLifetime 变量,用于控制启动和停止服务组件。

其次,让我们创建类构造函数,它将注入日志记录器和应用程序生命周期服务。最后,我们创建并注册三个函数,分别用于应用程序启动、停止以及最终完成。对于这些函数中的每一个,使用 _logger.LogInformation("<MESSGAE>"); 格式添加一个日志消息。例如,在 OnStarted 方法中,我们可能会有一个信息消息,说明 OnMessage 已启动。

要开始使用此服务,我们需要在主程序中使用 HostBuilder 中的 .ConfigureServices 函数将其注册。

现在,当我们运行服务时,应该会在控制台中看到日志消息。通过连接基本服务命令,让我们扩展它以实际连接到 Discord。

让我们扩展类构造函数以注入配置服务,我们将从配置文件中提取 Discord 机器人令牌。此机器人令牌是从 Discord 网站生成的,需要使用键值对 "DISCORD_BOT_TOKEN": "<YOURTOKEN>" 添加到 hostsettings 中。

现在,将以下代码添加到 OnStarted 函数中:

Discord.LogSeverity logLevel = LogSeverity.Info;

if (_config["LOGLEVEL"] == "DEBUG")
    logLevel = LogSeverity.Debug;
else if (_config["LOGLEVEL"] == "WARNING")
    logLevel = LogSeverity.Warning;
else if (_config["LOGLEVEL"] == "ERROR")
    logLevel = LogSeverity.Error;

// Setup the Discord Client Configuration
discordClient = new DiscordShardedClient(new DiscordSocketConfig
{
    LogLevel = logLevel
});

ConfigureEventHandlers();

discordClient.LoginAsync(Discord.TokenType.Bot, botToken).Wait();
discordClient.StartAsync().Wait();

大部分代码用于设置日志记录,以便我们可以看到正在发生的事情。最后四行是最重要的。首先,我们创建一个新的分片 Discord 客户端。虽然直到您的机器人加入大量服务器之前,这并不是非常重要,但从一开始配置它并没有太大区别。接下来,ConfigureEventHandlers 函数将是一个 private 函数,它将注册机器人可以监听的所有不同的 Discord 事件。我们将在稍后配置该函数。最后两行是登录机器人,然后启动客户端处理。在转到 ConfigureEventHandlers 函数之前,让我们还将 discordClient.LogoutAsync(); 行添加到 OnStopping 函数中。这将在应用程序结束时干净地注销 Discord 客户端。

ConfigureEventHandlers 函数是我们添加机器人连接到的 Discord 服务器触发的所有不同事件的所有处理程序的地方。在示例代码中,我已经创建并连接了大多数这些事件处理程序,但让我们看一下最常用的一个,看看它的模式是什么样的:

discordClient.MessageReceived += async m => await RecieveMessage(m);

这段代码基本上允许您将一个函数添加到特定的 Discord 事件委托中,以便您的机器人可以处理事件,在这种情况下,每当 Discord 用户发送消息时。对于示例代码,我添加了一些虚拟代码,允许机器人用 !pong 响应 Discord 中的 !ping 命令。应用程序启动并连接后,机器人将从此响应中做出响应。

摘要

所以这是一个基本的 Discord 机器人,它实现了 Dot Net Core 在配置、日志记录和后台服务方面的一些推荐模式。如果我们真的想这样做,我们可以直接将我们的机器人代码添加到这里,但就我而言,下一阶段将是连接大多数这些事件到 Azure 存储队列。希望下次您能与我一起参与下一部分。

附加信息

同样,您可以在此处的 GitHub 项目中找到此机器人的示例代码。这可能是一种简单的方式,让您以相当简单的方式开始和扩展 Discord 机器人,只需获取一个令牌,将其添加到 hostsettings.json 文件中,然后将您的机器人添加到服务器。如果您想这样做,请随意操作,我很乐意听到您是否已将其用于您的机器人。

历史

  • 2019 年 8 月 27 日:初始版本
© . All rights reserved.