Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active July 23, 2023 20:59
Show Gist options
  • Save guest271314/49b0dfc91ac78fcc57c54485327646a8 to your computer and use it in GitHub Desktop.
Save guest271314/49b0dfc91ac78fcc57c54485327646a8 to your computer and use it in GitHub Desktop.
Browser <=> Deno fetch(), listenTls() full duplex streaming
#!/usr/bin/env -S deno run -A --unsafely-ignore-certificate-errors=localhost --unstable --v8-flags="--expose-gc,--jitless"
// Deno Native Messaging host
// guest271314, 10-5-2022
// Browser <=> Deno fetch(), listenTls() full duplex streaming
// 7-22-2023
/*
Usage:
port.postMessage({url:'https://localhost:8443', method:'post', body: `new ReadableStream({
async start(controller) {
await wait(1000);
controller.enqueue('This ');
await wait(1000);
controller.enqueue('is ');
await wait(1000);
controller.enqueue('a ');
await wait(1000);
controller.enqueue('slow ');
await wait(1000);
controller.enqueue('request.');
controller.close();
},
}).pipeThrough(new TextEncoderStream())`, eval: true})
port.postMessage({url:'https://github.com/guest271314/AudioWorkletStream/raw/master/house--64kbs-0-wav', method:'get', body: null})
*/
// https://github.com/denoland/deno/discussions/17236#discussioncomment-4566134
// https://github.com/saghul/txiki.js/blob/master/src/js/core/tjs/eval-stdin.js
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const wait = async (ms) => new Promise((r) => setTimeout(r, ms));
const responseInit = {
headers: {
'Connection': 'close',
'Cache-Control': 'no-cache',
'Content-Type': 'text/plain; charset=UTF-8',
'Cross-Origin-Opener-Policy': 'unsafe-none',
'Cross-Origin-Embedder-Policy': 'unsafe-none',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Private-Network': 'true',
'Access-Control-Allow-Headers': 'Access-Control-Request-Private-Network',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET,HEAD,QUERY',
},
};
async function readFullAsync(length) {
const buffer = new Uint8Array(65536);
const data = [];
let n = null;
while (data.length < length && (n = await Deno.stdin.read(buffer))) {
data.push(...buffer.subarray(0, n));
}
return new Uint8Array(data);
}
async function getMessage() {
const header = new Uint32Array(1);
await Deno.stdin.read(new Uint8Array(header.buffer));
const settings = JSON.parse(decoder.decode(await readFullAsync(header[0])));
return fetch(settings.url, {
method: settings.method,
headers: {
'Content-Type': 'text/plain',
'Access-Control-Request-Private-Network': true
},
body: settings.eval ? eval(settings.body) : settings.body
})
// .then((r) => r.body.pipeThrough(new TextDecoderStream()))
.then((r) => r.body.pipeTo(new WritableStream({
async write(value) {
await sendMessage(encodeMessage([...value]));
gc();
},
async close() {
await sendMessage(encodeMessage('Stream closed.'));
}
}))).catch(async (e) => {
await sendMessage(encodeMessage(e.message));
});
}
async function sendMessage(message) {
const header = new Uint32Array([message.length]);
await Deno.stdout.write(new Uint8Array(header.buffer));
await Deno.stdout.write(message);
}
function encodeMessage(message) {
return encoder.encode(JSON.stringify(message));
}
async function main() {
(async () => {
// https://medium.com/deno-the-complete-reference/http-2-in-deno-f825251a5ab2
for await (
const conn of Deno.listenTls({
port: 8443,
certFile: './certificate.pem',
keyFile: './certificate.key',
alpnProtocols: ["h2", "http/1.1"],
})
) {
for await (const {
request,
respondWith
}
of Deno.serveHttp(conn)) {
await sendMessage(encodeMessage(`fetch request method: ${request.method}`));
if (request.method === 'OPTIONS' || request.method === 'HEAD') {
respondWith(new Response(null, responseInit));
}
if (request.method === 'GET') {
respondWith(new Response(null, responseInit));
}
const stream = request.body;
/*
.pipeThrough(new TextDecoderStream())
.pipeThrough(
new TransformStream({
transform(value, c) {
c.enqueue(value.toUpperCase());
},
async flush() {
// await sendMessage(encodeMessage('TransformStream flush.'));
},
})
)
.pipeThrough(new TextEncoderStream());
*/
respondWith(new Response(
stream, responseInit));
}
}
})().catch(async (e) => {
await sendMessage(encoder.encode(e.message));
});
while (true) {
await getMessage();
gc();
}
}
try {
main();
} catch (e) {
Deno.exit();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment