Hi,
as I have just started with swift and swift-nio I am having trouble with a simple thing. Writing data in channelRead of a handler. The data is properly written but it is not flushed (sent) back to the server. When I close the app the missing buffer is sent.
Let me show you some of the code (please don't mind the poor quality, it's just a POC )
Setting up the client:
import Foundation
import NIO
import SWIRCMessageParser
final public class IRCClient {
private var channel: Channel? = nil
private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
private let parser = IRCMessageParser()
private let dispatcher = IRCMessageDispatcher()
private let host: String
private let port: Int
public init(host: String, port: Int) {
self.host = host;
self.port = port;
dispatcher.addReceiver(PingReceiver(self))
}
public func connect() throws {
do {
self.channel = try ClientBootstrap(group: group)
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
.channelInitializer { channel in
channel.pipeline.addHandler(ByteToMessageHandler(LineDecoder())).flatMap { v in
channel.pipeline.addHandler(IRCMessageHandler(dispatcher: self.dispatcher, parser: self.parser))
}
}
.connect(host: self.host, port: self.port)
.wait()
} catch let error {
throw error
}
}
public func close() throws {
try group.syncShutdownGracefully()
}
public func send(_ message: String) throws {
if self.channel == nil {
throw NSError(domain: "Called \(#function) before connect", code: 1)
}
_ = channel!.writeAndFlush(message)
}
}
Simple dispatcher:
import Foundation
import SWIRCMessageParser
final class IRCMessageDispatcher {
private var receivers: [IRCMessageReceiver]
public init(_ receivers: [IRCMessageReceiver] = []) {
self.receivers = receivers
}
public func addReceiver(_ receiver: IRCMessageReceiver) {
self.receivers.append(receiver)
}
public func dispatch(_ message: IRCMessage) {
self.receivers.forEach { (receiver: IRCMessageReceiver) in
receiver.receive(message)
}
}
}
Channel Handler:
import NIO
import SWIRCMessageParser
final class IRCMessageHandler: ChannelDuplexHandler {
typealias InboundIn = ByteBuffer
typealias InboundOut = ByteBuffer
typealias OutboundIn = String
typealias OutboundOut = ByteBuffer
private let dispatcher: IRCMessageDispatcher
private let parser: IRCMessageParser
init(dispatcher: IRCMessageDispatcher, parser: IRCMessageParser) {
self.dispatcher = dispatcher
self.parser = parser
}
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
let message = parser.parse(rawMessage: String(buffer: self.unwrapInboundIn(data)))
if message == nil {
print("Invalid message received: \(data.description)")
context.fireChannelRead(data)
return
}
print(message!)
self.dispatcher.dispatch(message!)
context.fireChannelRead(data)
}
func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
var buffer = context.channel.allocator.buffer(capacity: 200)
buffer.writeString(self.unwrapOutboundIn(data))
context.write(NIOAny(buffer), promise: promise)
}
}
And the PingReceiver:
import Foundation
import SWIRCMessageParser
open class PingReceiver: IRCMessageReceiver {
private let client: IRCClient
public init(_ client: IRCClient) {
self.client = client;
}
public func receive(_ message: IRCMessage) {
if message.command == "PING" {
do {
try self.client.send("PONG :\(message.params.first!)")
} catch let error {
print("PONG Error: \(error.localizedDescription)")
}
}
}
}
I have already tried simplifying it to just context.writeAndFlush if message is a ping in channelRead and that still did not send the message instantly.