@base44/sdk
Version:
JavaScript SDK for Base44 API
161 lines (160 loc) • 5.76 kB
JavaScript
import { io } from "socket.io-client";
import { getAccessToken } from "./auth-utils.js";
const ROOM_LEAVE_GRACE_MS = 250;
function initializeSocket(config, handlers) {
var _a;
const socket = io(config.serverUrl, {
path: config.mountPath,
transports: config.transports,
query: {
app_id: config.appId,
token: (_a = config.token) !== null && _a !== void 0 ? _a : getAccessToken(),
},
});
socket.on("connect", async () => {
var _a;
console.log("connect", socket.id);
return (_a = handlers.connect) === null || _a === void 0 ? void 0 : _a.call(handlers);
});
socket.on("update_model", async (msg) => {
var _a;
return (_a = handlers.update_model) === null || _a === void 0 ? void 0 : _a.call(handlers, msg);
});
socket.on("error", async (error) => {
var _a;
return (_a = handlers.error) === null || _a === void 0 ? void 0 : _a.call(handlers, error);
});
socket.on("connect_error", async (error) => {
var _a;
console.error("connect_error", error);
return (_a = handlers.error) === null || _a === void 0 ? void 0 : _a.call(handlers, error);
});
return socket;
}
export function RoomsSocket({ config }) {
let currentConfig = { ...config };
const roomsToListeners = {};
const pendingRoomLeaves = {};
const handlers = {
connect: async () => {
const promises = [];
Object.keys(roomsToListeners).forEach((room) => {
const listeners = getListeners(room);
if (listeners.length === 0) {
return;
}
joinRoom(room);
listeners.forEach(({ connect }) => {
const promise = async () => connect === null || connect === void 0 ? void 0 : connect();
promises.push(promise());
});
});
await Promise.all(promises);
},
update_model: async (msg) => {
const listeners = getListeners(msg.room);
const promises = listeners.map((listener) => { var _a; return (_a = listener.update_model) === null || _a === void 0 ? void 0 : _a.call(listener, msg); });
await Promise.all(promises);
},
error: async (error) => {
console.error("error", error);
const promises = Object.values(roomsToListeners)
.flat()
.map((listener) => { var _a; return (_a = listener.error) === null || _a === void 0 ? void 0 : _a.call(listener, error); });
await Promise.all(promises);
},
};
let socket = initializeSocket(config, handlers);
function cleanup() {
disconnect();
}
function disconnect() {
clearPendingRoomLeaves();
if (socket) {
socket.disconnect();
}
}
function updateConfig(config) {
cleanup();
currentConfig = {
...currentConfig,
...config,
};
socket = initializeSocket(currentConfig, handlers);
}
function joinRoom(room) {
socket.emit("join", room);
}
function leaveRoom(room) {
socket.emit("leave", room);
}
async function updateModel(room, data) {
var _a;
const dataStr = JSON.stringify(data);
return (_a = handlers.update_model) === null || _a === void 0 ? void 0 : _a.call(handlers, { room, data: dataStr });
}
function getListeners(room) {
var _a;
return (_a = roomsToListeners[room]) !== null && _a !== void 0 ? _a : [];
}
function cancelPendingRoomLeave(room) {
const pendingLeave = pendingRoomLeaves[room];
if (!pendingLeave) {
return;
}
clearTimeout(pendingLeave);
delete pendingRoomLeaves[room];
}
function clearPendingRoomLeaves() {
Object.keys(pendingRoomLeaves).forEach((room) => {
var _a, _b;
clearTimeout(pendingRoomLeaves[room]);
delete pendingRoomLeaves[room];
if (((_b = (_a = roomsToListeners[room]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) === 0) {
delete roomsToListeners[room];
}
});
}
function scheduleRoomLeave(room) {
cancelPendingRoomLeave(room);
pendingRoomLeaves[room] = setTimeout(() => {
var _a, _b;
delete pendingRoomLeaves[room];
if (((_b = (_a = roomsToListeners[room]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0) {
return;
}
leaveRoom(room);
delete roomsToListeners[room];
}, ROOM_LEAVE_GRACE_MS);
}
const subscribeToRoom = (room, handlers) => {
if (roomsToListeners[room]) {
cancelPendingRoomLeave(room);
}
else {
joinRoom(room);
roomsToListeners[room] = [];
}
roomsToListeners[room].push(handlers);
let unsubscribed = false;
return () => {
var _a, _b;
if (unsubscribed) {
return;
}
unsubscribed = true;
roomsToListeners[room] =
(_b = (_a = roomsToListeners[room]) === null || _a === void 0 ? void 0 : _a.filter((listener) => listener !== handlers)) !== null && _b !== void 0 ? _b : [];
if (roomsToListeners[room].length === 0) {
scheduleRoomLeave(room);
}
};
};
return {
socket,
subscribeToRoom,
updateConfig,
updateModel,
disconnect,
};
}