Repository navigation
Expand file tree
/
Copy pathServerSocket.cs
More file actions
executable file
·123 lines (96 loc) · 4.14 KB
/
Copy pathServerSocket.cs
File metadata and controls
executable file
·123 lines (96 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System.Collections.Immutable;
using System.Net;
using DotNetty.Common.Utilities;
using DotNetty.Handlers.Logging;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using Semver;
using Serilog;
using Shiki.Common.Identity;
using Shiki.Common.Result;
using UniScan.Network.Data.Info.Software;
using UniScan.Network.Group;
using UniScan.Network.Protocol.PayloadPart;
using UniScan.Network.Request;
using UniScan.Network.Server.Handler;
using UniScan.Network.Server.HostMethod;
using UniScan.Network.Socket;
using UniScan.Network.Util;
namespace UniScan.Network.Server;
public class ClientAttributes
{
public static readonly AttributeKey<ClientSoftwareInfo> SoftwareInfoAttribute =
AttributeKey<ClientSoftwareInfo>.ValueOf("software");
public static readonly AttributeKey<KeyValuePair<Guid, UniScan.Server.Authentication.User>> SessionAttribute =
AttributeKey<KeyValuePair<Guid, UniScan.Server.Authentication.User>>.ValueOf("session");
}
public class ServerSocket : IHostSocket
{
public ILogger Logger { get; }
private UniScanServerChannelInitializer _channelInitializer;
public UniScanChannelInitializer ChannelInitializer => _channelInitializer;
private readonly ImmutableList<IServerHostMethod> _hostMethods;
private readonly List<IChannel> _channels = [];
private readonly IHostNetworkGroupManager _networkGroupManager;
private readonly RequestManager _requestManager = new();
public ClientsManager ClientManager { get; } = new();
public ServerSocket(UniScanServerChannelInitializer channelInitializer, IEnumerable<IServerHostMethod> methods, IHostNetworkGroupManager groupManager)
{
_hostMethods = [.. methods];
_channelInitializer = channelInitializer;
_networkGroupManager = groupManager;
Logger = Log.ForContext<ServerSocket>();
}
public async Task StartAsync()
{
if (!_hostMethods.Any())
{
throw new Exception("No host methods found");
}
try
{
var task = _hostMethods.Select(async m =>
{
ServerBootstrap bootstrap = new();
m.Apply(bootstrap, _networkGroupManager);
bootstrap.ChildHandler(new ActionChannelInitializer<IChannel>((channel) =>
{
IChannelPipeline pipeline = channel.Pipeline;
m.ApplyPipeline(pipeline);
pipeline.AddLast(ChannelInitializer);
pipeline.AddFirst(new ConnectionStateTracker());
pipeline.AddFirst(ClientManager);
pipeline.AddLast(new ResponseHandler(_requestManager));
}));
_channels.Add(await m.BindAsync(bootstrap));
Logger.Information("Listening on transport {Transport}", m.ToDisplayString());
});
await Task.WhenAll(task);
}
catch (Exception ex)
{
Logger.Error(ex, "Failed to start socket");
await StopAsync();
}
}
public async Task StopAsync()
{
if (_requestManager != null) await _requestManager.RejectAllAsync(new OperationCanceledException("Socket is shutting down")).ContinueWith(_ => _requestManager.DisposeAsync());
var t = _channels.Select(c => c.CloseAsync());
await Task.WhenAll(t);
_channels.Clear();
}
public async Task<bool> SendPacketAsync(IChannel? client, IPacket packet)
{
if (client is not { Active: true }) return false;
await client.WriteAndFlushAsync(packet);
return true;
}
public async Task BroadcastPacketAsync(IPacket packet) => await ClientManager.BroadcastAsync(packet);
public async Task<Result<TResponse, Exception>> SendRequestAsync<TResponse>(IChannel? client, IRequestPayloadPart<TResponse> packet, CancellationToken ct = default)
where TResponse : IPacket, IResponsePayloadPart
{
return await _requestManager.MakeRequestAsync(client, packet, ct);
}
}