103 lines
3.2 KiB
C#
103 lines
3.2 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks.Channels;
|
|
using Microsoft.AspNetCore.Sockets.Internal;
|
|
|
|
namespace Microsoft.AspNetCore.Sockets
|
|
{
|
|
public class ConnectionManager
|
|
{
|
|
private readonly ConcurrentDictionary<string, ConnectionState> _connections = new ConcurrentDictionary<string, ConnectionState>();
|
|
private readonly Timer _timer;
|
|
|
|
public ConnectionManager()
|
|
{
|
|
_timer = new Timer(Scan, this, 0, 1000);
|
|
}
|
|
|
|
public bool TryGetConnection(string id, out ConnectionState state)
|
|
{
|
|
return _connections.TryGetValue(id, out state);
|
|
}
|
|
|
|
public ConnectionState CreateConnection()
|
|
{
|
|
var id = MakeNewConnectionId();
|
|
|
|
var transportToApplication = Channel.CreateUnbounded<Message>();
|
|
var applicationToTransport = Channel.CreateUnbounded<Message>();
|
|
|
|
var transportSide = new ChannelConnection<Message>(applicationToTransport, transportToApplication);
|
|
var applicationSide = new ChannelConnection<Message>(transportToApplication, applicationToTransport);
|
|
|
|
var state = new ConnectionState(
|
|
new Connection(id, applicationSide),
|
|
transportSide);
|
|
|
|
_connections.TryAdd(id, state);
|
|
return state;
|
|
}
|
|
|
|
public void RemoveConnection(string id)
|
|
{
|
|
ConnectionState state;
|
|
_connections.TryRemove(id, out state);
|
|
|
|
// Remove the connection completely
|
|
}
|
|
|
|
private static string MakeNewConnectionId()
|
|
{
|
|
// TODO: We need to sign and encyrpt this
|
|
return Guid.NewGuid().ToString();
|
|
}
|
|
|
|
private static void Scan(object state)
|
|
{
|
|
((ConnectionManager)state).Scan();
|
|
}
|
|
|
|
private void Scan()
|
|
{
|
|
// Scan the registered connections looking for ones that have timed out
|
|
foreach (var c in _connections)
|
|
{
|
|
if (!c.Value.Active && (DateTimeOffset.UtcNow - c.Value.LastSeenUtc).TotalSeconds > 5)
|
|
{
|
|
ConnectionState s;
|
|
if (_connections.TryRemove(c.Key, out s))
|
|
{
|
|
// REVIEW: Should we keep firing and forgetting this?
|
|
var ignore = s.DisposeAsync();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void CloseConnections()
|
|
{
|
|
// Stop firing the timer
|
|
_timer.Dispose();
|
|
|
|
var tasks = new List<Task>();
|
|
|
|
foreach (var c in _connections)
|
|
{
|
|
ConnectionState s;
|
|
if (_connections.TryRemove(c.Key, out s))
|
|
{
|
|
tasks.Add(s.DisposeAsync());
|
|
}
|
|
}
|
|
|
|
Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(5));
|
|
}
|
|
}
|
|
}
|