UNPKG

5.71 kBPlain TextView Raw
1/**
2 * Copyright (c) Microsoft Corporation. All rights reserved.
3 * Licensed under the MIT License.
4 */
5import * as BB from 'botbuilder'
6import * as request from 'request'
7import * as semver from 'semver'
8import * as fs from 'fs-extra'
9import * as path from 'path'
10import * as crypto from 'crypto'
11import * as CLM from '@conversationlearner/models'
12
13export class Utils {
14 public static SendTyping(adapter: BB.BotAdapter, address: any) {
15 /* TODO
16 let msg = <builder.IMessage>{ type: 'typing'};
17 msg.address = address;
18 bot.post(msg);
19 */
20 }
21
22 /** Trick to get errors to render on Azure */
23 private static ReplaceErrors(key: any, value: any) {
24 if (value instanceof Error) {
25 const error = {}
26
27 Object.getOwnPropertyNames(value).forEach(k => {
28 error[k] = value[k]
29 })
30
31 return error
32 }
33
34 return value
35 }
36
37 /** Handle that catch clauses can be any type */
38 public static ErrorString(error: any, context: string = ''): string {
39 let prefix = context ? `${context}: ` : ''
40 try {
41 if (!error) {
42 return prefix + 'Unknown'
43 }
44 // Special message for 403 as it's like a bad ModelId
45 else if (error.statusCode === 403) {
46 return `403 Forbidden: Please check you have set a valid CONVERSATION_LEARNER_MODEL_ID`
47 }
48 else if (!error.body) {
49 if (typeof error == 'string') {
50 return prefix + error
51 } else {
52 return prefix + JSON.stringify(error, this.ReplaceErrors)
53 }
54 } else if (error.body.message) {
55 return prefix + error.body.message
56 } else if (error.body.errorMessages) {
57 return prefix + error.body.errorMessages.join()
58 } else if (typeof error.body == 'string') {
59 return prefix + error.body
60 } else {
61 return prefix + JSON.stringify(error.body)
62 }
63 } catch (e) {
64 return prefix + `Error Parsing Failed` //: ${Object.prototype.toString.call(e)} ${JSON.stringify(e)}`;
65 }
66 }
67
68 public static ReadFromFile(url: string): Promise<string> {
69 return new Promise((resolve, reject) => {
70 const requestData = {
71 url: url,
72 json: true,
73 encoding: 'utf8'
74 }
75 request.get(requestData, (error, response, body) => {
76 if (error) {
77 reject(error)
78 } else if (response.statusCode && response.statusCode >= 300) {
79 reject(body.message)
80 } else {
81 let model = String.fromCharCode.apply(null, body.data)
82 resolve(model)
83 }
84 })
85 })
86 }
87}
88
89const convertToMapById = (entityMap: CLM.FilledEntityMap): CLM.FilledEntityMap => {
90 const map = Object.keys(entityMap.map).reduce((newMap, key) => {
91 const filledEntity = entityMap.map[key]
92 if (!filledEntity.entityId) {
93 throw new Error(`Cannot convert filledEntityMap by name to filledEntityMap by id because id does not exist for entity: ${key}`)
94 }
95
96 newMap[filledEntity.entityId] = filledEntity
97
98 return newMap
99 }, {})
100
101 return new CLM.FilledEntityMap({ map })
102}
103
104export const addEntitiesById = (valuesByName: CLM.FilledEntityMap): CLM.FilledEntityMap => {
105 const valuesById = convertToMapById(valuesByName)
106 const map = {
107 ...valuesByName.map,
108 ...valuesById.map
109 }
110
111 return new CLM.FilledEntityMap({ map })
112}
113
114export function replace<T>(xs: T[], updatedX: T, getId: (x: T) => any): T[] {
115 const index = xs.findIndex(x => getId(x) === getId(updatedX))
116 if (index < 0) {
117 throw new Error(`You attempted to replace item in list with id: ${getId(updatedX)} but no item could be found. Perhaps you meant to add the item to the list or it was already removed.`)
118 }
119
120 return [...xs.slice(0, index), updatedX, ...xs.slice(index + 1)]
121}
122
123// Create checksum for determining when bot has changed
124export function botChecksum(callbacks: CLM.Callback[], templates: CLM.Template[]): string {
125 const source = `${JSON.stringify(callbacks)}${JSON.stringify(templates)}}`
126 return crypto.createHash('sha256').update(source).digest('hex')
127}
128
129/* Returns true is SDK version in package is less than passed in version */
130const packageJsonPath = path.join(__dirname, '..', 'package.json')
131export async function isSDKOld(curVersion: string): Promise<boolean> {
132 const packageJson = await fs.readJson(packageJsonPath)
133 if (packageJson.version === "0.0.0-development") {
134 return false
135 }
136 return semver.lt(packageJson.version, curVersion)
137}
138
139export function IsCardValid(card: string | Partial<BB.Activity>): boolean {
140 if (typeof card === 'string') {
141 return true
142 }
143 if (card.id && typeof card.id !== 'string') {
144 return false
145 }
146 return true
147}
148
149export function GetLogicAPIError(logicResult: CLM.LogicResult | undefined): CLM.LogicAPIError | null {
150 if (!logicResult) {
151 return null
152 }
153 if (!logicResult.logicValue) {
154 return null
155 }
156 const logicAPIResult = JSON.parse(logicResult.logicValue) as CLM.LogicAPIError
157 if (!logicAPIResult || !logicAPIResult.APIError) {
158 return null
159 }
160 return logicAPIResult
161}
162
163export const CL_DEVELOPER = 'ConversationLearnerDeveloper';
164export const UI_RUNNER_APPID = 'UIRunner_AppId'
165export const DEFAULT_MAX_SESSION_LENGTH = 20 * 60 * 1000; // 20 minutes
166
167