Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FSharp.Data.GraphQL.Server.AspNetCore #430

Merged
merged 102 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
45a7d48
ignoring the whole .vscode/ folder
valbers Mar 3, 2023
c3f1a48
introducing FSharp.Data.GraphQL.Server.AppInfrastructure
valbers Mar 4, 2023
83a9198
moving Server.AppInfrastructure near to other projs in sln
valbers Mar 5, 2023
9e88ac9
Apply suggestions from code review
valbers Mar 5, 2023
d322439
correctly calling "GetRequiredService<T>"
valbers Mar 5, 2023
bf6bd6b
using standardized namespace for chat-app sample
valbers Mar 5, 2023
c63ef2d
renamed sample chat-app to standardized proj name
valbers Mar 5, 2023
639f1e2
fixing build (related to https://github.com/dotnet/fsharp/issues/12839 )
valbers Mar 5, 2023
925873f
fixing HttpHandler: the "errors" property shouldn't be there if no errs
valbers Mar 11, 2023
6fcbf71
automatically updating chat-app/client/TestData/schema-snapshot.json
valbers Mar 11, 2023
d72500a
Apply commit suggestion
valbers Mar 11, 2023
5226c16
Apply review suggestion
valbers Mar 11, 2023
13c495e
trying to use more structured logging (and fixing code)
valbers Mar 11, 2023
f3e85cc
not calling .ToString() on objects that go into structured logging
valbers Mar 12, 2023
fdc5289
Using more concise Task.WaitAll
valbers Mar 19, 2023
34471ab
ChatAppServer -> ChatServer
valbers Mar 18, 2023
e427f55
build.fsx: intr. helper func "updateIntrospectionFile"
valbers Mar 18, 2023
ea5be34
renamed AppInfrastructure to AspNetCore
valbers Mar 19, 2023
bf672ca
removing logger.IsEnabled where it is superfluous
valbers Mar 19, 2023
c390676
Using better suited LogError overload and are shorter error message
valbers Mar 19, 2023
d8a5619
CancellationToken.None instead of new CancellationToken()
valbers Mar 19, 2023
a2b271e
Using a better suited logger.LogError overload and better phrasing
valbers Mar 19, 2023
70ba89a
chat-app sample: moved FakePersistence to own file
valbers Mar 19, 2023
d3d737f
chat-app sample: moved exception-related functions to own module
valbers Mar 19, 2023
f34167e
Server.AspNetCore: removing now superfluous "executor" parameters
valbers Mar 19, 2023
2d516b5
Server.AspNetCore: trying to improve readability by changing func sig.
valbers Mar 19, 2023
e138939
Server.AspNetCore: removed the `safe_` prefix in order to avoid confus.
valbers Mar 19, 2023
89207d0
Server.AspNetCore renaming tests to be more explicit about what's tested
valbers Mar 19, 2023
9f8cc2e
added Server.AspnetCore to github workflows
valbers Mar 19, 2023
a790882
Server.AspNetCore: trying to simplify module declaration
valbers Mar 19, 2023
b66a0f6
Server.AspNetCore: complement to my last commit (identation)
valbers Mar 19, 2023
4b2937a
Update samples/chat-app/server/Exceptions.fs
valbers Mar 19, 2023
619bae2
Authors += ", valbers"
valbers Mar 19, 2023
fefe03b
Using Task.WhenAll
valbers Mar 19, 2023
4d2a8e5
Added TODO comment related to string allocation
valbers Mar 19, 2023
ce386c8
Added TODO comment regarding string allocation
valbers Mar 19, 2023
996cfe5
Using better suited logger.LogError overload
valbers Mar 19, 2023
447af9a
Using Task.WhenAll again (instead of Async.AwaitTask + Async.RunSynch…
valbers Mar 19, 2023
7725b7b
Making code better readable
valbers Mar 19, 2023
a05eb43
Revert "Using Task.WhenAll again (instead of Async.AwaitTask + Async.…
valbers Mar 19, 2023
a1ef59e
Revert "Using Task.WhenAll"
valbers Mar 19, 2023
28c386a
Extracted the target frameworks into a single file
xperiandri Feb 9, 2024
7128a68
Suppressed the warning about the `WebClient` in the `Build` project
xperiandri Feb 9, 2024
83f1734
Added constants for F# optional type names
Oct 18, 2023
b37b993
Fixed wrong condition on checking if dictionary is mutable
Oct 18, 2023
bb6c21e
Implemented converting `Option` and `ValueOption` returned from scala…
Oct 18, 2023
b1e180b
Implemented check that ValueOption returned from scalar coercion is a…
Oct 18, 2023
fe8712c
Added value object tests
xperiandri Feb 10, 2024
96dbd31
Adding HttpContext as parameter to root factory
valbers Feb 14, 2024
1422288
Merge branch 'dev' into introduce-graphql-transport-ws
valbers Feb 14, 2024
9fe5f2e
Adjusting ...Server.AspNetCore's branch code to latest `dev` stage
valbers Feb 19, 2024
a616a9f
Replacing locally maintained "Rop" with FsToolkit.ErrorHandling in...
valbers Feb 24, 2024
c28251b
Complement to my last commit (removed commented out code)
valbers Feb 24, 2024
9e4f942
Also in GraphQLWebsocketMiddleware using FsToolkit.ErrorHandling...
valbers Feb 25, 2024
566c848
new HttpHandler: fixing error handling on "applyPlanExecutionResult"
valbers Feb 26, 2024
00c1a29
Extracted the target frameworks into a single file
xperiandri Feb 9, 2024
073f980
Merge branch 'dev' into introduce-graphql-transport-ws
valbers Feb 26, 2024
ce0d437
.Server.AspNetCore: adding either package ref or proj. ref. according...
valbers Feb 26, 2024
18a71d5
.Server.AspNetCore: added targets "pack" and "push" for this new project
valbers Feb 26, 2024
b95ebf2
.Server.AspNetCore: added some documentation to functions.
valbers Feb 26, 2024
f6dd828
.Server.AspNetCore: correctly parsing variable value to JsonElement
valbers Feb 28, 2024
7216ece
chat-app sample: adapted code to new error handling and added proj to ..
valbers Feb 28, 2024
e5891f1
Update README.md
valbers Mar 5, 2024
89601ac
.Samples.ChatApp: removed superfluous `Label` attr. from ItemGroup
valbers Mar 5, 2024
65c7c52
.Samples.ChatApp: launchSettings.json: commandNames according to temp…
valbers Mar 5, 2024
3af6a11
Samples.StarWarsApi.fsproj : sorting Project References by name
valbers Mar 5, 2024
1552bd4
Using interpolated strings instead of sprintf at many places
valbers Mar 5, 2024
5c51714
.Samples.ChatApp: better name for logger
valbers Mar 5, 2024
51851ea
.Server.AspNetCore: formatted code with Fantomas
valbers Mar 6, 2024
318901d
Removed superfluous JsonOptions configuration
valbers Mar 6, 2024
390e893
samples: removing KestrelServerOptions.AllowSynchronousIO <- true...
valbers Mar 6, 2024
d6f9611
samples/chat-app: undoing wrong changes to launchSetting.json
valbers Mar 6, 2024
9b29037
.IntegrationTests.Server: removed some now superfluous settings
valbers Mar 6, 2024
017cdd7
.Server.AspNetCore/README.md: updated the sample snippet to...
valbers Mar 6, 2024
afa2b7a
Added ability to get idented `JsonSerializerOptions`
xperiandri Mar 10, 2024
dfdb263
Moved chat-app near to starwars-api
xperiandri Mar 10, 2024
7c2ad5f
Aligned StarWars API to ChatApp
xperiandri Mar 10, 2024
2888db6
Aligned code style
xperiandri Mar 10, 2024
b43c29d
Consolidated common logic in `FSharp.Data.GraphQL.Server.AspNetCore` …
xperiandri Mar 10, 2024
f482a98
Added GraphQL playgounds to chat-app
xperiandri Mar 10, 2024
41e5ec3
Fixed constant like values naming style
xperiandri Mar 10, 2024
379c354
Fixed tests
xperiandri Mar 10, 2024
fc50670
Fixed `FSharp.Data.GraphQL.Server.AspNetCore` tests
xperiandri Mar 10, 2024
e65e943
Fixed integration tests
xperiandri Mar 10, 2024
1281c27
Added missing `FSharp.Data.GraphQL.Server.AspNetCore` package referen…
xperiandri Mar 10, 2024
a3ce3c6
Set appropriate logging level
xperiandri Mar 11, 2024
8e4943d
Moved Giraffe request handlers out of the GraphQL handler
xperiandri Mar 11, 2024
ee93b7f
Fixed integration tests
xperiandri Mar 11, 2024
a0c464d
Implemented request cancellation passing inside GraphQL execution
xperiandri Mar 11, 2024
a6ee3e2
Set GraphQL request body error logging to the warning level and moved…
xperiandri Mar 17, 2024
38fed3c
Migrated to ValueOption, IOptions<> and simplified WebSocket handling…
xperiandri Mar 17, 2024
0cfd55c
InvalidMessageException -> InvalidWebsocketMessageException
valbers Mar 17, 2024
cd3b1ce
.AspNetCore: using static logger serializer options and fixed typo:
valbers Mar 17, 2024
c566724
Revert ".AspNetCore: using static logger serializer options and fixed…
valbers Mar 20, 2024
418aa7a
.AspNetCore: fixed typo: Idented -> Indented
valbers Mar 20, 2024
c9951c3
.WebsocketMiddleware: logging with logger instead of `printfn`
valbers Mar 20, 2024
855d5a7
.WebsocketMiddleware: logging it when subscriber already exists
valbers Mar 20, 2024
5dde6e9
Aligned error and logging messages, simplified WebSockets logging code
xperiandri Mar 21, 2024
bf6ab98
...WebsocketMiddleware.fs: improved warning logging
valbers Mar 21, 2024
4b16c87
.WebsocketMiddleware: better WS message deserialization exception handl.
valbers Mar 20, 2024
e7cfeff
chat-app: naming ObjectDef variables according to implicit convention
valbers Mar 21, 2024
f5f5294
Made error response static and fixed capital in error
xperiandri Mar 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open System.Runtime.CompilerServices
open System.Text.Json
open Microsoft.AspNetCore.Http
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Options

open FSharp.Core
open FsToolkit.ErrorHandling
Expand All @@ -26,7 +27,7 @@ type HttpContext with
/// </returns>
[<Extension>]
member ctx.TryBindJsonAsync<'T>(expectedJson) = taskResult {
let serializerOptions = ctx.RequestServices.GetRequiredService<IGraphQLOptions>().SerializerOptions
let serializerOptions = ctx.RequestServices.GetRequiredService<IOptions<IGraphQLOptions>>().Value.SerializerOptions
let request = ctx.Request

try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open System.Threading.Tasks
open Microsoft.AspNetCore.Http
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Logging
open Microsoft.Extensions.Options

open FsToolkit.ErrorHandling
open Giraffe
Expand All @@ -20,6 +21,8 @@ type HttpHandler = HttpFunc -> HttpContext -> HttpFuncResult

module HttpHandlers =

let [<Literal>] internal IdentedOptionsName = "Idented"

let rec private moduleType = getModuleType <@ moduleType @>

let ofTaskIResult ctx (taskRes: Task<IResult>) : HttpFuncResult = task {
Expand All @@ -38,12 +41,12 @@ module HttpHandlers =

let logger = sp.CreateLogger moduleType

let options = sp.GetRequiredService<GraphQLOptions<'Root>>()
let options = sp.GetRequiredService<IOptionsMonitor<GraphQLOptions<'Root>>>()

let toResponse { DocumentId = documentId; Content = content; Metadata = metadata } =

let serializeIdented value =
let jsonSerializerOptions = options.GetSerializerOptionsIdented()
let jsonSerializerOptions = options.Get(IdentedOptionsName).SerializerOptions
JsonSerializer.Serialize(value, jsonSerializerOptions)

match content with
Expand Down Expand Up @@ -243,7 +246,7 @@ module HttpHandlers =
variables
|> Option.iter (fun v -> logger.LogTrace($"GraphQL variables:{Environment.NewLine}{{variables}}", v))

let root = options.RootFactory ctx
let root = options.CurrentValue.RootFactory ctx

let! result =
Async.StartAsTask(
Expand All @@ -259,7 +262,7 @@ module HttpHandlers =
Task.FromResult None
else
taskResult {
let executor = options.SchemaExecutor
let executor = options.CurrentValue.SchemaExecutor
match! checkOperationType ctx with
| IntrospectionQuery optionalAstDocument -> return! executeIntrospectionQuery executor optionalAstDocument
| OperationQuery content -> return! executeOperation executor content
Expand Down
11 changes: 2 additions & 9 deletions src/FSharp.Data.GraphQL.Server.AspNetCore/GraphQLOptions.fs
valbers marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ open System.Text.Json
open System.Threading.Tasks
open Microsoft.AspNetCore.Http

type PingHandler = IServiceProvider -> JsonDocument option -> Task<JsonDocument option>
type PingHandler = IServiceProvider -> JsonDocument voption -> Task<JsonDocument voption>

type GraphQLTransportWSOptions = {
EndpointUrl : string
ConnectionInitTimeoutInMs : int
CustomPingHandler : PingHandler option
CustomPingHandler : PingHandler voption
}

type IGraphQLOptions =
abstract member SerializerOptions : JsonSerializerOptions
abstract member WebsocketOptions : GraphQLTransportWSOptions
abstract member GetSerializerOptionsIdented : unit -> JsonSerializerOptions

type GraphQLOptions<'Root> = {
SchemaExecutor : Executor<'Root>
Expand All @@ -26,12 +25,6 @@ type GraphQLOptions<'Root> = {
WebsocketOptions : GraphQLTransportWSOptions
} with

member options.GetSerializerOptionsIdented () =
let options = JsonSerializerOptions (options.SerializerOptions)
options.WriteIndented <- true
options

interface IGraphQLOptions with
member this.SerializerOptions = this.SerializerOptions
member this.WebsocketOptions = this.WebsocketOptions
member this.GetSerializerOptionsIdented () = this.GetSerializerOptionsIdented ()
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ open System.Threading.Tasks
open Microsoft.AspNetCore.Http
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.Logging
open Microsoft.Extensions.Options
open FsToolkit.ErrorHandling

open FSharp.Data.GraphQL
Expand All @@ -22,18 +23,24 @@ type GraphQLWebSocketMiddleware<'Root>
applicationLifetime : IHostApplicationLifetime,
serviceProvider : IServiceProvider,
logger : ILogger<GraphQLWebSocketMiddleware<'Root>>,
options : GraphQLOptions<'Root>
options : IOptions<GraphQLOptions<'Root>>
) =

let options = options.Value
let serializerOptions = options.SerializerOptions
let pingHandler = options.WebsocketOptions.CustomPingHandler
let endpointUrl = PathString options.WebsocketOptions.EndpointUrl
let connectionInitTimeout = options.WebsocketOptions.ConnectionInitTimeoutInMs

let serializeServerMessage (jsonSerializerOptions : JsonSerializerOptions) (serverMessage : ServerMessage) = task {
let raw =
match serverMessage with
| ConnectionAck -> { Id = None; Type = "connection_ack"; Payload = None }
| ServerPing -> { Id = None; Type = "ping"; Payload = None }
| ServerPong p -> { Id = None; Type = "pong"; Payload = p |> Option.map CustomResponse }
| Next (id, payload) -> { Id = Some id; Type = "next"; Payload = Some <| ExecutionResult payload }
| Complete id -> { Id = Some id; Type = "complete"; Payload = None }
| Error (id, errMsgs) -> { Id = Some id; Type = "error"; Payload = Some <| ErrorMessages errMsgs }
| ConnectionAck -> { Id = ValueNone; Type = "connection_ack"; Payload = ValueNone }
| ServerPing -> { Id = ValueNone; Type = "ping"; Payload = ValueNone }
| ServerPong p -> { Id = ValueNone; Type = "pong"; Payload = p |> ValueOption.map CustomResponse }
| Next (id, payload) -> { Id = ValueSome id; Type = "next"; Payload = ValueSome <| ExecutionResult payload }
| Complete id -> { Id = ValueSome id; Type = "complete"; Payload = ValueNone }
| Error (id, errMsgs) -> { Id = ValueSome id; Type = "error"; Payload = ValueSome <| ErrorMessages errMsgs }
return JsonSerializer.Serialize (raw, jsonSerializerOptions)
}

Expand Down Expand Up @@ -83,10 +90,10 @@ type GraphQLWebSocketMiddleware<'Root>
|> Array.ofSeq
|> System.Text.Encoding.UTF8.GetString
if String.IsNullOrWhiteSpace message then
return None
return ValueNone
else
let! result = message |> deserializeClientMessage serializerOptions
return Some result
return ValueSome result
}

let sendMessageViaSocket (jsonSerializerOptions) (socket : WebSocket) (message : ServerMessage) : Task = task {
Expand Down Expand Up @@ -137,15 +144,7 @@ type GraphQLWebSocketMiddleware<'Root>
let tryToGracefullyCloseSocketWithDefaultBehavior =
tryToGracefullyCloseSocket (WebSocketCloseStatus.NormalClosure, "Normal Closure")

let handleMessages
(cancellationToken : CancellationToken)
(httpContext : HttpContext)
(serializerOptions : JsonSerializerOptions)
(executor : Executor<'Root>)
(root : HttpContext -> 'Root)
(pingHandler : PingHandler option)
(socket : WebSocket)
=
let handleMessages (cancellationToken : CancellationToken) (httpContext : HttpContext) (socket : WebSocket) : Task =
let subscriptions = new Dictionary<SubscriptionId, SubscriptionUnsubscriber * OnUnsubscribeAction> ()
// ---------->
// Helpers -->
Expand Down Expand Up @@ -204,8 +203,8 @@ type GraphQLWebSocketMiddleware<'Root>

let getStrAddendumOfOptionalPayload optionalPayload =
optionalPayload
|> Option.map (fun payloadStr -> $" with payload: %A{payloadStr}")
|> Option.defaultWith (fun () -> "")
|> ValueOption.map (fun payloadStr -> $" with payload: %A{payloadStr}")
|> ValueOption.defaultWith (fun () -> "")

let logMsgReceivedWithOptionalPayload optionalPayload (msgAsStr : string) =
logger.LogTrace ("{message}{messageaddendum}", msgAsStr, (optionalPayload |> getStrAddendumOfOptionalPayload))
Expand All @@ -226,13 +225,13 @@ type GraphQLWebSocketMiddleware<'Root>
let! receivedMessage = rcv ()
match receivedMessage with
| Result.Error failureMsgs ->
"InvalidMessage" |> logMsgReceivedWithOptionalPayload None
"InvalidMessage" |> logMsgReceivedWithOptionalPayload ValueNone
match failureMsgs with
| InvalidMessage (code, explanation) -> do! socket.CloseAsync (enum code, explanation, CancellationToken.None)
| Ok maybeMsg ->
match maybeMsg with
| None -> logger.LogTrace ("Websocket socket received empty message! (socket state = {socketstate})", socket.State)
| Some msg ->
| ValueNone -> logger.LogTrace ("Websocket socket received empty message! (socket state = {socketstate})", socket.State)
| ValueSome msg ->
match msg with
| ConnectionInit p ->
"ConnectionInit" |> logMsgReceivedWithOptionalPayload p
Expand All @@ -245,10 +244,10 @@ type GraphQLWebSocketMiddleware<'Root>
| ClientPing p ->
"ClientPing" |> logMsgReceivedWithOptionalPayload p
match pingHandler with
| Some func ->
| ValueSome func ->
let! customP = p |> func serviceProvider
do! ServerPong customP |> sendMsg
| None -> do! ServerPong p |> sendMsg
| ValueNone -> do! ServerPong p |> sendMsg
| ClientPong p -> "ClientPong" |> logMsgReceivedWithOptionalPayload p
| Subscribe (id, query) ->
"Subscribe" |> logMsgWithIdReceived id
Expand All @@ -262,7 +261,8 @@ type GraphQLWebSocketMiddleware<'Root>
else
let variables = query.Variables |> Skippable.toOption
let! planExecutionResult =
executor.AsyncExecute (query.Query, root (httpContext), ?variables = variables)
let root = options.RootFactory httpContext
options.SchemaExecutor.AsyncExecute (query.Query, root, ?variables = variables)
do! planExecutionResult |> applyPlanExecutionResult id socket
| ClientComplete id ->
"ClientComplete" |> logMsgWithIdReceived id
Expand All @@ -282,14 +282,10 @@ type GraphQLWebSocketMiddleware<'Root>
// <-- Main
// <--------

let waitForConnectionInitAndRespondToClient
(serializerOptions : JsonSerializerOptions)
(connectionInitTimeoutInMs : int)
(socket : WebSocket)
: TaskResult<unit, string> =
taskResult {
let waitForConnectionInitAndRespondToClient (socket : WebSocket) : TaskResult<unit, string> =
task {
let timerTokenSource = new CancellationTokenSource ()
timerTokenSource.CancelAfter (connectionInitTimeoutInMs)
timerTokenSource.CancelAfter connectionInitTimeout
valbers marked this conversation as resolved.
Show resolved Hide resolved
let detonationRegistration =
timerTokenSource.Token.Register (fun _ ->
socket
Expand All @@ -302,14 +298,14 @@ type GraphQLWebSocketMiddleware<'Root>
logger.LogDebug ("Waiting for ConnectionInit...")
let! receivedMessage = receiveMessageViaSocket (CancellationToken.None) serializerOptions socket
match receivedMessage with
| Ok (Some (ConnectionInit _)) ->
| Ok (ValueSome (ConnectionInit _)) ->
logger.LogDebug ("Valid connection_init received! Responding with ACK!")
detonationRegistration.Unregister () |> ignore
do!
ConnectionAck
|> sendMessageViaSocket serializerOptions socket
return true
| Ok (Some (Subscribe _)) ->
| Ok (ValueSome (Subscribe _)) ->
do!
socket
|> tryToGracefullyCloseSocket (enum CustomWebSocketStatus.Unauthorized, "Unauthorized")
Expand All @@ -327,46 +323,30 @@ type GraphQLWebSocketMiddleware<'Root>
)
if (not timerTokenSource.Token.IsCancellationRequested) then
if connectionInitSucceeded then
return ()
return Ok ()
else
return!
Result.Error
<| "ConnectionInit failed (not because of timeout)"
return Result.Error ("ConnectionInit failed (not because of timeout)")
else
return! Result.Error <| "ConnectionInit timeout"
return Result.Error <| "ConnectionInit timeout"
}

member __.InvokeAsync (ctx : HttpContext) = task {
if not (ctx.Request.Path = PathString (options.WebsocketOptions.EndpointUrl)) then
if not (ctx.Request.Path = endpointUrl) then
do! next.Invoke (ctx)
else if ctx.WebSockets.IsWebSocketRequest then
use! socket = ctx.WebSockets.AcceptWebSocketAsync ("graphql-transport-ws")
let! connectionInitResult =
socket
|> waitForConnectionInitAndRespondToClient options.SerializerOptions options.WebsocketOptions.ConnectionInitTimeoutInMs
socket |> waitForConnectionInitAndRespondToClient
match connectionInitResult with
| Result.Error errMsg -> logger.LogWarning ("{warningmsg}", ($"%A{errMsg}"))
| Result.Error errMsg -> logger.LogWarning ("{warningmsg}", errMsg)
| Ok _ ->
let longRunningCancellationToken =
(CancellationTokenSource
.CreateLinkedTokenSource(ctx.RequestAborted, applicationLifetime.ApplicationStopping)
.Token)
longRunningCancellationToken.Register (fun _ ->
socket
|> tryToGracefullyCloseSocketWithDefaultBehavior
|> Async.AwaitTask
|> Async.RunSynchronously)
|> ignore
let safe_HandleMessages = handleMessages longRunningCancellationToken
longRunningCancellationToken.Register (fun _ -> (socket |> tryToGracefullyCloseSocketWithDefaultBehavior).Wait()) |> ignore
try
do!
socket
|> safe_HandleMessages
ctx
options.SerializerOptions
options.SchemaExecutor
options.RootFactory
options.WebsocketOptions.CustomPingHandler
do! socket |> handleMessages longRunningCancellationToken ctx
with ex ->
logger.LogError (ex, "Cannot handle Websocket message.")
else
Expand Down
12 changes: 6 additions & 6 deletions src/FSharp.Data.GraphQL.Server.AspNetCore/Messages.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ type SubscriptionUnsubscriber = IDisposable
type OnUnsubscribeAction = SubscriptionId -> unit
type SubscriptionsDict = IDictionary<SubscriptionId, SubscriptionUnsubscriber * OnUnsubscribeAction>

type RawMessage = { Id : string option; Type : string; Payload : JsonDocument option }
type RawMessage = { Id : string voption; Type : string; Payload : JsonDocument voption }

type ServerRawPayload =
| ExecutionResult of Output
| ErrorMessages of NameValueLookup list
| CustomResponse of JsonDocument

type RawServerMessage = { Id : string option; Type : string; Payload : ServerRawPayload option }
type RawServerMessage = { Id : string voption; Type : string; Payload : ServerRawPayload voption }

type ClientMessage =
| ConnectionInit of payload : JsonDocument option
| ClientPing of payload : JsonDocument option
| ClientPong of payload : JsonDocument option
| ConnectionInit of payload : JsonDocument voption
| ClientPing of payload : JsonDocument voption
| ClientPong of payload : JsonDocument voption
| Subscribe of id : string * query : GQLRequestContent
| ClientComplete of id : string

Expand All @@ -32,7 +32,7 @@ type ClientMessageProtocolFailure = InvalidMessage of code : int * explanation :
type ServerMessage =
| ConnectionAck
| ServerPing
| ServerPong of JsonDocument option
| ServerPong of JsonDocument voption
| Next of id : string * payload : Output
| Error of id : string * err : NameValueLookup list
| Complete of id : string
Expand Down
Loading