Skip to content

Commit

Permalink
🛷 Split CLI into app & tool
Browse files Browse the repository at this point in the history
- App uses ASP.NET Core host.
- Tool does config management like before and will handle migration to db in the future.
- Drop all calls of Console.WriteLine in library in favor of logger.
  • Loading branch information
database64128 committed Apr 24, 2024
1 parent fa7c527 commit 4f69375
Show file tree
Hide file tree
Showing 42 changed files with 356 additions and 332 deletions.
13 changes: 13 additions & 0 deletions CubicBot.Telegram.App/CubicBot.Telegram.App.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<ItemGroup>
<ProjectReference Include="..\CubicBot.Telegram\CubicBot.Telegram.csproj" />
</ItemGroup>

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
9 changes: 9 additions & 0 deletions CubicBot.Telegram.App/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using CubicBot.Telegram;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHostedService<BotService>();

var app = builder.Build();

await app.RunAsync();
38 changes: 38 additions & 0 deletions CubicBot.Telegram.App/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:11932",
"sslPort": 44318
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5178",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7041;http://localhost:5178",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
8 changes: 8 additions & 0 deletions CubicBot.Telegram.App/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions CubicBot.Telegram.App/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
12 changes: 12 additions & 0 deletions CubicBot.Telegram.App/appsettings.systemd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Console": {
"FormatterName": "systemd"
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace CubicBot.Telegram.CLI;
namespace CubicBot.Telegram.Tool.CLI;

public static class ConfigCommand
{
Expand Down
18 changes: 18 additions & 0 deletions CubicBot.Telegram.Tool/CubicBot.Telegram.Tool.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\CubicBot.Telegram\CubicBot.Telegram.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.24209.3" />
</ItemGroup>

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
158 changes: 158 additions & 0 deletions CubicBot.Telegram.Tool/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System.CommandLine;
using System.Text;
using CubicBot.Telegram.Tool.CLI;

var botTokenOption = new CliOption<string?>("--bot-token")
{
Description = "Telegram bot token.",
};
var enableCommandsModuleOption = new CliOption<bool?>("--enable-commands-mod")
{
Description = "Whether to enable the commands module.",
};
var enableStatsModuleOption = new CliOption<bool?>("--enable-stats-mod")
{
Description = "Whether to enable the stats module.",
};

var enablePersonalCommandsOption = new CliOption<bool?>("--enable-personal-commands")
{
Description = "Whether to enable personal commands.",
};
var enableCommonCommandsOption = new CliOption<bool?>("--enable-common-commands")
{
Description = "Whether to enable common commands.",
};
var enableDiceCommandsOption = new CliOption<bool?>("--enable-dice-commands")
{
Description = "Whether to enable dice commands.",
};
var enableConsentNotNeededCommandsOption = new CliOption<bool?>("--enable-consent-not-needed-commands")
{
Description = "Whether to enable consent not needed commands.",
};
var enableNonVeganCommandsOption = new CliOption<bool?>("--enable-non-vegan-commands")
{
Description = "Whether to enable non-vegan commands.",
};
var enableLawEnforcementCommandsOption = new CliOption<bool?>("--enable-law-enforcement-commands")
{
Description = "Whether to enable law enforcement commands.",
};
var enablePublicServicesCommandsOption = new CliOption<bool?>("--enable-public-services-commands")
{
Description = "Whether to enable public services commands.",
};
var enableChineseCommandsOption = new CliOption<bool?>("--enable-chinese-commands")
{
Description = "Whether to enable Chinese commands.",
};
var enableChineseTasksCommandsOption = new CliOption<bool?>("--enable-chinese-tasks-commands")
{
Description = "Whether to enable Chinese tasks commands.",
};
var enableSystemdCommandsOption = new CliOption<bool?>("--enable-systemd-commands")
{
Description = "Whether to enable systemd commands.",
};

var enableGrassStatsOption = new CliOption<bool?>("--enable-grass-stats")
{
Description = "Whether to enable grass stats.",
};
var enableCommandStatsOption = new CliOption<bool?>("--enable-command-stats")
{
Description = "Whether to enable command stats.",
};
var enableMessageCounterOption = new CliOption<bool?>("--enable-message-counter")
{
Description = "Whether to enable message counter.",
};
var enableTwoTripleThreeOption = new CliOption<bool?>("--enable-two-triple-three")
{
Description = "Whether to enable two triple three (2333) counter.",
};
var enableParenthesisEnclosureOption = new CliOption<bool?>("--enable-parenthesis-enclosure")
{
Description = "Whether to enable parenthesis enclosure.",
};

var configGetCommand = new CliCommand("get", "Print config.");

var configSetCommand = new CliCommand("set", "Change config.")
{
botTokenOption,
enableCommandsModuleOption,
enableStatsModuleOption,
enablePersonalCommandsOption,
enableCommonCommandsOption,
enableDiceCommandsOption,
enableConsentNotNeededCommandsOption,
enableNonVeganCommandsOption,
enableLawEnforcementCommandsOption,
enablePublicServicesCommandsOption,
enableChineseCommandsOption,
enableChineseTasksCommandsOption,
enableSystemdCommandsOption,
enableGrassStatsOption,
enableCommandStatsOption,
enableMessageCounterOption,
enableParenthesisEnclosureOption,
};

configGetCommand.SetAction((_, cancellationToken) => ConfigCommand.GetAsync(cancellationToken));
configSetCommand.SetAction((parseResult, cancellationToken) =>
{
var botToken = parseResult.GetValue(botTokenOption);
var enableCommandsModule = parseResult.GetValue(enableCommandsModuleOption);
var enableStatsModule = parseResult.GetValue(enableStatsModuleOption);
var enablePersonalCommands = parseResult.GetValue(enablePersonalCommandsOption);
var enableCommonCommands = parseResult.GetValue(enableCommonCommandsOption);
var enableDiceCommands = parseResult.GetValue(enableDiceCommandsOption);
var enableConsentNotNeededCommands = parseResult.GetValue(enableConsentNotNeededCommandsOption);
var enableNonVeganCommands = parseResult.GetValue(enableNonVeganCommandsOption);
var enableLawEnforcementCommands = parseResult.GetValue(enableLawEnforcementCommandsOption);
var enablePublicServicesCommands = parseResult.GetValue(enablePublicServicesCommandsOption);
var enableChineseCommands = parseResult.GetValue(enableChineseCommandsOption);
var enableChineseTasksCommands = parseResult.GetValue(enableChineseTasksCommandsOption);
var enableSystemdCommands = parseResult.GetValue(enableSystemdCommandsOption);
var enableGrassStats = parseResult.GetValue(enableGrassStatsOption);
var enableCommandStats = parseResult.GetValue(enableCommandStatsOption);
var enableMessageCounter = parseResult.GetValue(enableMessageCounterOption);
var enableTwoTripleThree = parseResult.GetValue(enableTwoTripleThreeOption);
var enableParenthesisEnclosure = parseResult.GetValue(enableParenthesisEnclosureOption);
return ConfigCommand.SetAsync(
botToken,
enableCommandsModule,
enableStatsModule,
enablePersonalCommands,
enableCommonCommands,
enableDiceCommands,
enableConsentNotNeededCommands,
enableNonVeganCommands,
enableLawEnforcementCommands,
enablePublicServicesCommands,
enableChineseCommands,
enableChineseTasksCommands,
enableSystemdCommands,
enableGrassStats,
enableCommandStats,
enableMessageCounter,
enableTwoTripleThree,
enableParenthesisEnclosure,
cancellationToken);
});

var configCommand = new CliCommand("config", "Print or change config.")
{
configGetCommand,
configSetCommand,
};

var rootCommand = new CliRootCommand("A stupid and annoying chatbot for your group chats.")
{
configCommand,
};

Console.OutputEncoding = Encoding.UTF8;
return await rootCommand.Parse(args).InvokeAsync();
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Telegram.Bot;
using Telegram.Bot.Polling;

namespace CubicBot.Telegram.CLI;
namespace CubicBot.Telegram;

public static class BotRunner
public sealed class BotService(ILogger<BotService> logger) : IHostedService
{
public static async Task<int> RunBotAsync(string? botToken, CancellationToken cancellationToken = default)
private readonly CancellationTokenSource _cts = new();
private Task _botTask = Task.CompletedTask;

public Task StartAsync(CancellationToken _ = default)
{
_botTask = RunBotAsync(null, _cts.Token);
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken _ = default)
{
_cts.Cancel();
return _botTask;
}

public async Task<int> RunBotAsync(string? botToken, CancellationToken cancellationToken = default)
{
Config config;

Expand All @@ -19,7 +32,7 @@ public static async Task<int> RunBotAsync(string? botToken, CancellationToken ca
}
catch (Exception ex)
{
Console.WriteLine($"Failed to load config: {ex.Message}");
logger.LogCritical(ex, "Failed to load config");
return 1;
}

Expand All @@ -30,7 +43,7 @@ public static async Task<int> RunBotAsync(string? botToken, CancellationToken ca
botToken = config.BotToken;
if (string.IsNullOrEmpty(botToken))
{
Console.WriteLine("Please provide a bot token with command line option `--bot-token`, environment variable `TELEGRAM_BOT_TOKEN`, or in the config file.");
logger.LogCritical("Please provide a bot token with command line option `--bot-token`, environment variable `TELEGRAM_BOT_TOKEN`, or in the config file.");
return 1;
}

Expand All @@ -42,7 +55,7 @@ public static async Task<int> RunBotAsync(string? botToken, CancellationToken ca
}
catch (Exception ex)
{
Console.WriteLine($"Failed to load data: {ex.Message}");
logger.LogCritical(ex, "Failed to load data");
return 1;
}

Expand All @@ -53,32 +66,32 @@ public static async Task<int> RunBotAsync(string? botToken, CancellationToken ca
using var httpClient = new HttpClient();
var bot = new TelegramBotClient(botToken, httpClient);
var me = await bot.GetMeAsync(cancellationToken);
if (me.CanReadAllGroupMessages is not true)
config.EnableStats = false;

if (string.IsNullOrEmpty(me.Username))
throw new Exception("Bot username is null or empty.");

var updateHandler = new UpdateHandler(me.Username, config, data);
var updateHandler = new UpdateHandler(me.Username, config, data, logger);
await updateHandler.RegisterCommandsAsync(bot, cancellationToken);
Console.WriteLine($"Started Telegram bot: @{me.Username} ({me.Id}).");

var updateReceiver = new QueuedUpdateReceiver(bot, null, UpdateHandler.HandleErrorAsync);
logger.LogInformation("Started Telegram bot: @{BotUsername} ({BotId})", me.Username, me.Id);

var updateReceiver = new QueuedUpdateReceiver(bot, null, updateHandler.HandleErrorAsync);
await updateHandler.HandleUpdateStreamAsync(bot, updateReceiver, cancellationToken);
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
Console.WriteLine($"Failed to start Telegram bot: {ex.Message}");
logger.LogError(ex, "Failed to start Telegram bot");
return 1;
}

await saveDataTask;
return 0;
}

private static async Task SaveDataHourlyAsync(Data data, CancellationToken cancellationToken = default)
private async Task SaveDataHourlyAsync(Data data, CancellationToken cancellationToken = default)
{
while (!cancellationToken.IsCancellationRequested)
{
Expand All @@ -93,10 +106,11 @@ private static async Task SaveDataHourlyAsync(Data data, CancellationToken cance
try
{
await data.SaveAsync(CancellationToken.None);
logger.LogDebug("Saved data");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to save data: {ex.Message}");
logger.LogError(ex, "Failed to save data");
}
}
}
Expand Down
Loading

0 comments on commit 4f69375

Please sign in to comment.