                     opts.cb?(if resp.error then resp.error else 'error')
                 else
                     opts.cb?(undefined, resp)
+                delete opts.cb
             @_hub_client_sockets[socket.id].callbacks[opts.message.id] = cb
         # Finally, send the message
         socket.write_mesg('json', opts.message)

                    dbg("failed")
                    delete @_hub_callbacks[opts.message.id]
                    opts.cb?("timeout after #{opts.timeout}s")
                timer = setTimeout(fail, opts.timeout*1000)
            opts.message.id ?= misc.uuid()
            cb = @_hub_callbacks[opts.message.id] = (resp) =>

            dbg()
            x = @_hub_client_sockets[socket.id] = {socket:socket, callbacks:{}, activity:new Date()}
            socket.on 'end', =>
                if not x.callbacks?
                    # end was already triggered
                    return
                dbg("end")
                for id, cb of x.callbacks
                    cb?('socket closed')
                delete x.callbacks  # so additional trigger of end doesn't do anything
                delete @_hub_client_sockets[socket.id]
                dbg("number of active sockets now equals #{misc.len(@_hub_client_sockets)}")
                if misc.len(@_hub_client_sockets) == 0
