mirror of
https://github.com/ppy/osu.git
synced 2026-05-17 08:42:35 +08:00
9a2846539f
- Supersedes / closes https://github.com/ppy/osu/pull/18129. Reasons I didn't use that PR are hopefully obvious upon comparing diffs but I can elaborate if they are not. - Single metric included for demonstration purposes. - Do not want to talk about further schema design at this time. - Specify `OSU_WEBSOCKET_SERVER=1` envvar to enable. - Can test consumption with [this five minute html job](https://github.com/user-attachments/files/26839923/index.html) (works even as a standalone file opened in browser, no CORS bs!) - There's a lot of inline comments, go read them. There are many WTFs because the .NET frozen websocket API is weird and stanky and reeks of the year 2007. The inline comments attempt to explain.
62 lines
1.8 KiB
C#
62 lines
1.8 KiB
C#
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
using System;
|
|
using System.Net.WebSockets;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using osu.Game.IPC;
|
|
|
|
namespace osu.Game.Tests.IPC
|
|
{
|
|
public sealed class WebSocketClient : IDisposable
|
|
{
|
|
public event Action<string>? MessageReceived;
|
|
public event Action? Closed;
|
|
|
|
private readonly int port;
|
|
private WebSocketChannel? channel;
|
|
|
|
public WebSocketClient(int port)
|
|
{
|
|
this.port = port;
|
|
}
|
|
|
|
public async Task Start(CancellationToken cancellationToken = default)
|
|
{
|
|
var webSocket = new ClientWebSocket();
|
|
await webSocket.ConnectAsync(new Uri($@"ws://localhost:{port}/"), cancellationToken);
|
|
channel = new WebSocketChannel(webSocket);
|
|
channel.MessageReceived += msg => MessageReceived?.Invoke(msg);
|
|
channel.ClosedPrematurely += () => Closed?.Invoke();
|
|
channel.Start(cancellationToken);
|
|
}
|
|
|
|
public async Task SendAsync(string message)
|
|
{
|
|
if (channel == null)
|
|
throw new InvalidOperationException($@"Must {nameof(Start)} first.");
|
|
|
|
await channel.SendAsync(message);
|
|
}
|
|
|
|
public async Task StopAsync(CancellationToken stoppingToken = default)
|
|
{
|
|
try
|
|
{
|
|
if (channel != null)
|
|
await channel.StopAsync(stoppingToken).ConfigureAwait(false);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// has to be caught manually because outer task isn't accepting `stoppingToken`.
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
channel?.Dispose();
|
|
}
|
|
}
|
|
}
|