UNPKG

voxa

Version:

A fsm (state machine) framework for Alexa, Dialogflow, Facebook Messenger and Botframework apps using Node.js

190 lines 6.92 kB
"use strict"; /* * Copyright (c) 2018 Rain Agency <contact@rain.agency> * Author: Rain Agency <contact@rain.agency> * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ Object.defineProperty(exports, "__esModule", { value: true }); const _ = require("lodash"); const rp = require("request-promise"); const urljoin = require("url-join"); const uuid = require("uuid"); const errors_1 = require("../../errors"); const VoxaReply_1 = require("../../VoxaReply"); class BotFrameworkReply { constructor(event) { this.event = event; this.speak = ""; this.text = ""; this.textFormat = "plain"; this.type = "message"; this.channelId = event.rawEvent.message.address.channelId; if (!event.session) { throw new Error("event.session is missing"); } this.conversation = { id: event.session.sessionId }; this.from = { id: event.rawEvent.message.address.bot.id }; this.inputHint = "ignoringInput"; this.locale = event.request.locale; if (!event.user) { throw new Error("event.user is missing"); } this.recipient = { id: event.user.id, }; if (event.user.name) { this.recipient.name = event.user.name; } this.replyToId = event.rawEvent.message .address.id; this.timestamp = new Date().toISOString(); } get hasMessages() { return !!this.speak || !!this.text; } get hasDirectives() { return !!this.attachments || !!this.suggestedActions; } get hasTerminated() { return this.inputHint === "acceptingInput"; } get speech() { if (!this.speak) { return ""; } return this.speak; } toJSON() { return _.omit(this, "event"); } clear() { this.attachments = undefined; this.suggestedActions = undefined; this.text = ""; this.speak = ""; } terminate() { this.inputHint = "acceptingInput"; } addStatement(statement, isPlain = false) { if (this.inputHint === "ignoringInput") { this.inputHint = "expectingInput"; } if (isPlain) { this.text = VoxaReply_1.addToText(this.text, statement); } else { this.speak = VoxaReply_1.addToSSML(this.speak, statement); } } hasDirective(type) { throw new errors_1.NotImplementedError("hasDirective"); } addReprompt(reprompt) { return; } async send() { this.event.log.debug("partialReply", { hasDirectives: this.hasDirectives, hasMessages: this.hasMessages, sendingPartialReply: !(!this.hasMessages && !this.hasDirectives), }); if (!this.hasMessages && !this.hasDirectives) { return; } const uri = this.getReplyUri(this.event.rawEvent.message); this.id = uuid.v1(); await this.botApiRequest("POST", uri, _.clone(this), this.event); this.clear(); } async botApiRequest(method, uri, reply, event, attempts = 0) { let authorization; const platform = event.platform; authorization = await this.getAuthorization(platform.applicationId, platform.applicationPassword); const requestOptions = { auth: { bearer: authorization.access_token, }, body: this, json: true, method, uri, }; event.log.debug("botApiRequest", { requestOptions }); return rp(requestOptions); } getReplyUri(event) { const address = event.address; const baseUri = address.serviceUrl; if (!baseUri || !address.conversation) { throw new Error("serviceUrl is missing"); } const conversationId = encodeURIComponent(address.conversation.id); let path = `/v3/conversations/${conversationId}/activities`; if (address.id) { path += "/" + encodeURIComponent(address.id); } return urljoin(baseUri, path); } async getAuthorization(applicationId, applicationPassword) { const url = "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token"; const requestOptions = { form: { client_id: applicationId, client_secret: applicationPassword, grant_type: "client_credentials", scope: "https://api.botframework.com/.default", }, json: true, method: "POST", url, }; return (await rp(requestOptions)); } async saveSession(attributes, event) { const storage = event.platform.storage; const conversationId = encodeURIComponent(event.session.sessionId); const userId = event.rawEvent.message.address.bot.id; const context = { conversationId, persistConversationData: false, persistUserData: false, userId, }; const data = { conversationData: {}, // we're only gonna handle private conversation data, this keeps the code small // and more importantly it makes it so the programming model is the same between // the different platforms privateConversationData: attributes, userData: {}, }; await new Promise((resolve, reject) => { storage.saveData(context, data, (error) => { if (error) { return reject(error); } event.log.debug("savedStateData", { data, context }); return resolve(); }); }); } } exports.BotFrameworkReply = BotFrameworkReply; //# sourceMappingURL=BotFrameworkReply.js.map