WebSocket-Kit Client

I'm trying to write a client using WebSocket-Kit in a standalone project. To open a connection, the documentation states...

        WebSocket.connect(to: "ws://echo.websocket.org", on: eventloop) { ws in
            // Connected WebSocket.
            print(ws)
        }

but there are at least 2 things here I don't understand:

  1. How should I define the eventloop stub?
  2. What is the print statement going to print?

Obviously, some initialisation code is needed, but the documentation doesn't go there.

Any help will be most appreciated.

It will print a description on the connection.

As for the event loop, you need to get one from somewhere. That's outside the scope of the library so have at look at SwiftNIO for more details on EventLoops and how to create one GitHub - apple/swift-nio: Event-driven network application framework for high performance protocol servers & clients, non-blocking.

I was hoping WebSocket-Kit would shield me from the complexities of NIO. The echo test is effectively a REST function - something that web sockets are not necessarily about. This is why you need to write better documentation and publish some real world examples. Otherwise, what is the point in writing this stuff if nobody can find out how to use it?

Developer.answerToEverything(from: question) { answer in
    // usually 42, but could take a long time
    print(answer)
}

Just joking.

If you want to avoid the complexities of NIO then you should use a framework like Vapor

Are you saying Vapor can be configured to act as a Client?

If so, can it be configure to act as a Client and a Server on the same machine?

Yes it's in the docs https://docs.vapor.codes/4.0/websockets/#client

Note that doing this from a route handler that isn't a web socket might cause issues but if you do it in the app startup etc then you'll be fine

1 Like

Thank you Tim. On reflection, running a client on the server might not be my best choice. One of the machines can come and go, so I'm now thinking it should be a client. This will mean setting up the main machine to deal with 2 different clients with different APIs. I'm assuming Vapor will be able to serve 2 WSS clients with different APIs with routing.

For the iMac Client, I've managed to get 2 WSS instances of WebSocket-Kit working, one to the local server and one to a remote - each with different APIs. I love the Kit's high level interface.

For now, I have a question for you. Should each client run on its own event loop, or should they share just one?

Depends on what else the app is doing but probably different event loops from the same provider

Amazingly, this WebSocket-kit client code will converse with my hacked NIO local server and also to a third party remote server, but it won't connect to a local Vapor server. Safari and a free app called Socket Debugger will though.

class MyWssService {
    let elg = MultiThreadedEventLoopGroup(numberOfThreads: 2)
    var ws: WebSocket?

    func connect(to urlStr: String) {
        let _ = WebSocket.connect(to: urlStr, on: elg) { wsx in
            self.ws = wsx
            self.ws!.onBinary(satServerCallback)
        }
    }

    func disconnect() {
        let _ = ws!.close()
    }

    func send(data: Data) {
        ws!.send(raw: data, opcode: .binary)
    }
}

The swift.doc documentation is nice and pretty, but otherwise useless when trying to understand how to use this stuff. I hate to keep banging on, but I can't find a single up-to-date example anywhere. So please can you come up with a working example?

Looking at Tests is not helpful. If they were , there wouldn't be any bugs or warning messages in release. Speaking of warnings, there are quite a few when installing the toolchain - which doesn't fill one with confidence.

Perhaps this will explain what I'm trying to do:

                              DATA FLOW

+------------------+   +-------------------+
|  receiver.local  |   | transmitter.local |
| linux WSS client |   | linux UPD server  |
+------------------+   +-------------------+
          |                      |
          |                      |
       +-------------------------------+   +------------------+
       |          server.local         |   | remoteserver.com |
       | linux WSS server & UPD client |   |    WSS server    |
       +-------------------------------+   +------------------+
                        |                           |
                        |                           |
                   +-------------------------------------+
                   |           controller.local          |
                   |          macOS 2 WSS clients        |
                   |           SwiftUI interface         |
                   +-------------------------------------+

receiver.local
- streams status data
- accepts requests that don't produce a response

transmitter.local
- accepts command requests which may return a response

server.local
- streams status data back to controller.local every 500 milliseconds
- accepts requests that don't produce a response
- links receiver.loca and transmitter.local with controller.local via...
- lots of logic, actors and async/await stuff, controlling and monitoring...
- 7 relays, 8 cooling fans, 3 temperature sensors and 3 voltage/current sensors

remoteserver.com
- streams spectrum data every 333 milliseconds

controller.local
- controls and monitore everthing via
- SwiftUI with about 50 buttons, text boxes and a real time spectrum graph

After almost a year in coding, I'm completely stuck. I desperately need help, advice and example code network side. Everything else is working. Please help.

If I were 60 years younger and applying to enter the WWDC22 Swift Student Challenge, I would be required to include ducumentation with my submission. Oh, and my creation must not use a network connection. How ironic is that?

Perhaps Apple is trying to find out what documentation should look like, but worries how few applications there'd be if students were tempted to include networking. Interesting though, their code would be in itself - an example.

I wonder if @0xTim will appreciate my sense of humour.

OK @0xTim , I give in and I'm done asking for help with Vapor and WebSocket-Kit. Without proper documentation and example code, the name says it all - it's vaporware.

Without seeing more code, i.e. the Vapor code that won't connect etc it's hard to tell what's going on. You're also throwing away the web socket when you connect, so the initial connect(to:) call will lose the reference to the web socket which is probably why it fails.

WebsocketKit is fairly low level and we don't expect most people to use it, we expect it to be used from Vapor for the most part. We don't have many docs for WebsocketKit because in low down on the priority and we have limited resources.

As a side note, disparaging and being rude to people who are trying to help is not going to get you far. I was getting around to responding as unsurprisingly I'm pretty busy and my time is limited. Vapor is an open source project, primarily worked on by people in their free time. If things aren't how you like you're more than welcome to open a PR to fill in the gaps or even sponsor the project to help increase our resources.

2 Likes

Yes, some of cynical comments can appear to be rude, so I do apologise. The thing is though, finding a Swift WebSocket client library for Linux is next to impossible. That's why I've been looking at your WebSocket-Kit.

All I need is to see a simple example, so I'll be able to take it from there. That's all I'm asking for.

1 Like

I don't have time to build a full example right now I'm afraid, but what you have looks ok. I'd check the logs and try chaining a failure parser to it as shown in these tests websocket-kit/WebSocketKitTests.swift at main · vapor/websocket-kit · GitHub

That should catch any errors