tetratto/crates/app/src/public/js/streams.js

126 lines
3.6 KiB
JavaScript

(() => {
const self = reg_ns("streams");
self.STREAMS = {};
self.USER = null;
self.define("user", ({ $ }, user_id) => {
$.USER = user_id;
});
self.define("sock", ({ $ }, stream) => {
return $.STREAMS[stream];
});
self.define("get", ({ $ }, id) => {
for (const stream of Object.values($.STREAMS)) {
if (stream.id === id) {
return stream;
}
}
});
self.define("subscribe", ({ $ }, stream) => {
if (!$.USER) {
console.warn("cannot subscribe without user id");
return;
}
if ($.STREAMS[stream]) {
console.warn("stream already exists");
return $.STREAMS[stream];
}
const endpoint = `${window.location.origin.replace("http", "ws")}/api/v1/auth/user/${$.USER}/_connect/${stream}`;
const socket = new WebSocket(endpoint);
$.STREAMS[stream] = {
id: null,
socket,
events: {
message: () => {},
},
};
socket.addEventListener("message", (event) => {
if (event.data === "Ping") {
return socket.send("Pong");
}
const data = JSON.parse(event.data);
if (data.method.Forward === "Key") {
$.STREAMS[stream].id = data.data;
return console.info(`${stream} ${data.data}`);
} else if (data.method.Forward === "Javascript") {
const s = document.createElement("script");
s.setAttribute("type", "module");
s.setAttribute("data-received", Date.now().toString());
s.text = JSON.parse(data.data).js;
document.body.appendChild(s).parentNode.removeChild(s);
return console.info(
`${stream} received Forward(PacketType::Javascript) payload of ${data.data.length} bytes`,
);
}
return $.sock(stream).events.message(data);
});
return $.STREAMS[stream];
});
self.define("close", ({ $ }, stream) => {
const socket = $.sock(stream);
if (!socket) {
console.warn("no such stream to close");
return;
}
socket.socket.send("Close");
socket.socket.close();
});
self.define("event", async ({ $ }, stream, event, handler) => {
const socket = await $.sock(stream);
if (!socket) {
console.warn("no such stream to add event to");
return;
}
socket.events[event] = handler;
});
self.define("send_packet", async ({ $ }, stream, method, data) => {
return await (
await fetch(`/api/v1/auth/user/${$.USER}/_connect/${stream}/send`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
method,
data: JSON.stringify(data),
}),
})
).json();
});
self.define("send_packet_to", async (_, user, stream, method, data) => {
return await (
await fetch(`/api/v1/auth/user/${user}/_connect/${stream}/send`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
method,
data: JSON.stringify(data),
}),
})
).json();
});
})();