Files
Tiber365/node_modules/crossws/dist/adapters/cloudflare-durable.mjs
2025-07-24 18:46:24 +02:00

142 lines
3.9 KiB
JavaScript

import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs';
import { a as adapterUtils, A as AdapterHookable } from '../shared/crossws.D9ehKjSh.mjs';
import 'uncrypto';
const cloudflareDurableAdapter = (opts = {}) => {
const hooks = new AdapterHookable(opts);
const peers = /* @__PURE__ */ new Set();
const resolveDurableStub = opts.resolveDurableStub || ((_req, env, _context) => {
const bindingName = opts.bindingName || "$DurableObject";
const binding = env[bindingName];
if (!binding) {
throw new Error(
`Durable Object binding "${bindingName}" not available`
);
}
const instanceId = binding.idFromName(opts.instanceName || "crossws");
return binding.get(instanceId);
});
return {
...adapterUtils(peers),
handleUpgrade: async (req, env, context) => {
const stub = await resolveDurableStub(req, env, context);
return stub.fetch(req);
},
handleDurableInit: async (obj, state, env) => {
},
handleDurableUpgrade: async (obj, request) => {
const { upgradeHeaders, endResponse } = await hooks.upgrade(
request
);
if (endResponse) {
return endResponse;
}
const pair = new WebSocketPair();
const client = pair[0];
const server = pair[1];
const peer = CloudflareDurablePeer._restore(
obj,
server,
request
);
peers.add(peer);
obj.ctx.acceptWebSocket(server);
await hooks.callHook("open", peer);
return new Response(null, {
status: 101,
webSocket: client,
headers: upgradeHeaders
});
},
handleDurableMessage: async (obj, ws, message) => {
const peer = CloudflareDurablePeer._restore(obj, ws);
await hooks.callHook("message", peer, new Message(message, peer));
},
handleDurableClose: async (obj, ws, code, reason, wasClean) => {
const peer = CloudflareDurablePeer._restore(obj, ws);
peers.delete(peer);
const details = { code, reason, wasClean };
await hooks.callHook("close", peer, details);
}
};
};
class CloudflareDurablePeer extends Peer {
get peers() {
return new Set(
this.#getwebsockets().map(
(ws) => CloudflareDurablePeer._restore(this._internal.durable, ws)
)
);
}
#getwebsockets() {
return this._internal.durable.ctx.getWebSockets();
}
send(data) {
return this._internal.ws.send(toBufferLike(data));
}
subscribe(topic) {
super.subscribe(topic);
const state = getAttachedState(this._internal.ws);
if (!state.t) {
state.t = /* @__PURE__ */ new Set();
}
state.t.add(topic);
setAttachedState(this._internal.ws, state);
}
publish(topic, data) {
const websockets = this.#getwebsockets();
if (websockets.length < 2) {
return;
}
const dataBuff = toBufferLike(data);
for (const ws of websockets) {
if (ws === this._internal.ws) {
continue;
}
const state = getAttachedState(ws);
if (state.t?.has(topic)) {
ws.send(dataBuff);
}
}
}
close(code, reason) {
this._internal.ws.close(code, reason);
}
static _restore(durable, ws, request) {
let peer = ws._crosswsPeer;
if (peer) {
return peer;
}
const state = ws.deserializeAttachment() || {};
peer = ws._crosswsPeer = new CloudflareDurablePeer({
ws,
request: request || { url: state.u },
durable
});
if (state.i) {
peer._id = state.i;
}
if (request?.url) {
state.u = request.url;
}
state.i = peer.id;
setAttachedState(ws, state);
return peer;
}
}
function getAttachedState(ws) {
let state = ws._crosswsState;
if (state) {
return state;
}
state = ws.deserializeAttachment() || {};
ws._crosswsState = state;
return state;
}
function setAttachedState(ws, state) {
ws._crosswsState = state;
ws.serializeAttachment(state);
}
export { cloudflareDurableAdapter as default };