-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathClientSocket.cs
More file actions
executable file
·106 lines (84 loc) · 3.82 KB
/
Copy pathClientSocket.cs
File metadata and controls
executable file
·106 lines (84 loc) · 3.82 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
using System.Data;
using DotNetty.Common.Utilities;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using Serilog;
using Shiki.Common.Result;
using UniScan.Network.Client.Extensions;
using UniScan.Network.Client.Remote.Connection;
using UniScan.Network.Protocol.PayloadPart;
using UniScan.Network.Request;
using UniScan.Network.Socket;
using UniScan.Network.Util;
namespace UniScan.Network.Client;
public class ClientSocket : ISocket
{
public ILogger Logger => Log.ForContext<ClientSocket>();
private IEventLoopGroup? _group;
private readonly UniScanClientChannelInitializer _channelInitializer;
public UniScanChannelInitializer ChannelInitializer => _channelInitializer;
public ConnectionStateTracker ConnectionState { get; } = new();
private readonly IRemoteConnectionMethod _connectionMethod;
public IChannel? Channel { get; private set; }
public bool Connected => Channel?.Active == true;
private readonly RequestManager _requestManager = new();
public ClientSocket(UniScanClientChannelInitializer channelInitializer, IRemoteConnectionMethod connectionMethod, IEventLoopGroup group)
{
ArgumentNullException.ThrowIfNull(channelInitializer);
ArgumentNullException.ThrowIfNull(connectionMethod);
_connectionMethod = connectionMethod;
_channelInitializer = channelInitializer;
_group = group;
}
public async Task StartAsync()
{
if (_connectionMethod is null) throw new NullReferenceException(nameof(_connectionMethod));
try
{
Bootstrap bs = new Bootstrap().Group(_group)
.ConnectionMethod(_connectionMethod)
.Handler(new ActionChannelInitializer<IChannel>((channel) =>
{
IChannelPipeline pipeline = channel.Pipeline;
pipeline.AddFirst(ConnectionState);
pipeline.AddLast(ChannelInitializer);
pipeline.AddLast(new ResponseHandler(_requestManager));
}));
Channel = await _connectionMethod.ConnectAsync(bs);
}
catch (Exception)
{
await StopAsync();
throw;
}
}
public async Task StopAsync()
{
if (_requestManager != null)
await _requestManager.RejectAllAsync(new OperationCanceledException("Socket is shutting down"));
if (Channel != null)
{
await Channel.CloseAsync();
Channel = null;
}
}
public async Task<bool> SendPacketAsync(IPacket packet) => await SendPacketAsync(Channel, packet);
public async Task<bool> SendPacketAsync(IChannel? channel, IPacket packet)
{
if (channel is not { Active: true }) return false;
await channel.WriteAndFlushAsync(packet);
return true;
}
public async Task<Result<TResponse, Exception>> SendRequestAsync<TResponse>(
IRequestPayloadPart<TResponse> request, CancellationToken ct = default)
where TResponse : IPacket, IResponsePayloadPart => await _requestManager.MakeRequestAsync(Channel, request, ct);
public async Task<Result<TResponse, Exception>> SendRequestAsync<TResponse>(
IChannel? channel, IRequestPayloadPart<TResponse> request, CancellationToken ct = default)
where TResponse : IPacket, IResponsePayloadPart
{
if (channel is not { Active: true })
return new Result<TResponse, Exception>(new ArgumentNullException(nameof(channel)));
return await _requestManager.MakeRequestAsync(channel, request, ct);
}
}