2022-04-12 14:22:05 -07:00
|
|
|
|
// <copyright file="SessionManager.cs" company="Scratch Foundation">
|
|
|
|
|
// Copyright (c) Scratch Foundation. All rights reserved.
|
|
|
|
|
// </copyright>
|
|
|
|
|
|
|
|
|
|
namespace ScratchLink;
|
|
|
|
|
|
2022-07-07 17:40:49 -07:00
|
|
|
|
using System;
|
2022-05-03 09:10:24 -07:00
|
|
|
|
using System.Collections.Concurrent;
|
2022-07-21 12:42:36 -07:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Linq;
|
2022-07-11 14:58:08 -07:00
|
|
|
|
using Fleck;
|
2022-04-12 14:22:05 -07:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This class connects a WebSocket to the appropriate session type and tracks the collection of active sessions.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal abstract class SessionManager
|
|
|
|
|
{
|
2022-05-03 09:10:24 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Stores the set of active sessions. Implemented as a dictionary because ConcurrentHashSet doesn't exist.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly ConcurrentDictionary<Session, bool> sessions = new ();
|
2022-04-19 15:47:17 -07:00
|
|
|
|
|
2022-04-12 14:22:05 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Activated when the number of active sessions changes.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public event EventHandler ActiveSessionCountChanged;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the count of active connected WebSocket sessions.
|
|
|
|
|
/// </summary>
|
2022-05-03 09:10:24 -07:00
|
|
|
|
public int ActiveSessionCount { get => this.sessions.Count; }
|
2022-04-12 14:22:05 -07:00
|
|
|
|
|
2022-07-21 12:42:36 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Close all currently-active sessions.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void EndAllSessions()
|
|
|
|
|
{
|
|
|
|
|
// shallow-copy the session list since it will change as sessions close
|
|
|
|
|
var allCurrentSessions = this.sessions.Keys.Select(session => session);
|
|
|
|
|
|
|
|
|
|
foreach (var session in allCurrentSessions)
|
|
|
|
|
{
|
|
|
|
|
session.EndSession();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-12 14:22:05 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Call this with a new connection context to ask the SessionManager to build and manage a session for it.
|
|
|
|
|
/// </summary>
|
2022-07-11 14:58:08 -07:00
|
|
|
|
/// <param name="webSocket">The WebSocket which the SessionManager should adopt and connect to a session.</param>
|
2022-07-21 12:42:36 -07:00
|
|
|
|
public async void ClientDidConnect(IWebSocketConnection webSocket)
|
2022-04-12 14:22:05 -07:00
|
|
|
|
{
|
2022-09-09 17:31:06 -07:00
|
|
|
|
Trace.WriteLine("ClientDidConnect");
|
2022-07-21 12:42:36 -07:00
|
|
|
|
using var session = this.MakeNewSession(webSocket);
|
|
|
|
|
if (!this.sessions.TryAdd(session, true))
|
|
|
|
|
{
|
|
|
|
|
throw new ApplicationException("Failed to add session to session manager.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.ActiveSessionCountChanged?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
try
|
2022-05-03 09:10:24 -07:00
|
|
|
|
{
|
2022-07-21 12:42:36 -07:00
|
|
|
|
await session.Run();
|
2022-09-09 17:31:06 -07:00
|
|
|
|
Trace.WriteLine("session.Run() complete");
|
2022-07-21 12:42:36 -07:00
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (this.sessions.TryRemove(session, out _))
|
2022-05-03 09:10:24 -07:00
|
|
|
|
{
|
2022-07-21 12:42:36 -07:00
|
|
|
|
this.ActiveSessionCountChanged?.Invoke(this, EventArgs.Empty);
|
2022-05-03 09:10:24 -07:00
|
|
|
|
}
|
2022-07-21 12:42:36 -07:00
|
|
|
|
else
|
2022-05-03 09:10:24 -07:00
|
|
|
|
{
|
2022-09-09 17:31:06 -07:00
|
|
|
|
Trace.WriteLine("Failed to remove session from session manager");
|
2022-05-03 09:10:24 -07:00
|
|
|
|
}
|
2022-07-21 12:42:36 -07:00
|
|
|
|
}
|
2022-04-12 14:22:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create a new Session object to handle a new WebSocket connection.
|
|
|
|
|
/// </summary>
|
2022-07-11 14:58:08 -07:00
|
|
|
|
/// <param name="webSocket">Create a Session to handle this connection.</param>
|
2022-04-12 14:22:05 -07:00
|
|
|
|
/// <returns>A new Session object connected to the provided context.</returns>
|
2022-07-11 14:58:08 -07:00
|
|
|
|
protected abstract Session MakeNewSession(IWebSocketConnection webSocket);
|
2022-04-12 14:22:05 -07:00
|
|
|
|
}
|