ゲーム好きの人たちにはおなじみの Slack みたいなチャットサービスのボットを C# でも作れます。Python が一応公式っぽい??
C# で Discord のボットを作る場合には Discord.NET というライブラリを使うのが一般的みたいです。
簡単に検索しただけでもチラホラ日本語記事がヒットします。
Discord 側でのアプリの作成やボットのアカウントの作り方とか、特定のチャンネルにボットを追加する方法は上記のブログなどにしっかり書いてあるので、ここでは Azure にデプロイしてみたいと思います。
今回は .NET Core にある汎用ホストで作っていきます。
.NET Core のコンソールアプリを作成して、Microsoft.Extensions.Hosting
と Discord.Net
と Microsoft.Extensions.Logging.Console
という NuGet パッケージを追加します。
あとは淡々と書いていきます。
using Discord.WebSocket; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; namespace DiscordBot.HostApp { class Program { static void Main(string[] args) => ConfigureHostBuider(args).Build().Run(); public static IHostBuilder ConfigureHostBuider(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging(b => { b.AddConsole(); }) .ConfigureServices((hostContext, services) => { services.AddHostedService<DiscordBotService>(); }); } class DiscordBotService : BackgroundService { private DiscordSocketClient _client; private readonly IConfiguration _configuration; private string Token => _configuration.GetValue<string>("Token"); public DiscordBotService(IConfiguration configuration) { _configuration = configuration; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _client = new DiscordSocketClient(new DiscordSocketConfig { LogLevel = Discord.LogSeverity.Info }); _client.Log += x => { Console.WriteLine($"{x.Message}, {x.Exception}"); return Task.CompletedTask; }; _client.MessageReceived += MessageReceived; await _client.LoginAsync(Discord.TokenType.Bot, Token); await _client.StartAsync(); } public override async Task StopAsync(CancellationToken cancellationToken) { await _client.StopAsync(); } private async Task MessageReceived(SocketMessage arg) { if (!(arg is SocketUserMessage m) || m.Author.IsBot) { return; } await m.Channel.SendMessageAsync($"{m.Content} と言いましたね。"); } }; }
プロジェクトには appsettings.json と appsettings.Development.json を追加します。
appsettings.json と appsettings.Development.json は ASP.NET Core の Web アプリケーションプロジェクトから持ってきました。Development の方には以下のように Token を足しています。ここに Discord でとってきたトークンを入れます。
{ "Logging": { "LogLevel": { "Default": "Debug", "System": "Information", "Grpc": "Information", "Microsoft": "Information" } }, "Token": "<ここにトークンを入れる>" }
これはプログラム中で以下のように Token という名前で設定を呼んでるから Token という名前で追加してるだけで、プログラムとあってれば任意の名前で大丈夫です。git を使う場合は、この appsettings.Development.json を .gitignore
に追加しておきましょう。
次にプロジェクトのプロパティで環境変数 DOTNET_ENVIRONMENT
に Development
を追加します。これでローカルでのデバッグ実行時に appsettings.Development.json を見に行ってくれるようになります。
実行するとなんか受付に対してレディになってますね。
Discord を見てみるとボットがオンラインになってるので話しかけてみました。ちゃんと動いてます。
Azure にデプロイ
では、今回はこの汎用ホストを WebJob にデプロイしてみようと思います。とりあえず Web App を作ります。Discord のボットは常駐してないと死んじゃうのでスタンダードプラン(S1)以上で作ります。
そして、作成された App Service (Web App) の構成ページで新しいアプリケーション設定として Token を追加して Discord のボットのトークンを入れます。ローカルのデバッグ実行は appsettings.Development.json から読み込んで、本番はここから環境変数として読み込む感じです。ここら辺をいい感じに IConfiguration に隠してくれるの便利ですよね。
本番で使うものは何かしらの CI/CD 系のサービスからデプロイするとして、今回のお試しはローカルの Visual Studio のプロジェクトの右クリックメニューから公開で WebJobs に公開していきます。
先ほど作ったのが選択肢に出てくるので選びます。
プロファイルが出来たら編集を押して Web ジョブの種類を Continuous にします。これで常時実行し続けます。
では発行しましょう。発行が終わると、そのうち Discord のほうでボットがオンラインになります。
ログぅ…
ダメ元で AddConsole メソッドを呼んでますが、WebJobs に置いただけでは Application Insights にはログはいてくれませんね。
なので Microsoft.Extensions.Logging.ApplicationInsights
を NuGet で追加して。ConfigureHostBuilder メソッドを以下のように書き換えます。
public static IHostBuilder ConfigureHostBuider(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging((ctx, b) => { b.ClearProviders(); if (ctx.HostingEnvironment.IsProduction()) { b.AddApplicationInsights(ctx.Configuration.GetValue<string>("APPINSIGHTS_INSTRUMENTATIONKEY")); } else { b.AddConsole(); } }) .ConfigureServices((hostContext, services) => { services.AddHostedService<DiscordBotService>(); });
こんな感じで変更して Azure に差異デプロイして、こんな風に話しかけると
こんな感じに Application Insights にもログが出るようになりました。
ソースコード
とりあえずそのまま GitHub に上げてます。