private async void RttRoutine()
        {
            while (Running && !RttToken.IsCancellationRequested)
            {
                try {
                    await Task.Delay(RttInterval, RttToken.Token);
                } catch (Exception) { }

                if (!RttToken.IsCancellationRequested)
                {
                    foreach (var keypair in Users)
                    {
                        WebSocketUser user = keypair.Value;

                        if (user.RTT.Sending)
                        {
                            user.RTT.Last = RttInterval;

                            if (user.RTT.Max < RttInterval)
                            {
                                user.RTT.Max = RttInterval;
                                OnRTT?.Invoke(this, new RttEventArgs(user));
                            }
                        }

                        user.RTT.Sending = true;
                        user.RTT.Sent    = DateTime.UtcNow;

                        await user.Writer.WriteCustomPing();
                    }
                }
            }
        }
        private async Task <(bool, string)> InterpretHeader(WebSocketUser user, Stream ns)
        {
            string header = await HttpUtils.ReadHeader(ns);

            Regex getRegex      = new Regex(@"^GET(.*)HTTP\/1\.1", RegexOptions.IgnoreCase);
            Match getRegexMatch = getRegex.Match(header);

            if (getRegexMatch.Success)
            {
                string[] lines = header.Split('\n');

                foreach (string line in lines)
                {
                    if (line.ToLower().StartsWith("user-agent:"))
                    {
                        int index = line.IndexOf(':') + 1;

                        if (index >= line.Length)
                        {
                            break;
                        }

                        user.Meta.UserAgent = line.Substring(index, line.Length - index).Trim();

                        break;
                    }
                }

                await DoHandshake(ns, header);

                return(true, header);
            }

            return(false, header);
        }
        public void RemoveClient(WebSocketUser user, WebSocketDisconnection reason)
        {
            try {
                if (user == null)
                {
                    return;
                }

                user.Disconnected = true;

                WebSocketUser outer;

                if (Users.ContainsKey(user.UID))
                {
                    Users.TryRemove(user.UID, out outer);
                }

                if (user.ListenToken != null)
                {
                    user.ListenToken.Cancel();
                }

                if (user.Socket != null)
                {
                    user.Socket.Shutdown(SocketShutdown.Both);
                }
            } catch (Exception) { }


            Logger.DebugWrite("INFO", $"Socket got removed. UID: {user.UID}, Reason: {reason}");
            OnDisconnect?.Invoke(this, new DisconnectEventArgs(user, reason));
        }
        private void OnPongReceived(WebSocketUser user)
        {
            if (user.RTT.Sending)
            {
                user.RTT.Sending = false;

                var span = DateTime.UtcNow - user.RTT.Sent;
                var ms   = user.RTT.Last = span.TotalMilliseconds;

                if (ms < user.RTT.Min || user.RTT.Min == -1)
                {
                    user.RTT.Min = ms;
                }

                if (ms > user.RTT.Max)
                {
                    user.RTT.Max = ms;
                }

                OnRTT?.Invoke(this, new RttEventArgs(user));

                //Logger.DebugWrite("INFO", $"RTT Last {user.RTT.Last} / {user.RTT.Min} / {user.RTT.Max}");
            }
        }
 public WebSocketWriter(WebSocketUser user)
 {
     User   = user;
     Stream = user.Stream;
 }
        private async Task ListenClient(WebSocketUser user)
        {
            using (Stream ns = user.Stream) {
                WebSocketReader reader = new WebSocketReader();
                var             res    = await InterpretHeader(user, ns);

                if (!(res.Item1))
                {
                    RemoveClient(user, WebSocketDisconnection.NoHeader);
                    return;
                }

                Logger.DebugWrite("INFO", $"Socket successfully handshaked the update. UID: {user.UID}");
                OnHandshake?.Invoke(this, new HandshakeEventArgs(user, res.Item2));

                while (Running && !user.ListenToken.IsCancellationRequested)
                {
                    WebSocketFrame frame = await reader.Read(ns, user);

                    if (frame == null || frame.Opcode == WebSocketOpcode.ConnectionCloseFrame)
                    {
                        RemoveClient(user, WebSocketDisconnection.Disconnect);
                        break;
                    }

                    switch (frame.Opcode)
                    {
                    case WebSocketOpcode.PingFrame:

                        if (frame.Data.Length <= 125)
                        {
                            await user.Writer.WritePong(frame);

                            OnPing?.Invoke(this, new PingEventArgs(frame.Data));
                        }

                        break;

                    case WebSocketOpcode.PongFrame:

                        OnPong?.Invoke(this, new PongEventArgs(frame.Data));

                        break;

                    case WebSocketOpcode.BinaryFrame:

                        user.Meta.LastTime.Binary = DateTime.UtcNow;

                        if (RttEnabled && frame.Data.Length == 4 && frame.Data[0] == 26 &&
                            frame.Data[1] == 27 && frame.Data[2] == 28 && frame.Data[3] == 29)
                        {
                            OnPongReceived(user);
                        }

                        OnMessage?.Invoke(this, new MessageEventArgs(user, frame));

                        break;

                    case WebSocketOpcode.TextFrame:

                        user.Meta.LastTime.Text = DateTime.UtcNow;

                        OnMessage?.Invoke(this, new MessageEventArgs(user, frame));

                        break;
                    }
                }
            }
        }
        private async void Listen()
        {
            Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

            Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
            Socket.Bind(new IPEndPoint(Address, Port));

            Socket.Listen(Backlog);
            Logger.DebugWrite("INFO", $"WebSocket Server is now listening to new connections.");

            while (Running && !ListenToken.IsCancellationRequested)
            {
                Socket socket = null;

                try {
                    socket = await Socket.AcceptAsync();
                } catch (Exception) {
                    continue;
                }

                WebSocketUser user = new WebSocketUser()
                {
                    Socket = socket,
                    Stream = await GetStream(socket),
                    UID    = RandomGen.GenRandomUID(Users, 128),
                    Server = this
                };

                if (user.Stream == null)
                {
                    try {
                        user.Socket.Shutdown(SocketShutdown.Both);
                    } catch (Exception) { }

                    continue;
                }

                while (!Users.TryAdd(user.UID, user))
                {
                    user.UID = RandomGen.GenRandomUID(Users, 12);
                }

                user.Writer = new WebSocketWriter(user);

                Logger.DebugWrite("INFO", $"New Socket connected to the WebSocket Server. {(user.Socket.RemoteEndPoint as IPEndPoint).Address}, UID: {user.UID}");
                OnConnect?.Invoke(this, new ConnectEventArgs(user));

                CancellationTokenSource cancel = new CancellationTokenSource();

                Task task = new Task(async() => {
                    try {
                        await ListenClient(user);
                    } catch (Exception er) {
                        Logger.DebugWrite("FAILED", "Listen Error: ", er);

                        RemoveClient(user, WebSocketDisconnection.Disconnect);
                    }
                }, cancel.Token, TaskCreationOptions.LongRunning);

                task.Start();

                user.ListenTask  = task;
                user.ListenToken = cancel;
            }
        }
        public async Task <WebSocketFrame> Read(Stream stream, WebSocketUser user)
        {
            byte first;

            try {
                byte[] firstData = new byte[1];
                await stream.ReadAsync(firstData, 0, firstData.Length);

                first = firstData[0];
            } catch (Exception) {
                return(null);
            }

            //if (user != null && !WebSocketUtils.IsClientConnected(user)) {

            //    return null;

            //}

            try {
                byte bitFinFlag = 0x80;
                byte opcodeFlag = 0x0F;

                bool            bitFinSet = (first & bitFinFlag) == bitFinFlag;
                WebSocketOpcode opcode    = (WebSocketOpcode)(first & opcodeFlag);

                byte bitMaskFlag = 0x80;

                byte[] secData = new byte[1];
                await stream.ReadAsync(secData, 0, secData.Length);

                byte second = secData[0];

                bool  bitMaskSet = (second & bitMaskFlag) == bitMaskFlag;
                ulong length     = await ReadLength(stream, second);

                if (length != 0)
                {
                    byte[] decoded;

                    if (bitMaskSet)
                    {
                        byte[] key = await WebSocketReaderWriter.Read(stream, 4);

                        byte[] encoded = await WebSocketReaderWriter.Read(stream, length);

                        decoded = new byte[length];

                        for (int i = 0; i < encoded.Length; i++)
                        {
                            decoded[i] = (byte)(encoded[i] ^ key[i % 4]);
                        }
                    }
                    else
                    {
                        decoded = await WebSocketReaderWriter.Read(stream, length);
                    }

                    WebSocketFrame frame = new WebSocketFrame(opcode, decoded);

                    return(frame);
                }
            }
            catch (Exception er) {
                Logger.DebugWrite("FAILED", "Error read bytes: ", er);
                return(null);
            }

            return(null);
        }