Skip to content

Commit 30dcc49

Browse files
feat: Adds Data sequence support to Server and Client
This avoids a string encoding step and is backwards compatible
1 parent 93e8e79 commit 30dcc49

4 files changed

Lines changed: 166 additions & 168 deletions

File tree

Sources/GraphQLWS/Client.swift

Lines changed: 75 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -51,83 +51,90 @@ public actor Client<InitPayload: Equatable & Codable> {
5151
/// Listen and react to the provided async sequence of server messages. This function will block until the stream is completed.
5252
/// - Parameter incoming: The server message sequence that the client should react to.
5353
public func listen<A: AsyncSequence & Sendable>(to incoming: A) async throws
54-
where A.Element == String {
54+
where A.Element == Data {
5555
for try await message in incoming {
56-
// Detect and ignore error responses.
57-
if message.starts(with: "44") {
58-
// TODO: Determine what to do with returned error messages
56+
try await respond(to: message)
57+
}
58+
}
59+
60+
/// Listen and react to the provided async sequence of server messages. This function will block until the stream is completed.
61+
/// - Parameter incoming: The server message sequence that the client should react to.
62+
@available(*, deprecated, message: "Use `Data` sequence instead.")
63+
public func listen<A: AsyncSequence & Sendable>(to incoming: A) async throws
64+
where A.Element == String {
65+
for try await stringMessage in incoming {
66+
guard let message = stringMessage.data(using: .utf8) else {
67+
try await self.error(.invalidEncoding())
5968
return
6069
}
70+
try await respond(to: message)
71+
}
72+
}
6173

62-
guard let json = message.data(using: .utf8) else {
63-
try await error(.invalidEncoding())
74+
private func respond(to message: Data) async throws {
75+
let response: Response
76+
do {
77+
response = try decoder.decode(Response.self, from: message)
78+
} catch {
79+
try await self.error(.noType())
80+
return
81+
}
82+
83+
switch response.type {
84+
case .GQL_CONNECTION_ERROR:
85+
guard
86+
let connectionErrorResponse = try? decoder.decode(
87+
ConnectionErrorResponse.self,
88+
from: message
89+
)
90+
else {
91+
try await error(.invalidResponseFormat(messageType: .GQL_CONNECTION_ERROR))
6492
return
6593
}
66-
67-
let response: Response
68-
do {
69-
response = try decoder.decode(Response.self, from: json)
70-
} catch {
71-
try await self.error(.noType())
94+
try await onConnectionError(connectionErrorResponse, self)
95+
case .GQL_CONNECTION_ACK:
96+
guard
97+
let connectionAckResponse = try? decoder.decode(
98+
ConnectionAckResponse.self,
99+
from: message
100+
)
101+
else {
102+
try await error(.invalidResponseFormat(messageType: .GQL_CONNECTION_ERROR))
72103
return
73104
}
74-
75-
switch response.type {
76-
case .GQL_CONNECTION_ERROR:
77-
guard
78-
let connectionErrorResponse = try? decoder.decode(
79-
ConnectionErrorResponse.self,
80-
from: json
81-
)
82-
else {
83-
try await error(.invalidResponseFormat(messageType: .GQL_CONNECTION_ERROR))
84-
return
85-
}
86-
try await onConnectionError(connectionErrorResponse, self)
87-
case .GQL_CONNECTION_ACK:
88-
guard
89-
let connectionAckResponse = try? decoder.decode(
90-
ConnectionAckResponse.self,
91-
from: json
92-
)
93-
else {
94-
try await error(.invalidResponseFormat(messageType: .GQL_CONNECTION_ERROR))
95-
return
96-
}
97-
try await onConnectionAck(connectionAckResponse, self)
98-
case .GQL_CONNECTION_KEEP_ALIVE:
99-
guard
100-
let connectionKeepAliveResponse = try? decoder.decode(
101-
ConnectionKeepAliveResponse.self,
102-
from: json
103-
)
104-
else {
105-
try await error(.invalidResponseFormat(messageType: .GQL_CONNECTION_KEEP_ALIVE))
106-
return
107-
}
108-
try await onConnectionKeepAlive(connectionKeepAliveResponse, self)
109-
case .GQL_DATA:
110-
guard let nextResponse = try? decoder.decode(DataResponse.self, from: json) else {
111-
try await error(.invalidResponseFormat(messageType: .GQL_DATA))
112-
return
113-
}
114-
try await onData(nextResponse, self)
115-
case .GQL_ERROR:
116-
guard let errorResponse = try? decoder.decode(ErrorResponse.self, from: json) else {
117-
try await error(.invalidResponseFormat(messageType: .GQL_ERROR))
118-
return
119-
}
120-
try await onError(errorResponse, self)
121-
case .GQL_COMPLETE:
122-
guard let completeResponse = try? decoder.decode(CompleteResponse.self, from: json)
123-
else {
124-
try await error(.invalidResponseFormat(messageType: .GQL_COMPLETE))
125-
return
126-
}
127-
try await onComplete(completeResponse, self)
128-
default:
129-
try await error(.invalidType())
105+
try await onConnectionAck(connectionAckResponse, self)
106+
case .GQL_CONNECTION_KEEP_ALIVE:
107+
guard
108+
let connectionKeepAliveResponse = try? decoder.decode(
109+
ConnectionKeepAliveResponse.self,
110+
from: message
111+
)
112+
else {
113+
try await error(.invalidResponseFormat(messageType: .GQL_CONNECTION_KEEP_ALIVE))
114+
return
115+
}
116+
try await onConnectionKeepAlive(connectionKeepAliveResponse, self)
117+
case .GQL_DATA:
118+
guard let nextResponse = try? decoder.decode(DataResponse.self, from: message) else {
119+
try await error(.invalidResponseFormat(messageType: .GQL_DATA))
120+
return
121+
}
122+
try await onData(nextResponse, self)
123+
case .GQL_ERROR:
124+
guard let errorResponse = try? decoder.decode(ErrorResponse.self, from: message) else {
125+
try await error(.invalidResponseFormat(messageType: .GQL_ERROR))
126+
return
127+
}
128+
try await onError(errorResponse, self)
129+
case .GQL_COMPLETE:
130+
guard let completeResponse = try? decoder.decode(CompleteResponse.self, from: message)
131+
else {
132+
try await error(.invalidResponseFormat(messageType: .GQL_COMPLETE))
133+
return
130134
}
135+
try await onComplete(completeResponse, self)
136+
default:
137+
try await error(.invalidType())
131138
}
132139
}
133140

Sources/GraphQLWS/Server.swift

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -56,66 +56,74 @@ where
5656
/// Listen and react to the provided async sequence of client messages. This function will block until the stream is completed.
5757
/// - Parameter incoming: The client message sequence that the server should react to.
5858
public func listen<A: AsyncSequence & Sendable>(to incoming: A) async throws
59-
where A.Element == String {
59+
where A.Element == Data {
6060
for try await message in incoming {
61-
// Detect and ignore error responses.
62-
if message.starts(with: "44") {
63-
// TODO: Determine what to do with returned error messages
64-
return
65-
}
61+
try await respond(to: message)
62+
}
63+
}
6664

67-
guard let json = message.data(using: .utf8) else {
65+
/// Listen and react to the provided async sequence of client messages. This function will block until the stream is completed.
66+
/// - Parameter incoming: The client message sequence that the server should react to.
67+
@available(*, deprecated, message: "Use `Data` sequence instead.")
68+
public func listen<A: AsyncSequence & Sendable>(to incoming: A) async throws
69+
where A.Element == String {
70+
for try await stringMessage in incoming {
71+
guard let message = stringMessage.data(using: .utf8) else {
6872
try await error(.invalidEncoding())
6973
return
7074
}
7175

72-
let request: Request
73-
do {
74-
request = try decoder.decode(Request.self, from: json)
75-
} catch {
76-
try await self.error(.noType())
76+
try await respond(to: message)
77+
}
78+
}
79+
80+
private func respond(to message: Data) async throws {
81+
let request: Request
82+
do {
83+
request = try decoder.decode(Request.self, from: message)
84+
} catch {
85+
try await self.error(.noType())
86+
return
87+
}
88+
89+
// handle incoming message
90+
switch request.type {
91+
case .GQL_CONNECTION_INIT:
92+
guard
93+
let connectionInitRequest = try? decoder.decode(
94+
ConnectionInitRequest<InitPayload>.self,
95+
from: message
96+
)
97+
else {
98+
try await error(.invalidRequestFormat(messageType: .GQL_CONNECTION_INIT))
7799
return
78100
}
79-
80-
// handle incoming message
81-
switch request.type {
82-
case .GQL_CONNECTION_INIT:
83-
guard
84-
let connectionInitRequest = try? decoder.decode(
85-
ConnectionInitRequest<InitPayload>.self,
86-
from: json
87-
)
88-
else {
89-
try await error(.invalidRequestFormat(messageType: .GQL_CONNECTION_INIT))
90-
return
91-
}
92-
try await onConnectionInit(connectionInitRequest, messenger)
93-
case .GQL_START:
94-
guard let startRequest = try? decoder.decode(StartRequest.self, from: json) else {
95-
try await error(.invalidRequestFormat(messageType: .GQL_START))
96-
return
97-
}
98-
try await onStart(startRequest, messenger)
99-
case .GQL_STOP:
100-
guard let stopRequest = try? decoder.decode(StopRequest.self, from: json) else {
101-
try await error(.invalidRequestFormat(messageType: .GQL_STOP))
102-
return
103-
}
104-
try await onStop(stopRequest)
105-
case .GQL_CONNECTION_TERMINATE:
106-
guard
107-
let connectionTerminateRequest = try? decoder.decode(
108-
ConnectionTerminateRequest.self,
109-
from: json
110-
)
111-
else {
112-
try await error(.invalidRequestFormat(messageType: .GQL_CONNECTION_TERMINATE))
113-
return
114-
}
115-
try await onConnectionTerminate(connectionTerminateRequest, messenger)
116-
default:
117-
try await error(.invalidType())
101+
try await onConnectionInit(connectionInitRequest, messenger)
102+
case .GQL_START:
103+
guard let startRequest = try? decoder.decode(StartRequest.self, from: message) else {
104+
try await error(.invalidRequestFormat(messageType: .GQL_START))
105+
return
106+
}
107+
try await onStart(startRequest, messenger)
108+
case .GQL_STOP:
109+
guard let stopRequest = try? decoder.decode(StopRequest.self, from: message) else {
110+
try await error(.invalidRequestFormat(messageType: .GQL_STOP))
111+
return
112+
}
113+
try await onStop(stopRequest)
114+
case .GQL_CONNECTION_TERMINATE:
115+
guard
116+
let connectionTerminateRequest = try? decoder.decode(
117+
ConnectionTerminateRequest.self,
118+
from: message
119+
)
120+
else {
121+
try await error(.invalidRequestFormat(messageType: .GQL_CONNECTION_TERMINATE))
122+
return
118123
}
124+
try await onConnectionTerminate(connectionTerminateRequest, messenger)
125+
default:
126+
try await error(.invalidType())
119127
}
120128
}
121129

0 commit comments

Comments
 (0)