# All files / src/client pubsub.js

87.72% Statements 50/57
71.43% Branches 10/14
78.57% Functions 11/14
87.76% Lines 43/49

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    1171x
    1x
    1x
    1x
    1x
    1x

    23x

    23x

    1027x

    1027x
    1025x
    1025x
    1025x

    1027x
    3081x
    1027x
    1027x

    1027x

    20020x
    20020x

    20020x

    20020x

    20020x
    20020x
    20020x

    1027x

    1027x

    1027x

    1027x

    1027x
    1025x
    1025x

    2x

    2054x
    1027x
    1027x

    1027x
    1027x
    1027x
    1027x

    1027x

    4x

    23x

     import { caller, expose } from 'postmsg-rpc'
    import callbackify from 'callbackify'
    import shortid from 'shortid'
    import { pre } from 'prepost'
    import { functionToJson } from '../serialization/function'
    import { isBufferJson, bufferFromJson, preBufferToJson } from '../serialization/buffer'

    export default function (opts) {
      const subs = [
      /*
        {
          topic,      // name of the topic subscribed to
          handler,    // the handler provided by the subscriber - rpc.exposedFn calls this function
          rpc: {      // details of the exposed RPC function created to receive updates
            fnName,   // the RPC function name
            exposedFn // the exposed RPC function created by postmsg-rpc
          }
        }
      */
      ]

      const api = {
        publish: callbackify.variadic(
          pre(
            preBufferToJson(1),
            caller('ipfs.pubsub.publish', opts)
          )
        ),
        subscribe: function (topic, options, handler, cb) {
          let sub

          if (typeof options === 'function') {
            cb = handler
            handler = options
            options = {}
          }

          const stub = pre(
            (...args) => {
              const handlerIndex = args.length === 3 ? 2 : 1
              const fnName = `ipfs.pubsub.subscribe.handler.${shortid()}`

              sub = {
                topic,
                handler,
                rpc: {
                  fnName,
                  exposedFn: expose(fnName, pre(
                    (...args) => {
                      Iif (isBufferJson(args[0].data)) {
                        args[0].data = bufferFromJson(args[0].data)
                      }

                      Iif (isBufferJson(args[0].seqno)) {
                        args[0].seqno = bufferFromJson(args[0].data)
                      }

                      return args
                    },
                    (...args) => {
                      process.nextTick(() => handler(...args))
                      return Promise.resolve()
                    }
                  ), opts)
                }
              }

              subs.push(sub)

              args[handlerIndex] = functionToJson(fnName)

              return args
            },
            // If error, then remove subscription handler
            (...args) => {
              return caller('ipfs.pubsub.subscribe', opts)(...args)
                .catch((err) => {
                  sub.rpc.exposedFn.close()
                  subs.splice(subs.indexOf(sub), 1)
                  throw err
                })
            }
          )

          if (cb) {
            stub(topic, options, handler)
              .then((res) => process.nextTick(() => cb(null, res)))
              .catch((err) => process.nextTick(() => cb(err)))
          } else {
            return stub(topic, options, handler)
          }
        },
        unsubscribe: pre(
          (...args) => {
            const topic = args[0]
            const sub = subs.find((s) => s.topic === topic && s.handler === args[1])

            Eif (sub) {
              args[1] = functionToJson(sub.rpc.fnName)
              sub.rpc.exposedFn.close()
              subs.splice(subs.indexOf(sub), 1)
            }

            return args
          },
          caller('ipfs.pubsub.unsubscribe', opts)
        ),
        peers: callbackify.variadic(caller('ipfs.pubsub.peers', opts)),
        ls: callbackify.variadic(caller('ipfs.pubsub.ls', opts)),
        // interface-ipfs-core tests use this function
        // noop since we're not an EventEmitter
        setMaxListeners: () => api
      }

      return api
    }