@wordpress/sync
Version:
333 lines (331 loc) • 11.1 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/sync/src/providers/webrtc-http-stream-signaling.js
var webrtc_http_stream_signaling_exports = {};
__export(webrtc_http_stream_signaling_exports, {
HttpSignalingConn: () => HttpSignalingConn,
WebrtcProviderWithHttpSignaling: () => WebrtcProviderWithHttpSignaling
});
module.exports = __toCommonJS(webrtc_http_stream_signaling_exports);
var import_y_webrtc = require("./y-webrtc/y-webrtc");
var cryptoutils = __toESM(require("./y-webrtc/crypto"));
var map = __toESM(require("lib0/map"));
var import_observable = require("lib0/observable");
var buffer = __toESM(require("lib0/buffer"));
var import_url = require("@wordpress/url");
function setupSignalEventHandlers(signalCon, url) {
signalCon.on("connect", () => {
(0, import_y_webrtc.log)(`connected (${url})`);
const topics = Array.from(import_y_webrtc.rooms.keys());
signalCon.send({ type: "subscribe", topics });
import_y_webrtc.rooms.forEach(
(room) => (0, import_y_webrtc.publishSignalingMessage)(signalCon, room, {
type: "announce",
from: room.peerId
})
);
});
signalCon.on(
"message",
(m) => {
switch (m.type) {
case "publish": {
const roomName = m.topic;
const room = import_y_webrtc.rooms.get(roomName);
if (room === null || typeof roomName !== "string" || room === void 0) {
return;
}
const execMessage = (data) => {
const webrtcConns = room.webrtcConns;
const peerId = room.peerId;
if (data === null || data.from === peerId || data.to !== void 0 && data.to !== peerId || room.bcConns.has(data.from)) {
return;
}
const emitPeerChange = webrtcConns.has(data.from) ? () => {
} : () => room.provider.emit("peers", [
{
removed: [],
added: [data.from],
webrtcPeers: Array.from(
room.webrtcConns.keys()
),
bcPeers: Array.from(room.bcConns)
}
]);
switch (data.type) {
case "announce":
if (webrtcConns.size < room.provider.maxConns) {
map.setIfUndefined(
webrtcConns,
data.from,
() => new import_y_webrtc.WebrtcConn(
signalCon,
true,
data.from,
room
)
);
emitPeerChange();
}
break;
case "signal":
if (data.signal.type === "offer") {
const existingConn = webrtcConns.get(
data.from
);
if (existingConn) {
const remoteToken = data.token;
const localToken = existingConn.glareToken;
if (localToken && localToken > remoteToken) {
(0, import_y_webrtc.log)(
"offer rejected: ",
data.from
);
return;
}
existingConn.glareToken = void 0;
}
}
if (data.signal.type === "answer") {
(0, import_y_webrtc.log)("offer answered by: ", data.from);
const existingConn = webrtcConns.get(
data.from
);
if (existingConn) {
existingConn.glareToken = void 0;
}
}
if (data.to === peerId) {
map.setIfUndefined(
webrtcConns,
data.from,
() => new import_y_webrtc.WebrtcConn(
signalCon,
false,
data.from,
room
)
).peer.signal(data.signal);
emitPeerChange();
}
break;
}
};
if (room.key) {
if (typeof m.data === "string") {
cryptoutils.decryptJson(
buffer.fromBase64(m.data),
room.key
).then(execMessage);
}
} else {
execMessage(m.data);
}
}
}
}
);
signalCon.on("disconnect", () => (0, import_y_webrtc.log)(`disconnect (${url})`));
}
function setupHttpSignal(httpClient) {
if (httpClient.shouldConnect && httpClient.ws === null) {
const subscriberId = Math.floor(1e5 + Math.random() * 9e5);
const url = httpClient.url;
const eventSource = new window.EventSource(
(0, import_url.addQueryArgs)(url, {
subscriber_id: subscriberId,
action: "gutenberg_signaling_server"
})
);
let pingTimeout = null;
eventSource.onmessage = (event) => {
httpClient.lastMessageReceived = Date.now();
const data = event.data;
if (data) {
const messages = JSON.parse(data);
if (Array.isArray(messages)) {
messages.forEach(onSingleMessage);
}
}
};
httpClient.ws = eventSource;
httpClient.connecting = true;
httpClient.connected = false;
const onSingleMessage = (message) => {
if (message && message.type === "pong") {
clearTimeout(pingTimeout);
pingTimeout = setTimeout(
sendPing,
messageReconnectTimeout / 2
);
}
httpClient.emit("message", [message, httpClient]);
};
const onclose = (error) => {
if (httpClient.ws !== null) {
httpClient.ws.close();
httpClient.ws = null;
httpClient.connecting = false;
if (httpClient.connected) {
httpClient.connected = false;
httpClient.emit("disconnect", [
{ type: "disconnect", error },
httpClient
]);
} else {
httpClient.unsuccessfulReconnects++;
}
}
clearTimeout(pingTimeout);
};
const sendPing = () => {
if (httpClient.ws && httpClient.ws.readyState === window.EventSource.OPEN) {
httpClient.send({
type: "ping"
});
}
};
if (httpClient.ws) {
httpClient.ws.onclose = () => {
onclose(null);
};
httpClient.ws.send = function send(message) {
window.fetch(url, {
body: new URLSearchParams({
subscriber_id: subscriberId.toString(),
action: "gutenberg_signaling_server",
message
}),
method: "POST"
}).catch(() => {
(0, import_y_webrtc.log)(
"Error sending to server with message: " + message
);
});
};
}
eventSource.onerror = () => {
};
eventSource.onopen = () => {
if (httpClient.connected) {
return;
}
if (eventSource.readyState === window.EventSource.OPEN) {
httpClient.lastMessageReceived = Date.now();
httpClient.connecting = false;
httpClient.connected = true;
httpClient.unsuccessfulReconnects = 0;
httpClient.emit("connect", [
{ type: "connect" },
httpClient
]);
pingTimeout = setTimeout(
sendPing,
messageReconnectTimeout / 2
);
}
};
}
}
var messageReconnectTimeout = 3e4;
var HttpSignalingConn = class extends import_observable.Observable {
/**
* @param {string} url
*/
constructor(url) {
super();
this.url = url;
this.ws = null;
this.binaryType = null;
this.connected = false;
this.connecting = false;
this.unsuccessfulReconnects = 0;
this.lastMessageReceived = 0;
this.shouldConnect = true;
this._checkInterval = setInterval(() => {
if (this.connected && messageReconnectTimeout < Date.now() - this.lastMessageReceived && this.ws) {
this.ws.close();
}
}, messageReconnectTimeout / 2);
setupHttpSignal(this);
this.providers = /* @__PURE__ */ new Set();
setupSignalEventHandlers(this, url);
}
/**
* @param {any} message
*/
send(message) {
if (this.ws) {
this.ws.send(JSON.stringify(message));
}
}
destroy() {
clearInterval(this._checkInterval);
this.disconnect();
super.destroy();
}
disconnect() {
this.shouldConnect = false;
if (this.ws !== null) {
this.ws.close();
}
}
connect() {
this.shouldConnect = true;
if (!this.connected && this.ws === null) {
setupHttpSignal(this);
}
}
};
var WebrtcProviderWithHttpSignaling = class extends import_y_webrtc.WebrtcProvider {
connect() {
this.shouldConnect = true;
this.signalingUrls.forEach((url) => {
const signalingConn = map.setIfUndefined(
import_y_webrtc.signalingConns,
url,
// Only this conditional logic to create a normal websocket connection or
// an http signaling connection was added to the constructor when compared
// with the base class.
url.startsWith("ws://") || url.startsWith("wss://") ? () => new import_y_webrtc.SignalingConn(url) : () => new HttpSignalingConn(url)
);
this.signalingConns.push(signalingConn);
signalingConn.providers.add(this);
});
if (this.room) {
this.room.connect();
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
HttpSignalingConn,
WebrtcProviderWithHttpSignaling
});
//# sourceMappingURL=webrtc-http-stream-signaling.js.map