Skip to content

Commit 47ebc0b

Browse files
Server/Client now wrap messenger
Client gets better message sending methods
1 parent 77b975d commit 47ebc0b

File tree

3 files changed

+122
-80
lines changed

3 files changed

+122
-80
lines changed

Sources/GraphQLWS/Client.swift

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// Copyright (c) 2021 PassiveLogic, Inc.
22

33
import Foundation
4+
import GraphQL
45

56
/// Adds client-side [graphql-ws protocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md)
67
/// support, namely parsing and adding callbacks for each type of server respose.
78
class Client {
9+
let messenger: Messenger
10+
811
let onMessage: (String) -> Void
912
let onConnectionError: (ConnectionErrorResponse) -> Void
1013
let onConnectionAck: (ConnectionAckResponse) -> Void
@@ -13,37 +16,41 @@ class Client {
1316
let onError: (ErrorResponse) -> Void
1417
let onComplete: (CompleteResponse) -> Void
1518

19+
let encoder = GraphQLJSONEncoder()
1620
let decoder = JSONDecoder()
1721

1822
/// Create a new client.
1923
///
2024
/// - Parameters:
21-
/// - onMessage: callback run on receipt of any message
22-
/// - onConnectionError: callback run on receipt of a `connection_error` message
23-
/// - onConnectionAck: callback run on receipt of a `connection_ack` message
24-
/// - onData: callback run on receipt of a `data` message
25-
/// - onError: callback run on receipt of an `error` message
26-
/// - onComplete: callback run on receipt of a `complete` message
25+
/// - messenger: The messenger to bind the client to.
26+
/// - onConnectionError: Callback run on receipt of a `connection_error` message
27+
/// - onConnectionAck: Callback run on receipt of a `connection_ack` message
28+
/// - onData: Callback run on receipt of a `data` message
29+
/// - onError: Callback run on receipt of an `error` message
30+
/// - onComplete: Callback run on receipt of a `complete` message
31+
/// - onMessage: Callback run on receipt of any message
2732
init(
28-
onMessage: @escaping (String) -> Void = { _ in () },
33+
messenger: Messenger,
2934
onConnectionError: @escaping (ConnectionErrorResponse) -> Void = { _ in () },
3035
onConnectionAck: @escaping (ConnectionAckResponse) -> Void = { _ in () },
3136
onConnectionKeepAlive: @escaping (ConnectionKeepAliveResponse) -> Void = { _ in () },
3237
onData: @escaping (DataResponse) -> Void = { _ in () },
3338
onError: @escaping (ErrorResponse) -> Void = { _ in () },
34-
onComplete: @escaping (CompleteResponse) -> Void = { _ in () }
39+
onComplete: @escaping (CompleteResponse) -> Void = { _ in () },
40+
onMessage: @escaping (String) -> Void = { _ in () }
3541
) {
42+
self.messenger = messenger
3643
self.onMessage = onMessage
3744
self.onConnectionError = onConnectionError
3845
self.onConnectionAck = onConnectionAck
3946
self.onConnectionKeepAlive = onConnectionKeepAlive
4047
self.onData = onData
4148
self.onError = onError
4249
self.onComplete = onComplete
43-
}
44-
45-
func attach(to messenger: Messenger) {
46-
messenger.onRecieve { message in
50+
51+
self.messenger.onRecieve { [weak self] message in
52+
guard let self = self else { return }
53+
4754
self.onMessage(message)
4855

4956
// Detect and ignore error responses.
@@ -54,7 +61,7 @@ class Client {
5461

5562
guard let json = message.data(using: .utf8) else {
5663
let error = GraphQLWSError.invalidEncoding()
57-
messenger.error(error.message, code: error.code)
64+
self.messenger.error(error.message, code: error.code)
5865
return
5966
}
6067

@@ -64,57 +71,92 @@ class Client {
6471
}
6572
catch {
6673
let error = GraphQLWSError.noType()
67-
messenger.error(error.message, code: error.code)
74+
self.messenger.error(error.message, code: error.code)
6875
return
6976
}
7077

7178
switch response.type {
7279
case .GQL_CONNECTION_ERROR:
7380
guard let connectionErrorResponse = try? self.decoder.decode(ConnectionErrorResponse.self, from: json) else {
7481
let error = GraphQLWSError.invalidResponseFormat(messageType: .GQL_CONNECTION_ERROR)
75-
messenger.error(error.message, code: error.code)
82+
self.messenger.error(error.message, code: error.code)
7683
return
7784
}
7885
self.onConnectionError(connectionErrorResponse)
7986
case .GQL_CONNECTION_ACK:
8087
guard let connectionAckResponse = try? self.decoder.decode(ConnectionAckResponse.self, from: json) else {
8188
let error = GraphQLWSError.invalidResponseFormat(messageType: .GQL_CONNECTION_ACK)
82-
messenger.error(error.message, code: error.code)
89+
self.messenger.error(error.message, code: error.code)
8390
return
8491
}
8592
self.onConnectionAck(connectionAckResponse)
8693
case .GQL_CONNECTION_KEEP_ALIVE:
8794
guard let connectionKeepAliveResponse = try? self.decoder.decode(ConnectionKeepAliveResponse.self, from: json) else {
8895
let error = GraphQLWSError.invalidResponseFormat(messageType: .GQL_CONNECTION_KEEP_ALIVE)
89-
messenger.error(error.message, code: error.code)
96+
self.messenger.error(error.message, code: error.code)
9097
return
9198
}
9299
self.onConnectionKeepAlive(connectionKeepAliveResponse)
93100
case .GQL_DATA:
94101
guard let nextResponse = try? self.decoder.decode(DataResponse.self, from: json) else {
95102
let error = GraphQLWSError.invalidResponseFormat(messageType: .GQL_DATA)
96-
messenger.error(error.message, code: error.code)
103+
self.messenger.error(error.message, code: error.code)
97104
return
98105
}
99106
self.onData(nextResponse)
100107
case .GQL_ERROR:
101108
guard let errorResponse = try? self.decoder.decode(ErrorResponse.self, from: json) else {
102109
let error = GraphQLWSError.invalidResponseFormat(messageType: .GQL_ERROR)
103-
messenger.error(error.message, code: error.code)
110+
self.messenger.error(error.message, code: error.code)
104111
return
105112
}
106113
self.onError(errorResponse)
107114
case .GQL_COMPLETE:
108115
guard let completeResponse = try? self.decoder.decode(CompleteResponse.self, from: json) else {
109116
let error = GraphQLWSError.invalidResponseFormat(messageType: .GQL_COMPLETE)
110-
messenger.error(error.message, code: error.code)
117+
self.messenger.error(error.message, code: error.code)
111118
return
112119
}
113120
self.onComplete(completeResponse)
114121
case .unknown:
115122
let error = GraphQLWSError.invalidType()
116-
messenger.error(error.message, code: error.code)
123+
self.messenger.error(error.message, code: error.code)
117124
}
118125
}
119126
}
127+
128+
/// Send a `connection_init` request through the messenger
129+
func sendConnectionInit(payload: ConnectionInitAuth?) {
130+
messenger.send(
131+
ConnectionInitRequest(
132+
payload: payload
133+
).toJSON(encoder)
134+
)
135+
}
136+
137+
/// Send a `start` request through the messenger
138+
func sendStart(payload: GraphQLRequest, id: String) {
139+
messenger.send(
140+
StartRequest(
141+
payload: payload,
142+
id: id
143+
).toJSON(encoder)
144+
)
145+
}
146+
147+
/// Send a `stop` request through the messenger
148+
func sendStop(id: String) {
149+
messenger.send(
150+
StopRequest(
151+
id: id
152+
).toJSON(encoder)
153+
)
154+
}
155+
156+
/// Send a `connection_terminate` request through the messenger
157+
func sendConnectionTerminate() {
158+
messenger.send(
159+
ConnectionTerminateRequest().toJSON(encoder)
160+
)
161+
}
120162
}

Sources/GraphQLWS/Server.swift

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import NIO
77
import RxSwift
88

99
/// Adds server-side [graphql-ws subprotocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md)
10-
/// support, namely parsing and adding callbacks for each type of client request.
10+
/// support. This handles the majority of query processing according to the procol definition, allowing a few callbacks for customization.
1111
class Server {
12+
let messenger: Messenger
13+
1214
let auth: (ConnectionInitRequest) throws -> Void
1315
let onExecute: (GraphQLRequest) -> EventLoopFuture<GraphQLResult>
1416
let onSubscribe: (GraphQLRequest) -> EventLoopFuture<SubscriptionResult>
@@ -21,24 +23,33 @@ class Server {
2123
let decoder = JSONDecoder()
2224
let encoder = GraphQLJSONEncoder()
2325

26+
/// Create a new server
27+
///
28+
/// - Parameters:
29+
/// - messenger: The messenger to bind the server to.
30+
/// - auth: Callback run during `connection_init` resolution that allows authorization using the `payload`. Throw to indicate that authorization has failed.
31+
/// - onExecute: Callback run during `start` resolution for non-streaming queries. Typically this is `API.execute`.
32+
/// - onSubscribe: Callback run during `start` resolution for streaming queries. Typically this is `API.subscribe`.
33+
/// - onExit: Callback run when the communication is shut down, either by the client or server
34+
/// - onMessage: callback run on receipt of any message
2435
init(
36+
messenger: Messenger,
2537
auth: @escaping (ConnectionInitRequest) throws -> Void,
2638
onExecute: @escaping (GraphQLRequest) -> EventLoopFuture<GraphQLResult>,
2739
onSubscribe: @escaping (GraphQLRequest) -> EventLoopFuture<SubscriptionResult>,
2840
onExit: @escaping () -> Void,
2941
onMessage: @escaping (String) -> Void = { _ in () }
3042
) {
43+
self.messenger = messenger
3144
self.auth = auth
3245
self.onExecute = onExecute
3346
self.onSubscribe = onSubscribe
3447
self.onExit = onExit
3548
self.onMessage = onMessage
36-
}
37-
38-
/// Attaches the responder to the provided Messenger in order to recieve and transmit messages
39-
/// - Parameter messenger: The Messenger to use for communication
40-
func attach(to messenger: Messenger) {
41-
messenger.onRecieve { message in
49+
50+
self.messenger.onRecieve { [weak self] message in
51+
guard let self = self else { return }
52+
4253
self.onMessage(message)
4354

4455
// Detect and ignore error responses.
@@ -49,7 +60,7 @@ class Server {
4960

5061
guard let json = message.data(using: .utf8) else {
5162
let error = GraphQLWSError.invalidEncoding()
52-
messenger.error(error.message, code: error.code)
63+
self.messenger.error(error.message, code: error.code)
5364
return
5465
}
5566

@@ -59,53 +70,53 @@ class Server {
5970
}
6071
catch {
6172
let error = GraphQLWSError.noType()
62-
messenger.error(error.message, code: error.code)
73+
self.messenger.error(error.message, code: error.code)
6374
return
6475
}
6576

6677
switch request.type {
6778
case .GQL_CONNECTION_INIT:
6879
guard let connectionInitRequest = try? self.decoder.decode(ConnectionInitRequest.self, from: json) else {
6980
let error = GraphQLWSError.invalidRequestFormat(messageType: .GQL_CONNECTION_INIT)
70-
messenger.error(error.message, code: error.code)
81+
self.messenger.error(error.message, code: error.code)
7182
return
7283
}
73-
self.onConnectionInit(connectionInitRequest, messenger)
84+
self.onConnectionInit(connectionInitRequest)
7485
case .GQL_START:
7586
guard let startRequest = try? self.decoder.decode(StartRequest.self, from: json) else {
7687
let error = GraphQLWSError.invalidRequestFormat(messageType: .GQL_START)
77-
messenger.error(error.message, code: error.code)
88+
self.messenger.error(error.message, code: error.code)
7889
return
7990
}
80-
self.onStart(startRequest, messenger)
91+
self.onStart(startRequest)
8192
case .GQL_STOP:
8293
guard let stopRequest = try? self.decoder.decode(StopRequest.self, from: json) else {
8394
let error = GraphQLWSError.invalidRequestFormat(messageType: .GQL_STOP)
84-
messenger.error(error.message, code: error.code)
95+
self.messenger.error(error.message, code: error.code)
8596
return
8697
}
87-
self.onStop(stopRequest, messenger)
98+
self.onStop(stopRequest, self.messenger)
8899
case .GQL_CONNECTION_TERMINATE:
89100
guard let connectionTerminateRequest = try? self.decoder.decode(ConnectionTerminateRequest.self, from: json) else {
90101
let error = GraphQLWSError.invalidRequestFormat(messageType: .GQL_CONNECTION_TERMINATE)
91-
messenger.error(error.message, code: error.code)
102+
self.messenger.error(error.message, code: error.code)
92103
return
93104
}
94-
self.onConnectionTerminate(connectionTerminateRequest, messenger)
105+
self.onConnectionTerminate(connectionTerminateRequest)
95106
case .unknown:
96107
let error = GraphQLWSError.invalidType()
97-
messenger.error(error.message, code: error.code)
108+
self.messenger.error(error.message, code: error.code)
98109
}
99110
}
100111

101112
// Clean up any uncompleted subscriptions
102113
// TODO: Re-enable this
103-
// messenger.onClose {
104-
// _ = self.context?.cleanupSubscription()
105-
// }
114+
// messenger.onClose {
115+
// _ = self.context?.cleanupSubscription()
116+
// }
106117
}
107118

108-
private func onConnectionInit(_ connectionInitRequest: ConnectionInitRequest, _ messenger: Messenger) {
119+
private func onConnectionInit(_ connectionInitRequest: ConnectionInitRequest) {
109120
guard !initialized else {
110121
let error = GraphQLWSError.tooManyInitializations()
111122
messenger.error(error.message, code: error.code)
@@ -127,7 +138,7 @@ class Server {
127138
// TODO: Should we send the `ka` message?
128139
}
129140

130-
private func onStart(_ startRequest: StartRequest, _ messenger: Messenger) {
141+
private func onStart(_ startRequest: StartRequest) {
131142
guard initialized else {
132143
let error = GraphQLWSError.notInitialized()
133144
messenger.error(error.message, code: error.code)
@@ -153,43 +164,43 @@ class Server {
153164
guard let streamOpt = result.stream else {
154165
// API issue - subscribe resolver isn't stream
155166
let error = GraphQLWSError.internalAPIStreamIssue()
156-
messenger.error(error.message, code: error.code)
167+
self.messenger.error(error.message, code: error.code)
157168
return
158169
}
159170
let stream = streamOpt as! ObservableSubscriptionEventStream
160171
let observable = stream.observable
161172
observable.subscribe(
162173
onNext: { resultFuture in
163174
resultFuture.whenSuccess { result in
164-
messenger.send(DataResponse(result, id: id).toJSON(self.encoder))
175+
self.messenger.send(DataResponse(result, id: id).toJSON(self.encoder))
165176
}
166177
resultFuture.whenFailure { error in
167-
messenger.send(ErrorResponse(error, id: id).toJSON(self.encoder))
178+
self.messenger.send(ErrorResponse(error, id: id).toJSON(self.encoder))
168179
}
169180
},
170181
onError: { error in
171-
messenger.send(ErrorResponse(error, id: id).toJSON(self.encoder))
182+
self.messenger.send(ErrorResponse(error, id: id).toJSON(self.encoder))
172183
},
173184
onCompleted: {
174-
messenger.send(CompleteResponse(id: id).toJSON(self.encoder))
175-
_ = messenger.close()
185+
self.messenger.send(CompleteResponse(id: id).toJSON(self.encoder))
186+
_ = self.messenger.close()
176187
}
177188
).disposed(by: self.disposeBag)
178189
}
179190
subscribeFuture.whenFailure { error in
180191
let error = GraphQLWSError.graphQLError(error)
181-
_ = messenger.error(error.message, code: error.code)
192+
_ = self.messenger.error(error.message, code: error.code)
182193
}
183194
}
184195
else {
185196
let executeFuture = onExecute(graphQLRequest)
186197
executeFuture.whenSuccess { result in
187-
messenger.send(DataResponse(result, id: id).toJSON(self.encoder))
188-
messenger.send(CompleteResponse(id: id).toJSON(self.encoder))
198+
self.messenger.send(DataResponse(result, id: id).toJSON(self.encoder))
199+
self.messenger.send(CompleteResponse(id: id).toJSON(self.encoder))
189200
}
190201
executeFuture.whenFailure { error in
191-
messenger.send(ErrorResponse(error, id: id).toJSON(self.encoder))
192-
messenger.send(CompleteResponse(id: id).toJSON(self.encoder))
202+
self.messenger.send(ErrorResponse(error, id: id).toJSON(self.encoder))
203+
self.messenger.send(CompleteResponse(id: id).toJSON(self.encoder))
193204
}
194205
}
195206
}
@@ -203,7 +214,7 @@ class Server {
203214
onExit()
204215
}
205216

206-
private func onConnectionTerminate(_: ConnectionTerminateRequest, _ messenger: Messenger) {
217+
private func onConnectionTerminate(_: ConnectionTerminateRequest) {
207218
onExit()
208219
_ = messenger.close()
209220
}

0 commit comments

Comments
 (0)