Initial commit, working
This commit is contained in:
commit
795978c1e8
|
|
@ -0,0 +1,25 @@
|
|||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["SquadBot.csproj", "./"]
|
||||
RUN dotnet restore "SquadBot.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/"
|
||||
RUN dotnet build "./SquadBot.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "./SquadBot.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "SquadBot.dll"]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using NetCord.Gateway;
|
||||
using NetCord.Hosting.Gateway;
|
||||
using SquadBot.StateMangers;
|
||||
|
||||
namespace SquadBot.Handlers;
|
||||
|
||||
public class VoiceStatesHandler : IVoiceStateUpdateGatewayHandler
|
||||
{
|
||||
private ILogger _logger;
|
||||
private VoiceStateManager _voiceStateManager;
|
||||
public VoiceStatesHandler(ILogger<VoiceStatesHandler> Logger, VoiceStateManager vsManager)
|
||||
{
|
||||
_logger = Logger ?? throw new System.ArgumentNullException(nameof(Logger));
|
||||
_voiceStateManager = vsManager ?? throw new System.ArgumentNullException(nameof(vsManager));
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync(VoiceState voice_event)
|
||||
{
|
||||
if (voice_event.User == null) return;
|
||||
await _voiceStateManager.HandleVoiceStateChange(voice_event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using NetCord;
|
||||
using NetCord.Gateway;
|
||||
using NetCord.Hosting.Gateway;
|
||||
using NetCord.Hosting.Rest;
|
||||
using SquadBot.Handlers;
|
||||
using SquadBot.StateMangers;
|
||||
|
||||
namespace SquadBot;
|
||||
|
||||
public class Program
|
||||
{
|
||||
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var token = "";
|
||||
var pubkey = "";
|
||||
if (args.Length == 2)
|
||||
{
|
||||
token = args[0];
|
||||
pubkey = args[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine("Usage: squadbot <token> <pubkey>");
|
||||
}
|
||||
|
||||
var builder = Host.CreateApplicationBuilder(args);
|
||||
builder.Services.AddLogging();
|
||||
builder.Services.AddDiscordRest(options =>
|
||||
{
|
||||
options.PublicKey = pubkey;
|
||||
options.Token = token;
|
||||
});
|
||||
builder.Services.AddSingleton<VoiceStateManager>();
|
||||
builder.Services.AddSingleton<VoiceStatesHandler>();
|
||||
builder.Services.AddDiscordGateway(options =>
|
||||
{
|
||||
options.Intents = GatewayIntents.GuildMessages
|
||||
| GatewayIntents.GuildVoiceStates;
|
||||
options.Token = token;
|
||||
})
|
||||
.AddGatewayHandlers(typeof(Program).Assembly);
|
||||
|
||||
var host = builder.Build()
|
||||
.UseGatewayHandlers();
|
||||
await host.RunAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "todos",
|
||||
"applicationUrl": "http://localhost:13376",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
namespace SquadBot.Providers;
|
||||
|
||||
public static class PhraseProvider
|
||||
{
|
||||
private static Random rng = new Random();
|
||||
|
||||
private static List<string> phrases = new List<string>()
|
||||
{
|
||||
"there is a new yapper in the voice chat.",
|
||||
"someone is in the lobby, go irritate the shit out of them.",
|
||||
"voice chat: Because typing is so last century.",
|
||||
"come join the voice chat! If not we will talk about you.",
|
||||
"join the voice chat. It's the only way to prove you're not a bot.",
|
||||
"join the voice chat. We're not saying it'll be good, but it'll be something.",
|
||||
"who needs friends in real life? Someone is in the voice chat!",
|
||||
"someone is pretending to be productive in the voice chat.",
|
||||
"the memes are better dubbed",
|
||||
"voice chat's active. It's probably a disaster, but come anyway."
|
||||
};
|
||||
|
||||
public static string GetYapperPhrase()
|
||||
{
|
||||
return phrases[rng.Next(0, phrases.Count)];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<PublishAot>true</PublishAot>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetCord" Version="1.0.0-alpha.391" />
|
||||
<PackageReference Include="NetCord.Hosting" Version="1.0.0-alpha.391" />
|
||||
<PackageReference Include="NetCord.Hosting.AspNetCore" Version="1.0.0-alpha.391" />
|
||||
<PackageReference Include="NetCord.Hosting.Services" Version="1.0.0-alpha.391" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
@SquadBot_HostAddress = http://localhost:13376
|
||||
|
||||
GET {{SquadBot_HostAddress}}/todos/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
|
||||
GET {{SquadBot_HostAddress}}/todos/1
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SquadBot", "SquadBot.csproj", "{910F9D0B-51BD-4811-A2ED-DBD79BF02CCF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{910F9D0B-51BD-4811-A2ED-DBD79BF02CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{910F9D0B-51BD-4811-A2ED-DBD79BF02CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{910F9D0B-51BD-4811-A2ED-DBD79BF02CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{910F9D0B-51BD-4811-A2ED-DBD79BF02CCF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{910F9D0B-51BD-4811-A2ED-DBD79BF02CCF}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
using NetCord;
|
||||
using NetCord.Gateway;
|
||||
using NetCord.Hosting.Gateway;
|
||||
using NetCord.Rest;
|
||||
using SquadBot.Providers;
|
||||
|
||||
namespace SquadBot.StateMangers;
|
||||
|
||||
public class VoiceStateManager
|
||||
{
|
||||
// Key: GuildId Value: List of UserId for users in voice channel
|
||||
// TODO: We probably want to persist this somewhere else (Redis/Valkey)
|
||||
private Dictionary<ulong, ISet<ulong>> _guildVoiceStates;
|
||||
private Dictionary<ulong, DateTimeOffset> _yapperNotificationTimeouts;
|
||||
private RestClient _restClient;
|
||||
private ILogger<VoiceStateManager> _logger;
|
||||
|
||||
public VoiceStateManager(ILogger<VoiceStateManager> logger, RestClient restClient)
|
||||
{
|
||||
_guildVoiceStates = new Dictionary<ulong, ISet<ulong>>();
|
||||
_yapperNotificationTimeouts = new Dictionary<ulong, DateTimeOffset>();
|
||||
_restClient = restClient ?? throw new System.ArgumentNullException(nameof(restClient));
|
||||
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public async Task HandleVoiceStateChange(VoiceState voice_state)
|
||||
{
|
||||
if (voice_state.ChannelId is not null)
|
||||
{
|
||||
// Joining channel
|
||||
_logger.LogInformation($"New yapper detected: {voice_state.User.Username}");
|
||||
if (!_guildVoiceStates.TryGetValue(voice_state.GuildId, out var yappers) || yappers.Count < 0)
|
||||
{
|
||||
var channels = await _restClient.GetGuildChannelsAsync(voice_state.GuildId);
|
||||
var alertChannelId = channels.FirstOrDefault(channel => channel.Name == "bot-tinkering")?.Id;
|
||||
var guildRoles = await _restClient.GetGuildRolesAsync(voice_state.GuildId,
|
||||
new RestRequestProperties() { AuditLogReason = "Role lookup" });
|
||||
var yapperRoleId = guildRoles.FirstOrDefault(role => role.Name.ToLower() == "yapper")?.Id;
|
||||
if (alertChannelId is not null && yapperRoleId is not null && (!_yapperNotificationTimeouts.TryGetValue(voice_state.GuildId, out var timeout) || DateTimeOffset.UtcNow.CompareTo(timeout) > 0))
|
||||
{
|
||||
// Notify that new yapper has arrived
|
||||
await _restClient.SendMessageAsync(
|
||||
alertChannelId.GetValueOrDefault(),
|
||||
new MessageProperties()
|
||||
{
|
||||
AllowedMentions = new AllowedMentionsProperties() {AllowedRoles = [yapperRoleId.GetValueOrDefault()]},
|
||||
Content = $"<@&{yapperRoleId.GetValueOrDefault()}> " + PhraseProvider.GetYapperPhrase()
|
||||
});
|
||||
}
|
||||
|
||||
yappers = new HashSet<ulong>() { voice_state.UserId };
|
||||
}
|
||||
else
|
||||
{
|
||||
yappers = yappers.Append(voice_state.UserId).ToHashSet();
|
||||
}
|
||||
_guildVoiceStates[voice_state.GuildId] = yappers;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leaving channel
|
||||
_logger.LogInformation($"Yapper leaving: {voice_state.User.Username}");
|
||||
if (_guildVoiceStates.TryGetValue(voice_state.GuildId, out var yappers))
|
||||
{
|
||||
yappers.Remove(voice_state.UserId);
|
||||
_guildVoiceStates[voice_state.GuildId] = yappers;
|
||||
_yapperNotificationTimeouts[voice_state.GuildId] = DateTimeOffset.UtcNow.AddHours(2);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"Discord": {
|
||||
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "9.0.0",
|
||||
"rollForward": "latestMajor",
|
||||
"allowPrerelease": true
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue