Docker daemons starting with api version 1.28 return binary websocket frames.
Those cannot be processed by xterm.
Thanks for reporting @FlorianLudwig! Will be fixed.
@FlorianLudwig do you have any documentations or PRs about this available, as I cannot find this information at the API reference https://docs.docker.com/engine/api/v1.28/#operation/ContainerAttachWebsocket?
@parisk actually I got it working locally but its still a bit hacky, I will clean it up and make a PR
Awesome, thanks!
If you need any help, feel free to ping
Any chance there has been traction here? I'm also hitting this issue and I was wondering if the proposed PR would be submitted soon? Thanks!
@jwbennet no idea about the plans of @FlorianLudwig on this, but I can definitely help you out submit one if you are interested.
Feel free to catch up on https://gitter.im/sourcelair/xterm.js for this.
Hey guys,
let me provide a bit of context. Docker changed the websocket data type to "binary". Which actually is the correct thing to do. But that means we got have to deal with decoding the data into a string. Which in JS actually is a lot fun.
First of all it depends how you did create your websocket since the websocket actually got two different data types it provides the data in: blob (the default) and arraybuffers.
To convert the blob into a string the most sensible thing to do seems to use a FileReader. Since the interface is asynchrone it needs to be buffered.
Implementation (attach.js)
const reader = new FileReader();
var readerBuffer = [];
reader.addEventListener('loadend', (e) => {
// ev.data instanceof Blob
var data = e.srcElement.result;
if (buffered) {
term._pushToBuffer(data);
} else {
term.write(data);
}
if(readerBuffer.length != 0) {
reader.readAsText(readerBuffer.shift());
}
});
term._getMessage = function (ev) {
if(reader.readyState != FileReader.LOADING) {
reader.readAsText(ev.data);
} else {
readerBuffer.push(ev.data);
}
};
The websocket must be setup up accordingly:
var socket = new WebSocket(socketURL, true)
socket.binaryType = 'arraybuffer'
Implementation (attach.js)
var decoder = new TextDecoder('utf-8')
term._getMessage = function (ev) {
var data = decoder.decode(ev.data);
if (buffered) {
term._pushToBuffer(data);
} else {
term.write(data);
}
};
Due to (not all browser)[https://caniuse.com/#search=TextDecoder] implementing text decoding a polyfill might be needed.
Adding some type checks it would be possible to support all three ways (string, blob and arrayBuffer websockets). To keep the code sane I would just support the arrayBuffer version though.
@FlorianLudwig, if the ArrayBuffer implementation just works with Docker's WebSocket endpoint, this should be just fine for the attach add-on.
The only pitfall I see here is that we have to take care manually of the IE11/Edge support.
I've been following this ticket, hoping it's the answer to my issue connecting to a docker process over the web. I've updated the attach.js file with the array buffer method shown above, but to no avail. There were no logs shown to give a sense of exactly what's going on, but when I make a connection attempt, the logs show something like this:
dockerd[3657]: time="2017-10-25T00:10:41.948164579Z" level=error msg="Error attaching websocket: %!s(<nil>)"
Any sense of what that means? I suppose my next step would be to attempt to install an earlier version of Docker, and determine whether this is actually the problem. But I would love to see this bug squashed!
I changed my Docker version to 17.03.2-ce, which has API version 1.27 (according to https://docs.docker.com/develop/sdk/#api-version-matrix). I ran the same test page, and got the same result as above in the logs.
Following this issue as well, that'd be pretty cool to have.
I do not have time to get on top of this, but if anyone can provide a PR for it I would love to review it.
@FlorianLudwig what's the status on your work?
I'm curious, this would be really useful for me as well.
The attach addon has changed a lot since this was made, please create a new issue if this is still a problem.