@boringnode/transmit
Version:
A framework agnostic Server-Sent-Event library
75 lines (74 loc) • 2.28 kB
JavaScript
/*
* @boringnode/transmit
*
* @license MIT
* @copyright BoringNode
*/
import { Stream } from './stream.js';
import { Storage } from './storage.js';
export class StreamManager {
#storage;
#securedChannels = new Map();
constructor() {
this.#storage = new Storage();
}
createStream({ uid, context, request, response, injectResponseHeaders, onConnect, onDisconnect, }) {
const stream = new Stream(uid, request);
stream.pipe(response, undefined, injectResponseHeaders);
this.#storage.add(stream);
onConnect?.({ uid, context });
response.on('close', () => {
this.#storage.remove(stream);
onDisconnect?.({ uid, context });
});
return stream;
}
async subscribe({ uid, channel, context, skipAuthorization = false, onSubscribe, }) {
if (!skipAuthorization) {
const canAccessChannel = await this.verifyAccess(channel, context);
if (!canAccessChannel) {
return false;
}
}
const subscribed = this.#storage.subscribe(uid, channel);
if (!subscribed) {
return false;
}
onSubscribe?.({ uid, channel, context: context });
return true;
}
async unsubscribe({ uid, channel, context, onUnsubscribe }) {
this.#storage.unsubscribe(uid, channel);
onUnsubscribe?.({ uid, channel, context: context });
return true;
}
authorize(channel, callback) {
this.#storage.secure(channel);
this.#securedChannels.set(channel, callback);
}
async verifyAccess(channel, context) {
const definitions = this.#storage.getSecuredChannelDefinition(channel);
if (!definitions) {
return true;
}
const callback = this.#securedChannels.get(definitions.channel);
try {
return await callback(context, definitions.params);
}
catch (e) {
return false;
}
}
/**
* Get all subscribers
*/
getAllSubscribers() {
return this.#storage.getAllSubscribers();
}
/**
* Find all subscribers to a channel
*/
findByChannel(channel) {
return this.#storage.findByChannel(channel);
}
}