Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 6 additions & 4 deletions Runtime/SimpleGraphQL/GraphQLClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,11 @@ public async Task<bool> SubscribeAsync(
string id,
string authToken = null,
Dictionary<string, object> variables = null,
Dictionary<string, string> headers = null
Dictionary<string, string> headers = null,
HttpUtils.IWebSocket ws = null
)
{
return await SubscribeAsync(query, id, AuthScheme, authToken, variables, headers);
return await SubscribeAsync(query, id, AuthScheme, authToken, variables, headers, ws);
}

public async Task<bool> SubscribeAsync(
Expand All @@ -146,7 +147,8 @@ public async Task<bool> SubscribeAsync(
string authScheme = "Bearer",
string authToken = null,
Dictionary<string, object> variables = null,
Dictionary<string, string> headers = null
Dictionary<string, string> headers = null,
HttpUtils.IWebSocket ws = null
)
{
if(query.OperationType != OperationType.Subscription)
Expand All @@ -171,7 +173,7 @@ public async Task<bool> SubscribeAsync(
if(!HttpUtils.IsWebSocketReady())
{
// Prepare the socket before continuing.
bool connectionSuccessful = await HttpUtils.WebSocketConnect(Endpoint, authScheme, authToken, "graphql-ws", headers);
bool connectionSuccessful = await HttpUtils.WebSocketConnect(Endpoint, authScheme, authToken, "graphql-ws", headers, ws);
if(!connectionSuccessful)
{
return false;
Expand Down
97 changes: 94 additions & 3 deletions Runtime/SimpleGraphQL/HttpUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,90 @@ public enum SubscriptionError
[PublicAPI]
public static class HttpUtils
{
private static ClientWebSocket _webSocket;
public interface IWebSocket : IDisposable
{
interface ISocketOptions
{
public void AddSubProtocol(string protocol);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think public is needed inside the interface 🙂

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


public void SetRequestHeader(string v1, string v2);
}

WebSocketState State { get; }
ISocketOptions Options { get; }
WebSocketCloseStatus? CloseStatus { get; }

Task ConnectAsync(Uri uri, CancellationToken none);
Task SendAsync(ArraySegment<byte> arraySegment, WebSocketMessageType text, bool v, CancellationToken ct);
Task CloseAsync(WebSocketCloseStatus normalClosure, string v, CancellationToken ct);
Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken ct);
}


public class ClientWebSocketOptionsWrapper : IWebSocket.ISocketOptions
{
ClientWebSocketOptions options;

public ClientWebSocketOptionsWrapper(ClientWebSocketOptions options)
{
this.options = options;
}

public void AddSubProtocol(string protocol)
{
options.AddSubProtocol(protocol);
}

public void SetRequestHeader(string v1, string v2)
{
options.SetRequestHeader(v1, v2);
}
}


public class ClientWebSocketWrapper : IWebSocket
{
ClientWebSocket ws;

public ClientWebSocketWrapper()
{
ws = new ClientWebSocket();
}

WebSocketState IWebSocket.State => ws.State;

public WebSocketCloseStatus? CloseStatus => ws.CloseStatus;

public IWebSocket.ISocketOptions Options => new ClientWebSocketOptionsWrapper(ws.Options);


public Task ConnectAsync(Uri uri, CancellationToken ct)
{
return ws.ConnectAsync(uri, ct);
}

public Task SendAsync(ArraySegment<byte> arraySegment, WebSocketMessageType text, bool v, CancellationToken ct)
{
return ws.SendAsync(arraySegment, text, v, ct);
}

public Task CloseAsync(WebSocketCloseStatus normalClosure, string v, CancellationToken ct)
{
return ws.CloseAsync(normalClosure, v, ct);
}

public Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken ct)
{
return ws.ReceiveAsync(buffer, ct);
}

public void Dispose()
{
ws.Dispose();
}
}

private static IWebSocket _webSocket;

/// <summary>
/// Called when the websocket receives subscription data.
Expand Down Expand Up @@ -119,13 +202,21 @@ public static async Task<bool> WebSocketConnect(
string authScheme = "Bearer",
string authToken = null,
string protocol = "graphql-ws",
Dictionary<string, string> headers = null
Dictionary<string, string> headers = null,
IWebSocket ws = null
)
{
url = url.Replace("http", "ws");

Uri uri = new Uri(url);
_webSocket = new ClientWebSocket();
if (ws != null)
{
_webSocket = ws;
}
else
{
_webSocket = new ClientWebSocketWrapper();
}
_webSocket.Options.AddSubProtocol(protocol);

if(authToken != null)
Expand Down