|
public func connect(host: String, port: Int) -> EventLoopFuture<TCPClient> { |
|
assert(.initializing == self.state) |
|
|
|
let bootstrap = ClientBootstrap(group: self.group) |
|
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) |
|
.channelInitializer { channel in |
|
return channel.pipeline.addTimeoutHandlers(self.config.timeout) |
|
.flatMap { |
|
channel.pipeline.addFramingHandlers(framing: self.config.framing) |
|
}.flatMap { |
|
channel.pipeline.addHandlers([ |
|
CodableCodec<JSONResponse, JSONRequest>(), |
|
Handler(), |
|
]) |
|
} |
|
} |
|
|
|
self.state = .connecting("\(host):\(port)") |
|
return bootstrap.connect(host: host, port: port).flatMap { channel in |
|
self.channel = channel |
|
self.state = .connected |
|
return channel.eventLoop.makeSucceededFuture(self) |
|
} |
|
} |
|
|
|
public func disconnect() -> EventLoopFuture<Void> { |
|
if .connected != self.state { |
|
return self.group.next().makeFailedFuture(ClientError.notReady) |
|
} |
|
guard let channel = self.channel else { |
|
return self.group.next().makeFailedFuture(ClientError.notReady) |
|
} |
|
self.state = .disconnecting |
|
channel.closeFuture.whenComplete { _ in |
|
self.state = .disconnected |
|
} |
|
channel.close(promise: nil) |
|
return channel.closeFuture |
|
} |
|
|
|
public func call(method: String, params: RPCObject) -> EventLoopFuture<Result> { |
Thanks to @wlisac for the report.
At least TCPClient is very thread unsafe and really needs fixing. Without synchronisation, state is read/written to from different threads.
swift-nio-examples/json-rpc/Sources/JsonRpc/Client.swift
Lines 20 to 60 in d36c05a
Thanks to @wlisac for the report.
At least
TCPClientis very thread unsafe and really needs fixing. Without synchronisation,stateis read/written to from different threads.