Home Reference Source Repository

lib/pubsub.js

import skygear from 'skygear';
import uuid from 'uuid';
import _ from 'underscore';

const UserChannel = skygear.Record.extend('user_channel');

/**
 * SkygearChatPubsub is a class for dsipatching the message from user_channel
 * to the coorrect handler according to the event type and registeration
 */
export default class SkygearChatPubsub {
  constructor(container) {
    this.pubsub = container.pubsub;
    this.userChannel = null;
    this.dispatch = this.dispatch.bind(this);
    this.getUserChannel().then(this.subscribeDispatch.bind(this));
    this.typingHandler = {};
    this.allTypingHandler = [];
    this.messageHandler = [];
  }

  subscribeDispatch(channel) {
    this.pubsub.on(channel.name, this.dispatch);
  }

  dispatch(payload) {
    if (payload.event === 'typing') {
      this.dispatchTyping(payload.data);
    } else {
      this.dispatchUpdate(payload.data);
    }
  }

  dispatchUpdate(data) {
    const obj = {
      record_type: data.record_type,
      event_type: data.event_type
    };
    obj.record = new skygear.Record(data.record_type, data.record);
    if (data.original_record) {
      obj.original_record = new skygear.Record(
        data.record_type, data.original_record);
    }
    _.forEach(this.messageHandler, function (handler) {
      handler(obj);
    });
  }

  dispatchTyping(data) {
    _.forEach(this.allTypingHandler, function (ah) {
      ah(data);
    });
    _.forEach(data, function (t, conversationID) {
      const handlers = this.typingHandler[conversationID];
      _.forEach(handlers, function (h) {
        h(t);
      });
    }.bind(this));
  }

  sendTyping(conversation, state) {
    skygear.lambda('chat:typing', [
      conversation._id,
      state,
      new Date()
    ]);
  }

  subscribeAllTyping(handler) {
    this.allTypingHandler.push(handler);
  }

  subscribeTyping(conversation, handler) {
    if (!this.typingHandler[conversation.id]) {
      this.typingHandler[conversation.id] = [];
    }
    this.typingHandler[conversation.id].push(handler);
  }

  unsubscribeTyping(conversation, handler) {
    const index = this.typingHandler.indexOf(handler);
    if (!handler || index === -1) {
      this.typingHandler[conversation.id] = [];
    } else {
      this.typingHandler.splice(index, 1);
    }
  }

  subscribeMessage(handler) {
    this.messageHandler.push(handler);
  }

  unsubscribeMessage(handler) {
    const index = this.messageHandler.indexOf(handler);
    if (!handler || index === -1) {
      this.messageHandler = [];
    } else {
      this.messageHandler.splice(index, 1);
    }
  }

  getUserChannel() {
    if (this.userChannel) {
      return Promise.resolve(this.userChannel);
    }
    const query = new skygear.Query(UserChannel);
    return skygear.privateDB.query(query).then(function (records) {
      if (records.length > 0) {
        this.userChannel = records[0];
        return this.userChannel;
      }
      return null;
    }.bind(this)).then(function (record) {
      if (record === null) {
        const channel = new UserChannel();
        channel.name = uuid.v4();
        return skygear.privateDB.save(channel);
      }
      this.userChannel = record;
      return this.userChannel;
    }.bind(this));
  }
}