UNPKG

lprest

Version:

Node.js packages to access LivePerson Rest APIs

400 lines (342 loc) 11.9 kB
var _ = require("lodash"); var util = new require("util"); var Q = require("q"); var events = require("events"); /* CHAT { link: { [Function] all: [ { rel: 'self', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878' }, { rel: 'events', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/events' }, { rel: 'info', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/info' }, { rel: 'next', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878?from=2' }, { rel: 'transcript-request', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/transcriptRequest' }, { rel: 'exit-survey', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/exitSurvey' }, { rel: 'custom-variables', href: 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/customVariables' }, { rel: 'visit-session', href: 'https://dev.liveperson.net/api/account/P9700259/visit/H5743203613919339957K8394878' } ] }, events: { link: [ { '@href': 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/events', '@rel': 'self' }, { '@href': 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/events?from=2', '@rel': 'next' } ], event: [ { '@id': '0', '@type': 'state', time: '2014-12-02T08:22:42.575-05:00', state: 'waiting' }, { '@id': '1', '@type': 'line', time: '2014-12-02T08:22:42.580-05:00', textType: 'plain', text: 'Please hold for a moment. I will be right with you.', by: 'info', source: 'system', systemMessageId: 4, subType: 'REGULAR' } ] }, info: { link: [ { '@href': 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/info', '@rel': 'self' }, { '@href': 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/info/visitorName', '@rel': 'visitor-name' }, { '@href': 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/info/visitorTyping', '@rel': 'visitor-typing' }, { '@href': 'https://dev.liveperson.net/api/account/P9700259/chat/H5743203613919339957-5243781235070630709K8394878/info/agentTyping', '@rel': 'agent-typing' } ], state: 'waiting', chatSessionKey: 'H5743203613919339957-5243781235070630709K8394878', skillName: 'LiveEngage', agentName: 'Adrian', agentId: 3, startTime: '2014-12-02T08:22:42.580-05:00', duration: 0, lastUpdate: '2014-12-02T08:22:43.498-05:00', chatTimeout: 40, visitorId: 15115019951810, agentTyping: 'not-typing', visitorTyping: 'not-typing', visitorName: 'test', rtSessionId: 4294973566 } } */ var STATE_ENDED = "ended"; var Chat = function Chat(accessor) { events.EventEmitter.call(this); var chat = this; this._accessor = accessor; this._entity = null; function eventsLoaded(events) { chat._entity.events = events; var array = events.event; if (typeof array === "undefined") { array = []; } else if (!_.isArray(array)) { array = [array]; } array.forEach(function (event) { process.nextTick(function () { chat.emit(event["@type"], event); }); }); return array; }; function infoLoaded(info) { chat._entity.info = info; process.nextTick(function () { chat.emit('info', info); }); return info; }; /** * The transition-state event is used internally, it is used when a new state event arrives * or when we manually use chat.end(); */ this.on("transition-state", function updateInternalState(state) { chat._entity.info.state = state; }); this.init = function () { return accessor.get().then(function (chatEntity) { chat._entity = chatEntity; infoLoaded(accessor.asEntity(chatEntity.info)); eventsLoaded(accessor.asEntity(chatEntity.events)); }).thenResolve(chat); }; /** * Loads this chat's info and is resolved with the info entity. * @returns {*} */ this.info = function () { return chat._entity.info.link("self").get().then(infoLoaded); }; /** * Loads all events and dispatches them on this chat object, resolved with the newly received event array * @returns {*} */ this.events = function () { return chat._entity.events.link("next").get().then(function (events) { return eventsLoaded(events); }); }; /** * Set the transcript email address. * Returns a promise that is resolved if success, or fails otherwise * @param email string email */ this.transcriptRequest = function (email) { return chat._entity.link("transcript-request").set({email: email}).thenResolve(); //Resolving with undefined. }; /** * Sends a new event to the chat. * Returns a promise that is resolved if success, or fails otherwise */ this.sendEvent = function (event) { return chat._entity.link("events").create({ event: event }).thenResolve(); //Resolving with undefined. }; /** * Sends a new event to the chat. * Returns a promise that is resolved if success, or fails otherwise */ this.end = function () { if(chat.state() !== STATE_ENDED) { return chat.sendState(STATE_ENDED).then(function() { chat.emit("transition-state", STATE_ENDED); }); } return Q(); }; /** * Sends a new state to the chat * Returns a promise that is resolved if success, or fails otherwise */ this.sendState = function (state) { var event = { "@type": "state", state: state }; return chat.sendEvent(event); }; /** * Sends a new state to the chat * Returns a promise that is resolved if success, or fails otherwise */ this.whenState = function (state) { if(chat.state() === state) { return Q(); } var defer = Q.defer(); var listener = function(data) { if(data.state === state) { chat.removeListener("state",listener); defer.resolve(); } }; chat.on("state", listener); return defer.promise; }; /** * Sends a new line of text to the chat * Returns a promise that is resolved if success, or fails otherwise */ this.sendLine = function (text) { var event = { "@type": "line", text: text }; return chat.sendEvent(event); }; /* * Get the transcript email address. * Returns a promise that is resolved if success, or fails otherwise * @param name string survey name */ this.exitSurvey = function (name) { return chat._entity.link("transcript-request") .get(name ? {"surveyName": name} : {}).thenResolve(); //Resolving with undefined. }; /* * Gets the visitor session entity, not yet implemented further */ this.visitSession = function (name) { return chat._entity.link("visit-session").get(); }; /* * Gets the chat session key */ this.chatSessionKey = function () { return chat._entity.info.chatSessionKey; }; /* * Gets the agentName associated with chat session */ this.agentName = function () { return chat._entity.info.agentName; }; /* * Gets the agent Id associated with chat session */ this.agentId = function () { return chat._entity.info.agentId; }; /** * Gets the latest info we received. * @returns {*} */ this.state = function () { return chat._entity && chat._entity.info.state; }; /** * Gets this chat's location * @returns {*} */ this.location = function () { return chat._entity.link.map.self; }; /* * Gets the visitor ID */ this.visitorId = function () { return chat._entity.info.visitorId; }; //Updating latest info chat.on("state", function(data) { this.emit("tranision-state", data.state); }); /* * Get the transcript email address. * Returns a promise that is resolved if success, or fails otherwise * @param email string email */ this.customVariables = function (map) { var array = []; for (var key in map) { if (map.hasOwnProperty(key)) { array.push({name: key, value: map[key]}); } } return chat._entity.link("custom-variables") .set({ "customVariables": { "customVariable": array } }).thenResolve(); //Resolving with undefined. }; /* * Starts chat polling at the specified interval. If an error occurs polling stops. * Returns a promise with an additional method 'stop' that stops polling (if a request was already sent it will * complete). * The promise is rejected if an error has occurred in a poll. * The promise is resolved after the poller was stopped. * @param halting if true the poller will stop itself when chat is ended. */ this.polling = function (timing, maxIdleTime, halting) { var poller = Q.defer(); var timer = 0; var lastEvents = Date.now(); function schedulePoll() { if (timing > 0) { timer = setTimeout(function () { chat.events().then(function (events) { poller.notify(events); var now = Date.now(); if (events.length) { lastEvents = now; } if (maxIdleTime && now - lastEvents > maxIdleTime) { stop(); } else { schedulePoll(); } }, poller.reject); //Passing the events to the poller promise. }, timing); } } var stop = poller.promise.stop = function stop(emitStopEvent) { console.error("POLLING STOP!"); poller.resolve(); timing = 0; //stop. if (timer !== 0) { clearTimeout(timer); timer = 0; } }; if(halting) { //This will never be rejected unless a programmatic error. chat.whenState(STATE_ENDED).done(stop); } schedulePoll(); return poller.promise; }; /** * When ended is a special promise that will be called whether we received an "ended" state event or if we successfully * sent an "ended" event to Liveperson. * That is, this promise is resolved whenever an end event has been sent or received. */ this.whenEnded = Q.Promise(function(resolve) { chat.whenState(STATE_ENDED, resolve); chat.on("transition-state", function(state) { if(state === STATE_ENDED) { resolve(); } }); }); this.whenState(STATE_ENDED, function() { this.removeAllListeners(); }); }; util.inherits(Chat, events.EventEmitter); Chat.fromPath = function(token, path) { } module.exports = Chat;