Open HaloWang opened 2 years ago
i sort of got it to work i think with the responseType "stream" API here are some snippets:
client side;
GM_xmlhttpRequest({
url: url.href,
timeout: 99999999,
headers: {
socket: this.socketId,
index: index
},
responseType: 'stream',
onreadystatechange: async (r) => {
if (r.state === r.OPENED && !this.opened) {
this.onopen?.();
this.opened = true;
}
if (r.status === 200 && !startedReading) {
startedReading = true;
const reader = r.response.getReader();
// eslint-disable-next-line no-constant-condition
while (true) {
const { done, value } = await reader.read(); // value is Uint8Array
if (value) {
const jsonStr = new TextDecoder().decode(value);
const jsonObj = JSON.parse(jsonStr);
debugger;
this.onmessage?.(jsonObj);
console.log(value.length, 'received');
}
if (done) { break; }
}
console.log('done');
}
},
ontimeout: (e) => {
if (this.options.reconnect) {
this.connect('timeout', index);
}
this.onclose?.();
}
});
server side socket implementation (node ,express,typescript)
send(data) {
const responseKey = Object.keys(this.connectionMap)[0];
const connection = this.connectionMap[responseKey];
if (!connection) {
debugger;
return;
}
if (!connection.sentHeaders) {
connection.response.setHeader('Content-Type', 'text/plain; charset=utf-8');
connection.response.setHeader('Transfer-Encoding', 'chunked');
connection.response.status(200).flushHeaders();
connection.sentHeaders = true;
}
const buffer = Buffer.from(JSON.stringify(data));
connection.response.write(buffer); //connection.response is just the default express response
// connection.response.end(); //dont call end or your handle wont work anymore
}
i sort of got it to work i think with the responseType "stream" API here are some snippets:
client side;
GM_xmlhttpRequest({ url: url.href, timeout: 99999999, headers: { socket: this.socketId, index: index, }, responseType: 'stream', onreadystatechange: async r => { if (r.state === r.OPENED && !this.opened) { this.onopen?.() this.opened = true } if (r.status === 200 && !startedReading) { startedReading = true const reader = r.response.getReader() // eslint-disable-next-line no-constant-condition while (true) { const { done, value } = await reader.read() // value is Uint8Array if (value) { const jsonStr = new TextDecoder().decode(value) const jsonObj = JSON.parse(jsonStr) debugger this.onmessage?.(jsonObj) console.log(value.length, 'received') } if (done) { break } } console.log('done') } }, ontimeout: e => { if (this.options.reconnect) { this.connect('timeout', index) } this.onclose?.() }, })
server side socket implementation (node ,express,typescript)
send(data) { const responseKey = Object.keys(this.connectionMap)[0]; const connection = this.connectionMap[responseKey]; if (!connection) { debugger; return; } if (!connection.sentHeaders) { connection.response.setHeader('Content-Type', 'text/plain; charset=utf-8'); connection.response.setHeader('Transfer-Encoding', 'chunked'); connection.response.status(200).flushHeaders(); connection.sentHeaders = true; } const buffer = Buffer.from(JSON.stringify(data)); connection.response.write(buffer); //connection.response is just the default express response // connection.response.end(); //dont call end or your handle wont work anymore }
Pretty good! I will try this approach
small update the stream api only works when sending data from backend to client
would be nice to also have support for the https://developer.chrome.com/articles/fetch-streaming-requests/ request streaming with fetch - didnt work when i tried it tho :( https://github.com/Tampermonkey/tampermonkey/issues/1757
@jonnytest1 what do you mean byy "from backend to client"? Is it not possible to send data from Tampermonkey to e.g. local app through websocket currently?
@Destroy666x well i havent found a way to stream a request body 🤔 what i did in he end was i just sent a new request from tampermonkey against the server every time an event happened and then matched the events to uuids i sent with the socket
what is timeline for this feature implementation?
@kryptoniancode I doubt there's any timeline. But a hint from me if you're looking for solutions - I was seeking OBS integration personally and obs-websocket-js
works perfectly with some tunelling for me. Maybe you'll find something similar for your use case.
Thanks I will look into this.
I mean, are there any built in functions like
GM_wsConnectTo()
because of some webpages forbid unauthorized websocket connection, for example: "ws://localhost:8000"?I think TM use built in function
GM_xmlHttpRequest
to avoid being blocked by website. So I ask this question.I'm not good at network programming. But using
GM_xmlHttpRequest
to tell server to upgrade connect to websocket seems like something not possible 🤔