-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More Communication Protocols #15
Comments
Send me an email, I could probably help with the javascript / CCSDS protocol stuff. |
This is fairly low on my priority list right now, but when I do get round to it I'll put together a prototype and if you could try out the SOAP interface from JS that'd be great (I don't know JS very well...) I was thinking we could allow additional DLLs to be placed in kRPC's plugin directory, which would provide additional communication layers. The in-game server interface could then allow you to choose which communication protocol you want the server to use. |
Quick suggestion: REST instead of SOAP, since it's also HTTP but a lot easier to interface with! |
GRPC might be cheap to generate code for |
GRPC would solve a lot of your issues, you are already doing what grpc does, proto messages over ipc but it will do a lot more as well, and make it more reliable and stable. |
Seconding GRPC, it seems well maintained and solves the problem of having to write client libraries. Unfortunately it won't help for getting data in the browser, as GRPC has no defined mechanism for interacting with it (like websockets). |
I've only had a quick look at GRPC, but here are two issues that came to mind compared to the current server protocol:
Also, I've started working on making the server protocol used by kRPC extensible. My vision is that the user will be able to start one or more servers, and each server can be of a different 'type'. I see no reason why GRPC couldn't be included as one of these 'server types'. Then GRPC can even run alongside the current server protocol (with its streams and dynamic client support). A REST 'server type' is also planned. |
In case you're interested, the changes are on this branch: https://github.com/krpc/krpc/tree/feature/server-refactoring |
I have used GRPC streaming in a project and it worked by having the client connect to the server to get data. The server would never finish sending data so the stream was maintained until the client decided to end the connection. |
Indeed, GRPC does force you to have a well defined interface, and compiling protobufs at runtime is not easy. Is that added flexibility useful in practice, though? Doesn't the current code have to agree on the protobufs ahead of time anyway? If we do get gRPC, REST would come for free, if we are willing to run a external program |
Yes the current code does have to agree on the protobufs, but not the RPCs. The protobufs just define what a request/response message looks like, not what the RPCs are. So you can add/change RPCs on the server and the python/lua clients automatically pick up the changes. The existing C++, C# and Java clients have generated stubs though, so these could be just be replaced with gRPC. |
Let me know if you need help testing a websockets/REST API, I'll definitely port KeRD to kRPC as soon as this is ready. |
I've now got the server refactored into a state where I can start adding additional communication protocols, and I'm going to start by adding ReST+websockets. Here my thoughts on a potential design. Comments welcome! RPC Server Uses ReST over HTTP. Requests are sent to the server as GET requests.
Some examples:
Responses are sent as JSON formatted strings, following the JSON API specification: http://jsonapi.org/ Stream server For this, I don't think ReST over HTTP is enough, as the server needs to send data to the client continuously. I think websockets would be more suitable? The client could connect to the websocket, send a request (formatted in the same manner as above, but just putting the URI in a text frame?) and the server will then send repeated messages containing the return value of the request. If the client sends additional requests, their results could be added to the response messages sent by the server, so that clients can have multiple streams over the same TCP connection. Now I'm going to go ponder how to fit gRPC into all of this! |
I'm personally not sure if a separate REST API is required for this plugin, or at least if it should be prioritized over WS. After playing around with the Python API, I'd prefer a very similar RPC API for JS using only websockets. The reason for this is that there's much more overhead requesting stuff via HTTP, so polling some resource at e.g. 10hz would be unreasonably resource intensive with a REST-based API, but would work just fine with websockets. A REST API would in my opinion be better suited for applications where the data doesn't change as frequently, or in this case maybe limited to actions instead of data retrieval - e.g. for RCS like you mentioned Just a point regarding REST APIs: they're usually implemented using existing HTTP methods instead of having method names in the URI, so data retrieval would use e.g. I was looking around for a simple temporary workaround to start playing around with websockets, and noticed that the websockify project might be able to accomplish what I think would work great as a JS API. Basically it would expose the gRPC/protobuf(?) API directly to JS via websockets, then something like protobuf.js could possibly be used to decode and encode communications with kRPC. The JS API would then expose actions and data through objects similar to e.g. the Python API. By doing it this way you'll also be able to keep the JS API similar to the other RPC APIs which is a plus. What do you think? |
You make a good point about performance. Having to create a new tcp connection for every request would be painful! I guess what we are really after then is a JS client with some code to wrap server-side object ids up as JS objects. This is separate to the actual transport layer underneath, so could be done via gRPC (or the current protocol based on protobuf, but would take more work to implement the client). Then there's no need for websockets or REST over HTTP at all. I don't know if gRPC can provide this object id wrapping though? |
You'd still need websockets support in kRPC (currently no browser can open regular TCP connections), but I'm sure there's some library or wrapper for C# that can expose the kRPC socket as a websocket (Telemachus has a simple WS server implementation, and here's more info related to writing WS servers). If you're able to implement a way to connect to kRPC via websockets I can definitely help writing the JS bindings if needed. |
Ah I see. Sorry my knowledge of browser based programming is rather lacking. Didn't know you can't just open a TCP connection! So I guess option 1 is to add a websockets server to kRPC, and use the same protobuf based serialization over it just like the current TCP based protocol. Then implement a JS client (just like the current clients). Or option 2: we add a gRPC server to kRPC and just use their JS client. But I guess this would not work in a browser if it needs to open a TCP connection? Or can we do gRPC over websockets? Also, some other thoughts on gRPC: I've been having a read of the gRPC documentation, and it doesn't look like it can provide the same "remote objects" that the current kRPC clients do. It follows the design philosophy of "services not objects and messages not references". While adding a gRPC server would give us a JS and many other clients for free (which is a good reason to add support for it) those clients would feel very different to the current clients. You would need to pass object ids around as plain old integers in the gRPC messages, rather than being able to make method calls on objects. So option 2b is to add a gRPC server to kRPC, then build a JS client on top of the gRPC JS client that provides these "remote objects". Writing such a client would probably be less implementation with than writing a JS client for the current protocol, plus we get all the gRPC clients for free :) I think I prefer option 2b if gRPC can run in a browser - less implementaion work and lots of free clients :) |
To answer my own question, gRPC doesn't work in the browser. I guess we need option 1 for KeRD to work with kRPC. |
There is also an official JS protobuf library we could use (instead of protobuf.js) for the encoding and decoding and it works in the browser: https://github.com/google/protobuf/tree/master/js |
Yep, option 1 sounds like the only real option (at least if you want to support browser based kRPC clients), even if it means more work implementing the JS bindings. Google's protobuf library sounds good! I can start working on JS bindings as soon as a websocket server is added to kRPC, do you know if it will require a lot of work implementing a WS server? |
No, it should be fairly straight forward. I imagine I'll be able to get a prototype done over the weekend for you to try out. |
Awesome, I can't wait to check it out. |
This is looking great! I just want to point out that, although browser-based clients can't possibly support gRPC (because of the lack of TCP support), there are some projects around that act as bridges (https://github.com/gengo/grpc-gateway), so we could get REST for free, if there's a way of running that from inside Kerbal (can you launch processes within unity?). Technically, we could also get gRPC support from websockets using this project (https://github.com/kanaka/websockify), but we'd have to re-implement gRPC in javascript...
With HTTP (1.1), you can reuse the same connection. The overhead in HTTP really comes from the fact that it's request/response based - streams of data are not well supported, so the client has to constantly issue new requests. |
@Lokaltog I've got a websockets server ready for you to play with :D You can download it from here: https://krpc.s3.amazonaws.com/deploy/feature/websockets/375.1/krpc-0.3.0-30-g65ca751.zip To use it, just install the plugin as usual, fire up KSP, choose a port number and hit start server. Then send KRPC.Request messages to it and receive KRPC.Response protobuf mesages from it using websockets frames with opcode = binary. Note that you don't need to send the size of the protobuf message like you do with the other protocol. The size is include in the ws frame header, so you just need to send the protobuf message data. Here's an example script (in python) that I used to test it: https://gist.github.com/djungelorm/6372d31acc515fc63f18c889a8f5f631#file-ws-client-py I haven't done much testing so expect bugs. I'll be doing some more testing tomorrow, so let me know if you have any issues! If your interested in the server code it's here: 856f819b7fed55064e2094ee05d30ed0d48a6665 |
Sweet! I just downloaded and installed it, and your test script works fine. I'll start working on some proof-of-concept JS code right away. |
I've reimplemented the basic example using webpack and proto-loader which uses protobuf.js to compile .proto files to JSON and handle the message encoding and decoding. Here's the example script in JS: var ProtoBuf = require('protobufjs')
var proto = ProtoBuf.loadJson(require('krpc.proto')).build()
var sock = new WebSocket('ws://localhost:50000')
sock.binaryType = 'arraybuffer'
sock.onopen = (ev) => {
let req = new proto.krpc.schema.Request('KRPC', 'GetStatus')
sock.send(req.toArrayBuffer())
}
sock.onmessage = (ev) => {
let resp = proto.krpc.schema.Response.decode(ev.data)
let status = proto.krpc.schema.Status.decode(resp.return_value)
console.log(status)
} This prints the same status object as the Python script. I'll start reading up on how the kRPC Python bindings are actually implemented, then I'll start working on the JS bindings. I'll use protobuf.js for now, as Google's JS implementation is currently in a poorly documented beta. |
I'm currently attempting to set the client name and receive the client identifier like this, but I'm not receiving any response from kRPC when sending the hello message and client ID. The connection is also left open so I think some error may be occuring in kRPC. Is this feature not implemented yet? |
I have managed to get a very basic node client library up and running if anyone feels like playing around, there are still a bunch of things to do like:
I started off building code manually (see the apis/krpc.js file) but then realised I could generate it all from the getServices call, so switched to that (Code in the ./utilities/generate-service.js file). So far I have tested:
|
Great stuff, thanks, ExigentCoder! |
Yeah it's possible. Although for now I think it would be easier for @eXigentCoder to work on it in its own repo? Also, having it in the main kRPC release wouldn't really gain much from a users perspective. They would just be doing |
Yeah, I think with npm it should be fine to leave the source where it is. Especially since it's currently working with Travis to run CI & deployment. Once the documentation is done, would we just need to add a link from http://krpc.github.io/krpc to the node documentation file (would most likely be markdown) or would your rather have it as html on that site? |
I don't mind if you want to host the documentation yourself - probably makes more sense as you could maintain it more easily. And I'm happy to link to it from all the various places. |
I have now merged the websockets branch into the v0.4.0 branch, and have revamped the UI so now you can create multiple servers, and choose which protocol they use! Latest build is here: http://krpc.s3-website-us-east-1.amazonaws.com/deploy/v0.4.0/692.1/ And here's a screenshot. The UI is functionally complete, although it could probably do with some visual improvements. Feedback welcome - you can probably tell I am not a UX designer! |
Fantastic news, thanks for all the work djungelorm! |
Oooo there is a nasty bug! Nothing to do with your client - the UI changes introduced an issue where reconfiguring a server doesn't update its event handlers, leading to it not starting properly. Should be fixed in this version: http://krpc.s3-website-us-east-1.amazonaws.com/deploy/v0.4.0/706.1/ |
Awesome thanks, will test it out this evening! |
Hi @djungelorm What is the status of WebSockets? Is it implemented and does it just wrap Protobuf? Regards, NeverCast. |
I've got most of the node.js library working (At least I think so, need to add a bunch more tests), however one part that definitely isn't working is connecting to the stream server. Am I right in thinking this endpoint isn't upgraded yet to use WebSockets or have I just broken something?
This is while using the v0.4.0- 711.1 build |
@nevercast websockets is fully implemented and working in the upcoming v0.4.0 release (pre-release is available with it working). It does indeed use protobuf to serialize messages within the websockets messages. @eXigentCoder The stream server should work. I'll have a look. |
@djungelorm Thanks excellent for my HTML UI needs. Cheers! |
Really looking forward to the websocket support as I'm trying to create a browser-based (for mobile) throttle controller. The idea is to have the iPhone sitting to the left of my keyboard with a throttle interface, instead of a HOTAS throttle. |
@djungelorm sorry, I was on a bit of a break but am back now and trying to get everything working. I got the latest release of the 0.4 branch (0.4.0-122) and most of the existing code I had is still working except for streams. I am trying to connect to the stream server using Does anything there seem obviously wrong to you? |
@eXigentCoder To connect to the stream server, you need to pass the RPC clients identifier in the connection string (as a base64 encoded string). For example: This is used to "link" the two connections together in the server side logic. Unfortunately I neglected to add a way for a websockets client to get hold of this id! I've added an RPC called KRPC.GetClientID to allow this. Here's the latest build with this addition: And an example script that connects to the stream server: |
Yeah you are decoding the wrong type. The stream server sends a sequence of |
Ah yes that makes more sense. I updated the code to decode to Sorry to keep pestering you, will keep trying to get it working this side but if you have an idea of where to look I'd appreciate it. |
There was a bug... The server was writing the size of the message, followed by the message data. I've fixed it to only write the message, so your code should hopefully now work. Updated version available here: And here's the script I used to test it: https://gist.github.com/djungelorm/fb09f4683d8e988eebf4da63a2e340c7 And no worries - happy to help! |
Thanks so much, had a quick window to test out and it's working now, time to refactor it to be pretty and easier to use! |
Quick update from me: I've now "officially" released v0.4.0 with the websockets server included. I also have a serial I/O protocol in the works for release very soon, along with a client library written in C using nanopb targetting embedded devices so you can use kRPC from an Arduino/whatever. I will have another look into adding gRPC support after that is released. |
There has been some discussion on the discord regarding gRPC. While great to add it in theory, it isn't practical to do so. Here's a summary:
More info here: grpc/grpc-dotnet#1309 |
The underlying server communication protocol should be moddable, to allow communication via other means than just google's protocol buffers.
Then we can support, for example:
The text was updated successfully, but these errors were encountered: