Here is a simple example:
using System.Collections.Concurrent;
namespace SillageLogTracer
{
public class Program
{
// Change from ConcurrentBag to ConcurrentDictionary
private static readonly ConcurrentDictionary<Guid, HttpContext> SseClients = new ConcurrentDictionary<Guid, HttpContext>();
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseStaticFiles();
// SSE Endpoint for Trace
app.MapGet("/sse", async (HttpContext context, CancellationToken token) =>
{
context.Response.ContentType = "text/event-stream";
// Create a unique client ID for this connection
var clientId = Guid.NewGuid();
// Add the client to the list of connected clients
SseClients.TryAdd(clientId, context);
try
{
while (!token.IsCancellationRequested)
{
await context.Response.Body.FlushAsync(token);
await Task.Delay(1000, token); // Delay for 1 second
}
}
catch (TaskCanceledException)
{
// Handle the task cancellation gracefully
}
finally
{
// Remove the client from the list upon disconnection
SseClients.TryRemove(clientId, out _);
}
});
app.MapGet("/sendMessage", async (string message) =>
{
// Send message to all connected SSE clients
var tasks = new List<Task>();
foreach (var client in SseClients.Values)
{
if (!client.RequestAborted.IsCancellationRequested)
{
var task = client.Response.WriteAsync($"data: {message}\n\n");
tasks.Add(task);
}
}
// Wait for all messages to be sent
await Task.WhenAll(tasks);
return Results.Ok($"Message '{message}' sent to {SseClients.Count} clients.");
});
app.Run();
}
}
}
Here is the javascript client :
// client.js
//var message = prompt("Saisissez votre message : ");fetch(`/sendMessage?message=${message}`);
class TraceClient {
constructor(url) {
this.url = url;
this.eventSource = null;
this.messageElement = document.getElementById('messages');
}
connect() {
this.eventSource = new EventSource(this.url);
this.eventSource.onopen = () => {
console.log('Connection established');
};
this.eventSource.onmessage = (event) => {
this.handleMessage(event.data);
};
this.eventSource.onerror = (error) => {
console.error(error);
};
}
disconnect() {
if (this.eventSource) {
this.eventSource.close();
console.log('Connection closed');
console.log("closing...")
}
}
handleMessage(data) {
if (data.type === 'trace') {
this.addMessage(`Received trace: ${data.content}`);
} else if (data.type === 'heartbeat') {
this.addMessage('Heartbeat received');
} else {
this.addMessage(data)
}
}
addMessage(message) {
const msgElement = document.createElement('li');
msgElement.textContent = message;
this.messageElement.appendChild(msgElement);
this.messageElement.scrollTop = this.messageElement.scrollHeight;
}
}
document.addEventListener('DOMContentLoaded', () => {
const traceUrl = '/sse';
const client = new TraceClient(traceUrl);
client.connect();
});
Top comments (0)