text: const PubNub = require('pubnub');
  
  const credentials = {
      publishKey: 'pub-c-9dac929c-c743-4d55-9a28-4a0d68b0a739',
      subscribeKey: 'sub-c-35bb8436-f6ed-11eb-a919-a2ddbe22cd06'
  };
  
  const CHANNELS = {
      TEST: 'TEST',
      BLOCKCHAIN: 'BLOCKCHAIN',
      TRANSACTION: 'TRANSACTION'
  };
  
  class PubSub {
      constructor({ blockchain, transactionPool, wallet }) {
          this.blockchain = blockchain;
          this.transactionPool = transactionPool;
          this.wallet = wallet;
  
          this.pubnub = new PubNub(credentials);
  
          this.pubnub.subscribe({ channels: Object.values(CHANNELS) });
  
          this.pubnub.addListener(this.listener());
      }
  
      broadcastChain() {
          this.publish({
              channel: CHANNELS.BLOCKCHAIN,
              message: JSON.stringify(this.blockchain.chain)
          });
      }
  
      broadcastTransaction(transaction) {
          this.publish({
              channel: CHANNELS.TRANSACTION,
              message: JSON.stringify(transaction)
          });
      }
  
      subscribeToChannels() {
          this.pubnub.subscribe({
              channels: [Object.values(CHANNELS)]
          });
      }
  
      listener() {
          return {
              message: messageObject => {
                  const { channel, message } = messageObject;
  
                  console.log(`Message received. Channel: ${channel}. Message: ${message}`);
                  const parsedMessage = JSON.parse(message);
  
                  switch (channel) {
                      case CHANNELS.BLOCKCHAIN:
                          this.blockchain.replaceChain(parsedMessage, true, () => {
                              this.transactionPool.clearBlockchainTransactions(
                                  { chain: parsedMessage.chain }
                              );
                          });
                          break;
                      case CHANNELS.TRANSACTION:
                          if (!this.transactionPool.existingTransaction({
                              inputAddress: this.wallet.publicKey
                          })) {
                              this.transactionPool.setTransaction(parsedMessage);
                          }
                          break;
                      default:
                          return;
                  }
              }
          }
      }
  
      publish({ channel, message }) {
          this.pubnub.unsubscribe({ channel })
          setTimeout(() => this.pubnub.publish({ channel, message }), 3000)
          setTimeout(() => this.pubnub.subscribe({ channels: [Object.values(CHANNELS)] }), 6000)
      }
  
      broadcastChain() {
          this.publish({
              channel: CHANNELS.BLOCKCHAIN,
              message: JSON.stringify(this.blockchain.chain)
          });
      }
  
      broadcastTransaction(transaction) {
          this.publish({
              channel: CHANNELS.TRANSACTION,
              message: JSON.stringify(transaction)
          });
      }
  }
  
  module.exports = PubSub;