private async Task ClientDisconnected_Internal(ConnectedUser player)
 {
     lock (clients)
     {
         clients.Remove(player);
     }
     if (ClientDisconnected != null)
     {
         await ClientDisconnected.Invoke(player);
     }
 }
 private async Task Send(ConnectedUser ConnectedClient, ArraySegment <byte> data)
 {
     try
     {
         await ConnectedClient.socket.SendAsync(data, SocketFlags.None);
     }
     catch (Exception e)
     {
         Logger.Debug(e.ToString());
         await ClientDisconnected_Internal(ConnectedClient);
     }
 }
 public async Task Send(ConnectedUser ConnectedClient, Packet packet)
 {
     try
     {
         var bytes = GetFrameFromPacket(packet);
         await ConnectedClient.networkStream.WriteAsync(bytes.Array, 0, bytes.Count);
     }
     catch (Exception e)
     {
         Logger.Debug(e.ToString());
         await ClientDisconnected_Internal(ConnectedClient);
     }
 }
        public async Task Start()
        {
            var ipv4Address       = IPAddress.Any;
            var localIPV4EndPoint = new IPEndPoint(ipv4Address, port);

            ipv4Server = new Socket(ipv4Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            ipv4Server.Bind(localIPV4EndPoint);
            ipv4Server.Listen(100);

            while (Enabled)
            {
                // Start an asynchronous socket to listen for connections.
                Logger.Debug($"Waiting for an IPV4 connection on {ipv4Address}:{port} ...");
                var clientSocket = await ipv4Server.AcceptAsync();

                Logger.Debug($"Accepted connection on {ipv4Address}:{port} ...");

                var connectedUser = new ConnectedUser
                {
                    socket        = clientSocket,
                    networkStream = new NetworkStream(clientSocket, ownsSocket: true),
                    id            = Guid.NewGuid()
                };

                byte[] buffer         = new byte[1024];
                string headerResponse = string.Empty;
                if (ipv4Server != null && ipv4Server.IsBound)
                {
                    try
                    {
                        var i = connectedUser.networkStream.Read(buffer, 0, 1024);
                        headerResponse = (Encoding.UTF8.GetString(buffer)).Substring(0, i);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        Console.WriteLine(e.StackTrace);
                    }
                }

                if (clientSocket != null)
                {
                    /* Handshaking and managing ClientSocket */
                    if (headerResponse != "")
                    {
                        var key = headerResponse.Replace("ey:", "`")
                                  .Split('`')[1]
                                  .Replace("\r", "").Split('\n')[0]
                                  .Trim();

                        byte[] ComputeHash(string str)
                        {
                            return(sha1.ComputeHash(Encoding.ASCII.GetBytes(str)));
                        }

                        string AcceptKey(ref string refKey)
                        {
                            string longKey = refKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

                            byte[] hashBytes = ComputeHash(longKey);
                            return(Convert.ToBase64String(hashBytes));
                        }

                        var acceptKey = AcceptKey(ref key);

                        var newLine = "\r\n";

                        var response = "HTTP/1.1 101 Switching Protocols" + newLine
                                       + "Upgrade: websocket" + newLine
                                       + "Connection: Upgrade" + newLine
                                       + "Sec-WebSocket-Accept: " + acceptKey +
                                       newLine +
                                       newLine;
                        clientSocket.Send(Encoding.UTF8.GetBytes(response));
                    }
                }

                lock (clients)
                {
                    clients.Add(connectedUser);
                }

                if (ClientConnected != null)
                {
                    await ClientConnected.Invoke(connectedUser);
                }

                ReceiveLoop(connectedUser);
            }
        }
        private async void ReceiveLoop(ConnectedUser player)
        {
            try
            {
                // Begin receiving the data from the remote device.
                while (player?.socket?.Connected ?? false)
                {
                    var bytesRead = await player.networkStream.ReadAsync(player.buffer, 0, ConnectedUser.BufferSize);

                    if (bytesRead > 0)
                    {
                        var currentBytes = new byte[bytesRead];
                        Buffer.BlockCopy(player.buffer.ToArray(), 0, currentBytes, 0, bytesRead);

                        Packet readPacket = null;
                        bool   fin        = (currentBytes[0] & 0b10000000) != 0,
                               mask       = (currentBytes[1] & 0b10000000) != 0;

                        int opcode = currentBytes[0] & 0b00001111,
                            msglen = currentBytes[1] - 128,
                            offset = 2;

                        if (opcode == 0x8)
                        {
                            await Send(player, GetFrameFromPacket(null, EOpcodeType.ClosedConnection));

                            throw new Exception("Stream ended");
                        }

                        if (msglen == 126)
                        {
                            msglen = BitConverter.ToUInt16(new byte[] { currentBytes[3], currentBytes[2] }, 0);
                            offset = 4;
                        }

                        if (msglen == 0)
                        {
                            Logger.Debug("msglen == 0");
                        }
                        else if (mask)
                        {
                            byte[] decoded = new byte[msglen];
                            byte[] masks   = new byte[4] {
                                currentBytes[offset], currentBytes[offset + 1], currentBytes[offset + 2], currentBytes[offset + 3]
                            };
                            offset += 4;

                            for (int i = 0; i < msglen; ++i)
                            {
                                decoded[i] = (byte)(currentBytes[offset + i] ^ masks[i % 4]);
                            }

                            player.accumulatedBytes.AddRange(decoded);
                            var accumulatedBytes = player.accumulatedBytes.ToArray();
                            if (accumulatedBytes.Length == msglen)
                            {
                                try
                                {
                                    readPacket = decoded.ProtoDeserialize <Packet>();
                                    PacketReceived?.Invoke(player, readPacket);
                                }
                                catch (Exception e)
                                {
                                    Logger.Error(e.Message);
                                    Logger.Error(e.StackTrace);
                                }
                                player.accumulatedBytes.Clear();
                                accumulatedBytes = player.accumulatedBytes.ToArray();
                            }
                        }
                    }
                    else if (bytesRead == 0)
                    {
                        await Send(player, GetFrameFromPacket(null, EOpcodeType.ClosedConnection));

                        throw new Exception("Stream ended");
                    }
                }
            }
            catch (ObjectDisposedException)
            {
                await ClientDisconnected_Internal(player);
            }
            catch (Exception e)
            {
                Logger.Debug(e.ToString());
                await ClientDisconnected_Internal(player);
            }
        }
        private async Task WsServer_PacketReceived(ConnectedUser user, Packet packet)
        {
            if (packet.packetCase == Packet.packetOneofCase.Connect)
            {
                var response = new Packet()
                {
                    ConnectResponse = new ConnectResponse()
                    {
                        Self = new User()
                        {
                            Id   = Guid.NewGuid().ToString(),
                            Name = "Moon"
                        },
                        Response = new Response()
                        {
                            Message = "Successfully connected to Rain server",
                            Type    = Response.ResponseType.Success
                        },
                        State = State
                    }
                };
                await Send(user, response);
            }
            else if (packet.packetCase == Packet.packetOneofCase.Command)
            {
                UnityMainThreadDispatcher.Instance().Enqueue(() =>
                {
                    var command = packet.Command;
                    switch (command.commandCase)
                    {
                    case Command.commandOneofCase.do_action_command:
                        {
                            DoAction(command.do_action_command.Action);
                            break;
                        }
                    }
                });
            }
            else if (packet.packetCase == Packet.packetOneofCase.Event)
            {
                var @event = packet.Event;
                switch (@event.eventCase)
                {
                case Event.eventOneofCase.player_added_event:
                    await AddPlayer(@event.player_added_event.Player);

                    break;

                case Event.eventOneofCase.player_updated_event:
                    await UpdatePlayer(@event.player_updated_event.Player);

                    break;

                case Event.eventOneofCase.player_left_event:
                    await RemovePlayer(@event.player_left_event.Player);

                    break;

                case Event.eventOneofCase.toggle_updated_event:
                    await UpdateToggle(@event.toggle_updated_event.Toggle);

                    break;
                }
            }
        }