@ceramicnetwork/core
Version:
Typescript implementation of the Ceramic protocol
74 lines • 3.68 kB
JavaScript
import { Observable, EMPTY, pipe, of, from } from 'rxjs';
import { ServiceMetrics as Metrics } from '@ceramicnetwork/observability';
import { map, catchError, mergeMap, withLatestFrom, tap } from 'rxjs/operators';
import { deserialize, serialize } from './pubsub-message.js';
import { IncomingChannel, filterExternal, checkSlowObservable } from './incoming-channel.js';
import { TaskQueue } from '../ancillary/task-queue.js';
const textDecoder = new TextDecoder('utf-8');
function ipfsToPubsub(peerId$, pubsubLogger, topic) {
return pipe(withLatestFrom(peerId$), mergeMap(([incoming, peerId]) => of(incoming).pipe(map((incoming) => {
const message = deserialize(incoming);
const serializedMessage = serialize(message);
const logMessage = { ...incoming, ...JSON.parse(textDecoder.decode(serializedMessage)) };
delete logMessage.data;
delete logMessage.key;
delete logMessage.signature;
pubsubLogger.log({ peer: peerId, event: 'received', topic: topic, message: logMessage });
return message;
}), catchError(() => EMPTY))));
}
const PUBSUB_PUBLISHED = 'pubsub_published';
const PUBSUB_RECEIVED = 'pubsub_received';
export class Pubsub extends Observable {
constructor(ipfs, topic, resubscribeEvery, lateMessageAfter, pubsubLogger, logger, tasks = new TaskQueue()) {
super((subscriber) => {
const incoming$ = new IncomingChannel(ipfs, topic, resubscribeEvery, lateMessageAfter, pubsubLogger, logger, tasks);
incoming$
.pipe(filterExternal(this.peerId$), checkSlowObservable(lateMessageAfter, logger, `IPFS did not provide any internal messages, please check your IPFS configuration.`), ipfsToPubsub(this.peerId$, pubsubLogger, topic), tap((message) => {
Metrics.count(PUBSUB_RECEIVED, 1, { typ: message.typ });
}))
.subscribe(subscriber);
});
this.ipfs = ipfs;
this.topic = topic;
this.resubscribeEvery = resubscribeEvery;
this.lateMessageAfter = lateMessageAfter;
this.pubsubLogger = pubsubLogger;
this.logger = logger;
this.tasks = tasks;
this.peerId$ = from(this.ipfs.id().then((_) => _.id.toString()));
}
next(message) {
return this.peerId$
.pipe(mergeMap(async (peerId) => {
const serializedMessage = serialize(message);
const logMessage = { ...message, ...JSON.parse(textDecoder.decode(serializedMessage)) };
try {
await this.ipfs.pubsub.publish(this.topic, serializedMessage);
Metrics.count(PUBSUB_PUBLISHED, 1, { typ: message.typ });
this.pubsubLogger.log({
peer: peerId,
event: 'published',
topic: this.topic,
message: logMessage,
});
}
catch (error) {
this.pubsubLogger.log({
peer: peerId,
event: 'publish-error',
topic: this.topic,
message: logMessage,
});
if (error.message.includes('validation ignored')) {
this.logger.err(`HTTP validation error received while publishing message to pubsub, this usually indicates there was a duplicate message published and should be safe to ignore: ${error}`);
}
else {
this.logger.err(`Error received while publishing message to pubsub: ${error}`);
}
}
}))
.subscribe();
}
}
//# sourceMappingURL=pubsub.js.map