@ihadeed/transport-commons
Version:
Shared functionality for websocket providers
103 lines (84 loc) • 3.39 kB
text/typescript
import Debug from 'debug';
import { EventEmitter } from "events";
import { compact, flattenDeep, noop } from 'lodash';
import { Channel } from './channel/base';
import { CombinedChannel } from './channel/combined';
import { channelMixin, publishMixin, keys, PublishMixin, Event, Publisher } from './mixins';
import { Application, KeyValue, Service } from '@ihadeed/feathers';
const debug = Debug('@ihadeed/transport-commons/channels');
const { CHANNELS } = keys;
declare module '@ihadeed/feathers' {
interface ServiceAddons<T> {
publish (publisher: Publisher<T>): this;
publish (event: Event, publisher: Publisher<T>): this;
registerPublisher (publisher: Publisher<T>): this;
registerPublisher (event: Event, publisher: Publisher<T>): this;
}
interface Application<ServiceTypes extends KeyValue = any> extends EventEmitter {
channels: string[];
channel (name: string[]): Channel;
channel (...names: string[]): Channel;
publish<T> (publisher: Publisher<T>): this;
publish<T> (event: Event, publisher: Publisher<T>): this;
registerPublisher<T> (publisher: Publisher<T>): this;
registerPublisher<T> (event: Event, publisher: Publisher<T>): this;
}
}
export { keys };
export function channels () {
return (app: Application) => {
if (typeof app.channel === 'function' && typeof app.publish === 'function') {
return;
}
Object.assign(app, channelMixin(), publishMixin());
Object.defineProperty(app, 'channels', {
get () {
return Object.keys(this[CHANNELS]);
}
});
app.mixins.push((service: Service<any>, path: string) => {
if (typeof service.publish === 'function' || !service._serviceEvents) {
return;
}
Object.assign(service, publishMixin());
// @ts-ignore
service._serviceEvents.forEach((event: string) => {
service.on(event, function (data, hook) {
if (!hook) {
// Fake hook for custom events
hook = { path, service, app, result: data };
}
debug('Publishing event', event, hook.path);
const servicePublishers = (service as unknown as PublishMixin)[keys.PUBLISHERS];
const appPublishers = (app as unknown as PublishMixin)[keys.PUBLISHERS];
// This will return the first publisher list that is not empty
// In the following precedence
const publisher = (
// 1. Service publisher for a specific event
servicePublishers[event] ||
// 2. Service publisher for all events
servicePublishers[keys.ALL_EVENTS] ||
// 3. App publisher for a specific event
appPublishers[event] ||
// 4. App publisher for all events
appPublishers[keys.ALL_EVENTS] ||
// 5. No publisher
noop
);
Promise.resolve(publisher(data, hook)).then(result => {
if (!result) {
return;
}
const results = Array.isArray(result) ? compact(flattenDeep(result)) : [result];
const channel = new CombinedChannel(results);
if (channel && channel.length > 0) {
app.emit('publish', event, channel, hook, data);
} else {
debug('No connections to publish to');
}
});
});
});
});
};
}