-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add initial bootstrapping for voice server interception
- Loading branch information
1 parent
1046709
commit 72de0c5
Showing
8 changed files
with
229 additions
and
4 deletions.
There are no files selected for viewing
17 changes: 17 additions & 0 deletions
17
experiments/Lavalink4NET.Experiments.Receive/Extensions/ServiceCollectionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace Lavalink4NET.Experiments.Receive.Extensions; | ||
|
||
using Lavalink4NET.Players; | ||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
|
||
public static class ServiceCollectionExtensions | ||
{ | ||
public static IServiceCollection AddLavalinkReceive(this IServiceCollection services) | ||
{ | ||
ArgumentNullException.ThrowIfNull(services); | ||
|
||
services.TryAddSingleton<IVoiceServerSessionManager, VoiceServerSessionManager>(); | ||
services.Replace(ServiceDescriptor.Singleton<ILavalinkVoiceServerInterceptor, LavalinkReceiveVoiceServerInterceptor>()); | ||
|
||
return services; | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
experiments/Lavalink4NET.Experiments.Receive/IVoiceServerSessionManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Lavalink4NET.Experiments.Receive; | ||
|
||
using Lavalink4NET.Clients; | ||
|
||
interface IVoiceServerSessionManager | ||
{ | ||
Guid Allocate(ulong guildId, VoiceServer voiceServer); | ||
|
||
bool TryResolve(Guid sessionId, out ulong guildId, out VoiceServer voiceServer); | ||
} |
14 changes: 14 additions & 0 deletions
14
experiments/Lavalink4NET.Experiments.Receive/Lavalink4NET.Experiments.Receive.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Lavalink4NET\Lavalink4NET.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
40 changes: 40 additions & 0 deletions
40
experiments/Lavalink4NET.Experiments.Receive/LavalinkReceiveVoiceServerInterceptor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
namespace Lavalink4NET.Experiments.Receive; | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Lavalink4NET.Clients; | ||
using Lavalink4NET.Players; | ||
|
||
internal sealed class LavalinkReceiveVoiceServerInterceptor : ILavalinkVoiceServerInterceptor | ||
{ | ||
private readonly IVoiceServerSessionManager _sessionManager; | ||
private readonly ILogger<LavalinkReceiveVoiceServerInterceptor> _logger; | ||
|
||
public LavalinkReceiveVoiceServerInterceptor( | ||
IVoiceServerSessionManager sessionManager, | ||
ILogger<LavalinkReceiveVoiceServerInterceptor> logger) | ||
{ | ||
ArgumentNullException.ThrowIfNull(sessionManager); | ||
ArgumentNullException.ThrowIfNull(logger); | ||
|
||
_sessionManager = sessionManager; | ||
_logger = logger; | ||
} | ||
|
||
public ValueTask<VoiceServer> InterceptAsync( | ||
ulong guildId, | ||
VoiceServer voiceServer, | ||
CancellationToken cancellationToken = default) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
var sessionToken = _sessionManager.Allocate(guildId, voiceServer); | ||
var proxiedVoiceServer = new VoiceServer(sessionToken.ToString("N"), "localhost:16389"); | ||
|
||
_logger.LogInformation( | ||
"Mapping voice server '{OriginalEndpoint}' ({OriginalToken}) to '{ProxiedEndpoint}' ({ProxiedToken})", | ||
voiceServer.Endpoint, voiceServer.Token, proxiedVoiceServer.Endpoint, proxiedVoiceServer.Token); | ||
|
||
return new ValueTask<VoiceServer>(proxiedVoiceServer); | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
experiments/Lavalink4NET.Experiments.Receive/LavalinkVoiceServer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
namespace Lavalink4NET.Experiments.Receive; | ||
|
||
using Microsoft.AspNetCore.Hosting.Server; | ||
using Microsoft.AspNetCore.Http.Features; | ||
using Microsoft.AspNetCore.Server.Kestrel.Core; | ||
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; | ||
using Microsoft.AspNetCore.WebSockets; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.Net.Http.Headers; | ||
|
||
internal sealed class LavalinkVoiceServer : IHttpApplication<HttpContext> | ||
{ | ||
private readonly IVoiceServerSessionManager _serverSessionManager; | ||
private readonly KestrelServer _kestrelServer; | ||
private readonly WebSocketMiddleware _webSocketMiddleware; | ||
|
||
public LavalinkVoiceServer( | ||
IVoiceServerSessionManager serverSessionManager, | ||
ILoggerFactory loggerFactory) | ||
{ | ||
ArgumentNullException.ThrowIfNull(serverSessionManager); | ||
|
||
_serverSessionManager = serverSessionManager; | ||
|
||
var kestrelServerOptions = new KestrelServerOptions { AddServerHeader = false, }; | ||
kestrelServerOptions.ListenLocalhost(16389); | ||
|
||
var socketTransportOptions = new SocketTransportOptions { Backlog = 4, }; | ||
var socketTransportFactory = new SocketTransportFactory(Options.Create(socketTransportOptions), loggerFactory); | ||
|
||
_kestrelServer = new KestrelServer( | ||
options: Options.Create(kestrelServerOptions), | ||
transportFactory: socketTransportFactory, | ||
loggerFactory: loggerFactory); | ||
|
||
var webSocketOptions = new WebSocketOptions { }; | ||
|
||
_webSocketMiddleware = new WebSocketMiddleware( | ||
next: ProcessRequestInternalAsync, | ||
options: Options.Create(webSocketOptions), | ||
loggerFactory: loggerFactory); | ||
} | ||
|
||
public async ValueTask StartAsync(CancellationToken cancellationToken = default) | ||
{ | ||
await _kestrelServer | ||
.StartAsync(this, cancellationToken) | ||
.ConfigureAwait(false); | ||
} | ||
|
||
public async ValueTask StopAsync(CancellationToken cancellationToken = default) | ||
{ | ||
await _kestrelServer | ||
.StopAsync(cancellationToken) | ||
.ConfigureAwait(false); | ||
} | ||
|
||
HttpContext IHttpApplication<HttpContext>.CreateContext(IFeatureCollection contextFeatures) | ||
{ | ||
ArgumentNullException.ThrowIfNull(contextFeatures); | ||
|
||
return new DefaultHttpContext(contextFeatures); | ||
} | ||
|
||
void IHttpApplication<HttpContext>.DisposeContext(HttpContext context, Exception? exception) | ||
{ | ||
} | ||
|
||
Task IHttpApplication<HttpContext>.ProcessRequestAsync(HttpContext context) | ||
{ | ||
ArgumentNullException.ThrowIfNull(context); | ||
|
||
return _webSocketMiddleware.Invoke(context); | ||
} | ||
|
||
private async Task ProcessRequestInternalAsync(HttpContext httpContext) | ||
{ | ||
ArgumentNullException.ThrowIfNull(httpContext); | ||
|
||
var cancellationToken = httpContext.RequestAborted; | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
if (!httpContext.WebSockets.IsWebSocketRequest) | ||
{ | ||
httpContext.Response.StatusCode = StatusCodes.Status426UpgradeRequired; | ||
httpContext.Response.Headers[HeaderNames.Upgrade] = "websocket"; | ||
httpContext.Response.Headers[HeaderNames.Connection] = "Upgrade"; | ||
|
||
return; | ||
} | ||
|
||
var webSocketAcceptContext = new WebSocketAcceptContext { }; | ||
|
||
var webSocket = await httpContext.WebSockets | ||
.AcceptWebSocketAsync(webSocketAcceptContext) | ||
.ConfigureAwait(false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// See https://aka.ms/new-console-template for more information | ||
Console.WriteLine("Hello, World!"); |
38 changes: 38 additions & 0 deletions
38
experiments/Lavalink4NET.Experiments.Receive/VoiceServerSessionManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
namespace Lavalink4NET.Experiments.Receive; | ||
|
||
using System.Collections.Concurrent; | ||
using Lavalink4NET.Clients; | ||
|
||
internal sealed class VoiceServerSessionManager : IVoiceServerSessionManager | ||
{ | ||
private readonly ConcurrentDictionary<Guid, (ulong GuildId, VoiceServer VoiceServer)> _voiceServers; | ||
|
||
public VoiceServerSessionManager() | ||
{ | ||
_voiceServers = new ConcurrentDictionary<Guid, (ulong GuildId, VoiceServer VoiceServer)>(); | ||
} | ||
|
||
public Guid Allocate(ulong guildId, VoiceServer voiceServer) | ||
{ | ||
var sessionId = Guid.NewGuid(); | ||
_voiceServers.TryAdd(sessionId, (guildId, voiceServer)); | ||
|
||
return sessionId; | ||
} | ||
|
||
public bool TryResolve(Guid sessionId, out ulong guildId, out VoiceServer voiceServer) | ||
{ | ||
if (_voiceServers.TryGetValue(sessionId, out var pair)) | ||
{ | ||
guildId = pair.GuildId; | ||
voiceServer = pair.VoiceServer; | ||
|
||
return true; | ||
} | ||
|
||
guildId = default; | ||
voiceServer = default; | ||
|
||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters