# All files / client pubsub.js

10.34% Statements 6/58
0% Branches 0/16
0% Functions 0/14
12% Lines 6/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    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
    117
    118
    1191x
    1x
    1x
    1x
    1x
    1x

     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) => {
                      if (args[0]) {
                        if (isBufferJson(args[0].data)) {
                          args[0].data = bufferFromJson(args[0].data)
                        }

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

                      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])

            if (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
    }