private static bool TryDeserializeMessage(
            GraphQLSocketMessage parsedMessage,
            out OperationMessage message)
        {
            switch (parsedMessage.Type)
            {
            case MessageTypes.Connection.Initialize:
                message = DeserializeInitConnMessage(
                    parsedMessage);
                return(true);

            case MessageTypes.Connection.Terminate:
                message = TerminateConnectionMessage.Default;
                return(true);

            case MessageTypes.Subscription.Start:
                return(TryDeserializeDataStartMessage(
                           parsedMessage, out message));

            case MessageTypes.Subscription.Stop:
                message = DeserializeDataStopMessage(parsedMessage);
                return(true);

            default:
                message = null;
                return(false);
            }
        }
 private static DataCompleteMessage DeserializeSubscriptionCompleteMessage(
     GraphQLSocketMessage parsedMessage)
 {
     if (parsedMessage.Id is null)
     {
         // TODO : resources
         throw new InvalidOperationException("Invalid message structure.");
     }
     return(new DataCompleteMessage(parsedMessage.Id));
 }
        private static DataStopMessage DeserializeDataStopMessage(
            GraphQLSocketMessage parsedMessage)
        {
            if (parsedMessage.Payload.Length > 0 || parsedMessage.Id is null)
            {
                throw new InvalidOperationException("Invalid message structure.");
            }

            return(new DataStopMessage(parsedMessage.Id));
        }
        private static InitializeConnectionMessage DeserializeInitConnMessage(
            GraphQLSocketMessage parsedMessage)
        {
            if (parsedMessage.HasPayload)
            {
                object parsed = Utf8GraphQLRequestParser.ParseJson(
                    parsedMessage.Payload);

                if (parsed is IReadOnlyDictionary <string, object> payload)
                {
                    return(new InitializeConnectionMessage(payload));
                }
            }
            return(new InitializeConnectionMessage(null));
        }
        private static bool TryDeserializeDataStartMessage(
            GraphQLSocketMessage parsedMessage,
            [NotNullWhen(true)] out OperationMessage?message)
        {
            if (parsedMessage.Payload.Length == 0 || parsedMessage.Id is null)
            {
                message = null;
                return(false);
            }

            IReadOnlyList <GraphQLRequest> batch = Parse(parsedMessage.Payload);

            message = new DataStartMessage(parsedMessage.Id, batch[0]);
            return(true);
        }
        private static bool TryDeserializeDataStartMessage(
            GraphQLSocketMessage parsedMessage,
            out OperationMessage message)
        {
            if (!parsedMessage.HasPayload)
            {
                message = null;
                return(false);
            }

            IReadOnlyList <GraphQLRequest> batch =
                Utf8GraphQLRequestParser.Parse(parsedMessage.Payload);

            message = new DataStartMessage(parsedMessage.Id, batch[0]);
            return(true);
        }
        private OperationMessage DeserializeMessage(GraphQLSocketMessage parsedMessage)
        {
            switch (parsedMessage.Type)
            {
            // case MessageTypes.Connection.Error:

            case MessageTypes.Connection.Accept:
                return(AcceptConnectionMessage.Default);

            case MessageTypes.Subscription.Data:
                return(DeserializeSubscriptionResultMessage(parsedMessage));

            // case MessageTypes.Subscription.Error:

            case MessageTypes.Subscription.Complete:
                return(DeserializeSubscriptionCompleteMessage(parsedMessage));

            default:
                return(KeepConnectionAliveMessage.Default);
            }
        }
        private OperationMessage DeserializeSubscriptionResultMessage(
            GraphQLSocketMessage parsedMessage)
        {
            if (parsedMessage.Id is null || !parsedMessage.HasPayload)
            {
                // TODO : resources
                throw new InvalidOperationException("Invalid message structure.");
            }

            if (_subscriptionManager.TryGetSubscription(
                    parsedMessage.Id,
                    out ISubscription? subscription))
            {
                IResultParser          parser        = subscription !.ResultParser;
                OperationResultBuilder resultBuilder =
                    OperationResultBuilder.New(parser.ResultType);
                parser.Parse(parsedMessage.Payload, resultBuilder);
                return(new DataResultMessage(parsedMessage.Id, resultBuilder));
            }

            return(KeepConnectionAliveMessage.Default);
        }
        private static bool TryParseMessage(
            ReadOnlySequence <byte> slice,
            out OperationMessage message)
        {
            ReadOnlySpan <byte> messageData;

            byte[] buffer = null;

            if (slice.IsSingleSegment)
            {
                messageData = slice.First.Span;
            }
            else
            {
                buffer = ArrayPool <byte> .Shared.Rent(1024 * 4);

                int buffered = 0;

                SequencePosition      position = slice.Start;
                ReadOnlyMemory <byte> memory;

                while (slice.TryGet(ref position, out memory, true))
                {
                    ReadOnlySpan <byte> span = memory.Span;
                    var bytesRemaining       = buffer.Length - buffered;

                    if (span.Length > bytesRemaining)
                    {
                        var next = ArrayPool <byte> .Shared.Rent(
                            buffer.Length * 2);

                        Buffer.BlockCopy(buffer, 0, next, 0, buffer.Length);
                        ArrayPool <byte> .Shared.Return(buffer);

                        buffer = next;
                    }

                    for (int i = 0; i < span.Length; i++)
                    {
                        buffer[buffered++] = span[i];
                    }
                }

                messageData = buffer;
                messageData = messageData.Slice(0, buffered);
            }

            try
            {
                if (messageData.Length == 0 ||
                    (messageData.Length == 1 && messageData[0] == default))
                {
                    message = null;
                    return(false);
                }

                GraphQLSocketMessage parsedMessage =
                    Utf8GraphQLRequestParser.ParseMessage(messageData);
                return(TryDeserializeMessage(parsedMessage, out message));
            }
            catch (SyntaxException)
            {
                message = null;
                return(false);
            }
            finally
            {
                if (buffer != null)
                {
                    ArrayPool <byte> .Shared.Return(buffer);
                }
            }
        }
        private static bool TryParseMessage(
            ReadOnlySequence <byte> slice,
            [NotNullWhen(true)] out OperationMessage?message)
        {
            ReadOnlySpan <byte> messageData;

            byte[]? buffer = null;

            if (slice.IsSingleSegment)
            {
                messageData = slice.First.Span;
            }
            else
            {
                buffer = ArrayPool <byte> .Shared.Rent(1024 * 4);

                var buffered = 0;

                SequencePosition position = slice.Start;
                while (slice.TryGet(ref position, out ReadOnlyMemory <byte> memory))
                {
                    ReadOnlySpan <byte> span = memory.Span;
                    var bytesRemaining       = buffer.Length - buffered;

                    if (span.Length > bytesRemaining)
                    {
                        // TODO : we need to ensure that the message size is restricted like on the
                        // http request.
                        byte[] next = ArrayPool <byte> .Shared.Rent(buffer.Length * 2);

                        Buffer.BlockCopy(buffer, 0, next, 0, buffer.Length);
                        ArrayPool <byte> .Shared.Return(buffer);

                        buffer = next;
                    }

                    for (var i = 0; i < span.Length; i++)
                    {
                        buffer[buffered++] = span[i];
                    }
                }

                messageData = buffer;
                messageData = messageData.Slice(0, buffered);
            }

            try
            {
                if (messageData.Length == 0 ||
                    (messageData.Length == 1 && messageData[0] == default))
                {
                    message = null;
                    return(false);
                }

                GraphQLSocketMessage parsedMessage = ParseMessage(messageData);
                return(TryDeserializeMessage(parsedMessage, out message));
            }
            catch (SyntaxException)
            {
                message = null;
                return(false);
            }
            finally
            {
                if (buffer is not null)
                {
                    ArrayPool <byte> .Shared.Return(buffer);
                }
            }
        }
 private static InitializeConnectionMessage DeserializeInitConnMessage(
     GraphQLSocketMessage parsedMessage) =>
 parsedMessage.Payload.Length > 0 &&
 ParseJson(parsedMessage.Payload) is IReadOnlyDictionary <string, object?> payload
        public bool TryParseMessage(
            ReadOnlySequence <byte> slice,
            out OperationMessage?message)
        {
            ReadOnlySpan <byte> messageData;

            byte[] buffer = Array.Empty <byte>();

            if (slice.IsSingleSegment)
            {
                messageData = slice.First.Span;
            }
            else
            {
                buffer = ArrayPool <byte> .Shared.Rent(_initialBufferSize);

                var buffered = 0;

                SequencePosition position = slice.Start;

                while (slice.TryGet(ref position, out ReadOnlyMemory <byte> memory))
                {
                    ReadOnlySpan <byte> span = memory.Span;
                    var bytesRemaining       = buffer.Length - buffered;

                    if (span.Length > bytesRemaining)
                    {
                        byte[] next = ArrayPool <byte> .Shared.Rent(buffer.Length * 2);

                        Buffer.BlockCopy(buffer, 0, next, 0, buffer.Length);
                        ArrayPool <byte> .Shared.Return(buffer);

                        buffer = next;
                    }

                    span.CopyTo(buffer.AsSpan().Slice(buffered));
                }

                messageData = buffer;
                messageData = messageData.Slice(0, buffered);
            }

            try
            {
                if (messageData.Length == 0 ||
                    (messageData.Length == 1 && messageData[0] == default))
                {
                    message = null;
                    return(false);
                }

                GraphQLSocketMessage parsedMessage = ParseMessage(messageData);
                message = DeserializeMessage(parsedMessage);
                return(true);
            }
            catch (SyntaxException)
            {
                message = null;
                return(false);
            }
            finally
            {
                if (buffer.Length > 0)
                {
                    ArrayPool <byte> .Shared.Return(buffer);
                }
            }
        }