private async Task HandleRecievedMessage(byte[] content)
        {
            var opСode = (IoFogWebSocketOpCodeEnum)content[0];

            switch (opСode)
            {
            case IoFogWebSocketOpCodeEnum.Ping:
                Console.WriteLine($"{DateTime.Now}: " + "PING received");
                break;

            case IoFogWebSocketOpCodeEnum.Pong:
                Console.WriteLine($"{DateTime.Now}: " + "PONG received");
                break;

            case IoFogWebSocketOpCodeEnum.Ack:
                Console.WriteLine($"{DateTime.Now}: " + "ACK received");
                break;

            case IoFogWebSocketOpCodeEnum.ControlSignal:
                Console.WriteLine($"{DateTime.Now}: " + "ControlSignal received");
                await SendAcknowledgeAsync();

                _handler.OnNewConfigSignal();
                break;

            case IoFogWebSocketOpCodeEnum.Message:
                Console.WriteLine($"{DateTime.Now}: " + "MESSAGE received");
                int totalMsgLength = ByteUtils.BytesToInteger(ByteUtils.CopyOfRange(content, 1, 5));
                int msgLength      = totalMsgLength + 5;
                var message        = new IoMessage(ByteUtils.CopyOfRange(content, 5, msgLength));
                await SendAcknowledgeAsync();

                _handler.OnMessage(message);
                break;

            case IoFogWebSocketOpCodeEnum.Receipt:
                Console.WriteLine($"{DateTime.Now}: " + "RECEIPT received");
                int    size      = content[1];
                int    pos       = 3;
                string messageId = string.Empty;
                if (size > 0)
                {
                    messageId = StringUtils.NewString(ByteUtils.CopyOfRange(content, pos, pos + size));
                    pos      += size;
                }
                size = content[2];
                long timestamp = 0L;
                if (size > 0)
                {
                    timestamp = ByteUtils.BytesToLong(ByteUtils.CopyOfRange(content, pos, pos + size));
                }
                await SendAcknowledgeAsync();

                _handler.OnReceipt(messageId, timestamp);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        private void ConvertBytesToMessage(byte[] header, byte[] data, int pos)
        {
            if (header == null || header.Length == 0)
            {
                header = data;
            }

            Version = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 0, 2));

            if (Version != _version)
            {
                // TODO: incompatible version
                throw new Exception("Incompatible version");
            }

            int size = header[2];

            if (size > 0)
            {
                Id   = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos += size;
            }

            size = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 3, 5));
            if (size > 0)
            {
                Tag  = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos += size;
            }

            size = header[5];
            if (size > 0)
            {
                GroupId = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos    += size;
            }

            size = header[6];
            if (size > 0)
            {
                SequenceNumber = ByteUtils.BytesToInteger(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos           += size;
            }

            size = header[7];
            if (size > 0)
            {
                SequenceTotal = ByteUtils.BytesToInteger(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos          += size;
            }

            size = header[8];
            if (size > 0)
            {
                Priority = (sbyte)data[pos];
                pos     += size;
            }

            size = header[9];
            if (size > 0)
            {
                Timestamp = ByteUtils.BytesToLong(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos      += size;
            }

            size = header[10];
            if (size > 0)
            {
                Publisher = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos      += size;
            }

            size = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 11, 13));
            if (size > 0)
            {
                AuthId = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos   += size;
            }

            size = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 13, 15));
            if (size > 0)
            {
                AuthGroup = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos      += size;
            }

            size = header[15];
            if (size > 0)
            {
                ChainPosition = ByteUtils.BytesToLong(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos          += size;
            }

            size = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 16, 18));
            if (size > 0)
            {
                Hash = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos += size;
            }

            size = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 18, 20));
            if (size > 0)
            {
                PreviousHash = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos         += size;
            }

            size = ByteUtils.BytesToShort(ByteUtils.CopyOfRange(header, 20, 22));
            if (size > 0)
            {
                Nonce = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos  += size;
            }

            size = header[22];
            if (size > 0)
            {
                DifficultyTarget = ByteUtils.BytesToInteger(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos += size;
            }

            size = header[23];
            if (size > 0)
            {
                InfoType = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos     += size;
            }

            size = header[24];
            if (size > 0)
            {
                InfoFormat = StringUtils.NewString(ByteUtils.CopyOfRange(data, pos, pos + size));
                pos       += size;
            }

            size = ByteUtils.BytesToInteger(ByteUtils.CopyOfRange(header, 25, 29));
            if (size > 0)
            {
                ContextData = ByteUtils.CopyOfRange(data, pos, pos + size);
                pos        += size;
            }

            size = ByteUtils.BytesToInteger(ByteUtils.CopyOfRange(header, 29, 33));
            if (size > 0)
            {
                ContentData = ByteUtils.CopyOfRange(data, pos, pos + size);
            }
        }