using DotNetty.Buffers; using DotNetty.Codecs; using DotNetty.Handlers.Logging; using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; using Fody; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Team.Communicate.EventArg; using Team.Communicate.Handlers; namespace Team.Communicate.Server { // ReSharper disable once ClassNeverInstantiated.Global public class DotnettyServer : AbstractTcpConnector, IDisposable { private readonly ServerBootstrap _bootstrap = new(); private readonly MultithreadEventLoopGroup _bossGroup = new(1); private readonly MultithreadEventLoopGroup _workerGroup = new(); private IChannel _bootstrapChannel; private IChannelPipeline _channelPipeline; public ConcurrentDictionary ConnectionClients { get; } private bool _isInit; private readonly List UseUngisterKeys = new(); public event EventHandler ConnectionEvent; public event EventHandler UnRegisterMessageEvent; private readonly TelnetServerHandler _serverHandler; public override Encoding Encoding { get => base.Encoding; set { base.Encoding = value; _serverHandler?.SetEncoding(value); } } public DotnettyServer() { ConnectionClients = new ConcurrentDictionary(); Environment.SetEnvironmentVariable("io.netty.allocator.numDirectArenas", "0"); _serverHandler = new TelnetServerHandler { Encoding = Encoding }; } public override void SetEnd(string endWith) { base.SetEnd(endWith); _serverHandler.SetEndWith(endWith); } public override void UseUnRegisterMessage(string key) { if (UseUngisterKeys.Contains(key)) { return; } UseUngisterKeys.Add(key); _serverHandler.SetUseUnRegisterKeys(UseUngisterKeys); } public override void Register(string id, Func> func) { _serverHandler.Register(id, func); } public override void UnRegister(string id) { _serverHandler.UnRegister(id); } public void ClearAllRegister() { _serverHandler.ClearAllRegister(); } public void SetEventHandler(Func> sendEventHandler) { } [ConfigureAwait(false)] public async Task StartAsync(int port) { if (_isInit) { return true; } var stringEncoder = new StringEncoder(Encoding); var stringDecoder = new StringDecoder(Encoding); _bootstrap .Group(_bossGroup, _workerGroup) .Channel() .Option(ChannelOption.TcpNodelay, true) .Option(ChannelOption.SoBacklog, 100) .Handler(new LoggingHandler(LogLevel.INFO)) .ChildHandler(new ActionChannelInitializer(channel => { var pipeline = channel.Pipeline; _channelPipeline = pipeline; pipeline.AddLast(new DelimiterBasedFrameDecoder(8192, ByteBuffers)); //pipeline.AddLast(stringEncoder, stringDecoder, _serverHandler); pipeline.AddLast("echo", _serverHandler); })); _serverHandler.ConnectionEvent += ServerHandler_ConnectionEvent; _serverHandler.UseUnRegisterAction += (s, e) => { UnRegisterMessageEvent?.Invoke(this, new UnRegisterEventArgs(new UnRegisterContent(s, e, Encoding))); }; try { _bootstrapChannel = await _bootstrap.BindAsync(port); _isInit = true; return _isInit; } catch (Exception e) { Console.WriteLine(e); throw; } } private void ServerHandler_ConnectionEvent(object sender, TcpStateEventArgs e) { var id = e.ServerConnection.GetHashCode(); if (e.ServerConnection.Connected) { if (!ConnectionClients.ContainsKey(id)) { ConnectionClients.TryAdd(id, e); } else { ConnectionClients[id] = e; } } else { if (ConnectionClients.ContainsKey(id)) { ConnectionClients.TryRemove(id, out _); } } ConnectionEvent?.Invoke(this, e); } [ConfigureAwait(false)] public async Task SendMessage(string msg) { var stringBuilder = new StringBuilder(); stringBuilder.Append(msg); stringBuilder.Append(_serverHandler._endWith); var bytes = Encoding.GetBytes(stringBuilder.ToString()); var sendBytes = Unpooled.Buffer(256); sendBytes.WriteBytes(bytes); await _channelPipeline.WriteAndFlushAsync(sendBytes); //await _channelPipeline.WriteAndFlushAsync(msg + _serverHandler._endWith); } public async void Dispose() { try { if (_bootstrapChannel != null) { await _bootstrapChannel.Pipeline.DisconnectAsync(); await _bootstrapChannel.Pipeline.CloseAsync(); await _bootstrapChannel.DisconnectAsync(); await _bootstrapChannel?.CloseAsync(); } await _bossGroup.ShutdownGracefullyAsync(); await _workerGroup.ShutdownGracefullyAsync(); } catch (Exception e) { Console.WriteLine(e); } _isInit = false; } } }