/**
 * @packageDocumentation
 *
 * > Don't use this module
 *
 * This module is a naive implementation of pubsub. It broadcasts all messages to all network peers, cannot provide older messages and has no protection against bad actors.
 *
 * It exists for academic purposes only, you should not use it in production.
 *
 * Instead please use [gossipsub](https://www.npmjs.com/package/@chainsafe/libp2p-gossipsub) - a more complete implementation which is also compatible with floodsub.
 *
 * @example Configuring libp2p to use floodsub
 *
 * ```TypeScript
 * import { createLibp2p } from 'libp2p'
 * import { floodsub } from '@libp2p/floodsub'
 *
 * const node = await createLibp2p({
 *   services: {
 *     pubsub: floodsub()
 *   }
 *   //... other options
 * })
 * await node.start()
 *
 * node.services.pubsub.subscribe('fruit')
 * node.services.pubsub.addEventListener('message', (evt) => {
 *   console.log(evt)
 * })
 *
 * node.services.pubsub.publish('fruit', new TextEncoder().encode('banana'))
 * ```
 */
import { pubSubSymbol, serviceCapabilities, serviceDependencies } from '@libp2p/interface';
import { PubSubBaseProtocol } from '@libp2p/pubsub';
import { toString } from 'uint8arrays/to-string';
import { SimpleTimeCache } from './cache.js';
import { multicodec } from './config.js';
import { RPC } from './message/rpc.js';
export { multicodec };
/**
 * FloodSub (aka dumbsub is an implementation of pubsub focused on
 * delivering an API for Publish/Subscribe, but with no CastTree Forming
 * (it just floods the network).
 */
class FloodSub extends PubSubBaseProtocol {
    seenCache;
    constructor(components, init) {
        super(components, {
            ...init,
            canRelayMessage: true,
            multicodecs: [multicodec]
        });
        this.log = components.logger.forComponent('libp2p:floodsub');
        /**
         * Cache of seen messages
         *
         * @type {TimeCache}
         */
        this.seenCache = new SimpleTimeCache({
            validityMs: init?.seenTTL ?? 30000
        });
    }
    [pubSubSymbol] = true;
    [Symbol.toStringTag] = '@libp2p/floodsub';
    [serviceCapabilities] = [
        '@libp2p/pubsub'
    ];
    [serviceDependencies] = [
        '@libp2p/identify'
    ];
    /**
     * Decode a Uint8Array into an RPC object
     */
    decodeRpc(bytes) {
        return RPC.decode(bytes);
    }
    /**
     * Encode an RPC object into a Uint8Array
     */
    encodeRpc(rpc) {
        return RPC.encode(rpc);
    }
    decodeMessage(bytes) {
        return RPC.Message.decode(bytes);
    }
    encodeMessage(rpc) {
        return RPC.Message.encode(rpc);
    }
    /**
     * Process incoming message
     * Extends base implementation to check router cache.
     */
    async processMessage(from, message) {
        // Check if I've seen the message, if yes, ignore
        const seqno = await super.getMsgId(message);
        const msgIdStr = toString(seqno, 'base64');
        if (this.seenCache.has(msgIdStr)) {
            return;
        }
        this.seenCache.put(msgIdStr, true);
        await super.processMessage(from, message);
    }
    /**
     * Publish message created. Forward it to the peers.
     */
    async publishMessage(from, message) {
        const peers = this.getSubscribers(message.topic);
        const recipients = [];
        if (peers == null || peers.length === 0) {
            this.log('no peers are subscribed to topic %s', message.topic);
            return { recipients };
        }
        peers.forEach(id => {
            if (this.components.peerId.equals(id)) {
                this.log('not sending message on topic %s to myself', message.topic);
                return;
            }
            if (id.equals(from)) {
                this.log('not sending message on topic %s to sender %p', message.topic, id);
                return;
            }
            this.log('publish msgs on topics %s %p', message.topic, id);
            recipients.push(id);
            this.send(id, { messages: [message] });
        });
        return { recipients };
    }
}
export function floodsub(init = {}) {
    return (components) => new FloodSub(components, init);
}
//# sourceMappingURL=index.js.map