WebSocket support
How hard would it be to use a websocket connection instead of tcp in the server ? (and both ?)
That would allow anybody to connect through a web browser to connect to flying-squid using https://github.com/voxel/voxel-clientmc
relevant https://github.com/deathcap/wsmc
Yeah sure I know about wsmc, but it would be cool to have native support for that in nmp.
:+1: for native ws in nmp. Currently wsmc is broken, I think the relevant bits could be easier to maintain in sync with this repository if they were a part of it.
Or maybe, refactor node-minecraft-protocol to operate on node.js streams instead of TCP sockets? References:
TCP: https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/src/createClient.js Stream: https://github.com/deathcap/wsmc/blob/master/minecraft-protocol-stream.js
Since streams are an abstract interface, using them with websockets is as simple as piping to websocket-stream. Although some options may still be needed to control various other tweaks (e.g. for websockets you likely want to disable MC protocol encryption, since it is slow in JavaScript and wss:// URLs (analogous to https://) can be used instead for encryption). Useful handbook on streams:
https://github.com/substack/stream-handbook
edit: also, for web sockets you probably don't want Minecraft's packet framing, since the ws protocol https://html.spec.whatwg.org/multipage/comms.html#server-sent-events-intro already has its own framing
NPm already operates on streams. All you have to do is call setConnection with your stream?
On Sat, Jan 9, 2016, 7:06 AM deathcap [email protected] wrote:
Or maybe, refactor node-minecraft-protocol to operate on node.js streams https://nodejs.org/api/stream.html#stream_stream instead of TCP sockets? References:
TCP: https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/src/createClient.js Stream: https://github.com/deathcap/wsmc/blob/master/minecraft-protocol-stream.js
Since streams are an abstract interface, using them with websockets is as simple as piping to websocket-stream https://www.npmjs.com/package/websocket-stream. Although some options may still be needed to control various other tweaks (e.g. for websockets you likely want to disable MC protocol encryption, since it is slow in JavaScript and wss:// URLs (analogous to https://) can be used instead for encryption).
https://github.com/substack/stream-handbook
— Reply to this email directly or view it on GitHub https://github.com/PrismarineJS/node-minecraft-protocol/issues/312#issuecomment-170200699 .
But the createClient() API accepts host and port options, which it passes to net.connect() to get a stream for setSocket() — I'd like to pass createClient a stream directly.
Being able to pass a stream would be useful for https://github.com/PrismarineJS/node-minecraft-protocol/issues/185 too.
Actually, one of the point of the old modularization work (https://github.com/PrismarineJS/node-minecraft-protocol/pull/210) was to help mitigate this. You'd use the raw Client API and then attach the modulese to it, so you could pass whatever stream you want to Client. I never finished that PR, but the idea's there.
It's a good idea, the changes in modularizing NMP I think would be useful for websocket support:
- [ ] Protocol stream access: allow connecting NMP directly to a
Stream, which could be either a TCP socket or WS socket or something else, update: like in voxel-clientmc, I use a duplexer stream and connect NMP to a webworker, instead of a websocket directly (currently I have my own createClient taking astreamoption, callsclient.setSocket(stream)) - [ ] Handshaking: allow skipping the
HANDSHAKINGphase, not necessary/feasible for WS — this also disables packet encryption, can use WSS (≈ HTTPS) instead (currently I setclient.state = states.LOGINupon receiving theconnectevent) - [ ] Framing: allow disabling MC packet framing (length prepending), as WS has its own, and multiple writes cause packet fragmentation with WS unlike TCP with Nagle's algorithm https://github.com/PrismarineJS/node-minecraft-protocol/pull/316 (currently I set
client.framerto an empty transform stream) - [ ] Compression: allow disabling compression, since there is a websocket extension with per-frame compression (currently I'm not using this, very new only standardized last month, but would like to https://github.com/deathcap/wsmc/issues/23)
If NMP is sufficiently modularized, it should be possible to build all of the above from modular components, taking only what is needed from this module.
There's also the question of where websocket support should live exactly, e.g. should node-minecraft-protocol have websocket-stream as a dependency? On one hand, there is an argument for keeping NMP small and minimal, allowing other modules to build on top of it. On the other hand, having built-in WS support could greatly help ease WS/MC adoption - meaning that, for example, someone writing a client/server/proxy with NMP could trivially interoperate with WS client/server/proxies.
https://github.com/feross/webtorrent faces a similar problem: they have implemented bittorrent in the browser, but cannot interoperate with peers only supporting the original native TCP/UDP BT protocol. So they are advocating other bittorrent software (even native apps) adopt browser support so they can talk to each other (WebRTC in their case, but it is analogous to WebSockets in this project).
Prototyping sort of what I had in mind in: https://github.com/PrismarineJS/node-minecraft-protocol/pull/320 Client stream - factoring out the common code (keep alive, login state change, compression request), which both WS and TCP sockets can use.
BTW, it's worth noting that we disable Nagle's algorithm. So we actually send two TCP frames, one with the ID alone, one with the content. I consciously chose this on-the-wire overhead over recreating a buffer for the sole purpose of doing only a single, clean write.
That being said, with WS being message-based, (vs stream-based), having a framer makes absolutely no sense there ^^.
Oh and concerning websocket support directly IN NMP, I think it would be great if NMP worked easily with WS, but I'm a bit iffy with having it completely built-in. That is to say : patches to make websocket usage work better are great, but having a dependency on websocket is meh.
What would totally make sense, however, is having a server implementation based on NMP (E.G. : Flying-Squid) support WS natively (for instance, by running two instances of NMP, one with a websocket server stream, one with the usual tcp server stream, and synching the two).
For the multiple writes wrt Nagle, I think that's worth discussing further, in https://github.com/PrismarineJS/node-minecraft-protocol/pull/316
Not having a direct dependency on websocket-stream in NMP, looking into this some more, I agree. The most generic API that NMP could expose is a plain Node.js Stream, which is compatible with websocket-stream, duplexer, websocket-stream, etc. (I use all these for various purposes, so a built-in ws stream would only be marginally useful). I first passed this in through options.stream, but @rom1504 has a point, callers can just use client.setSocket() - updated https://github.com/PrismarineJS/node-minecraft-protocol/pull/320 accordingly.
#320 factors out all of the TCP-specific stuff into a separate file (DNS SRV lookup, net.connect, encryption/authentication/yggdrasil), this way WS clients (or other non-TCP clients — WebRTC P2P?) can use NMP without this baggage.
The remaining problem is disabling framing — cleanly —, #320 has a hack by setting the framer to an empty stream, not sure of the best way to do this.
To fix that problem, we really, really need the pipeline module outlined in #176
Have we gotten any updates regarding this issue?