* init commit

* save

* commit

* commit telemetry

* update

* add events

* change all to DEBUG

* add null check / add events

* added null check

* fix bug

* fix bug

Co-authored-by: Charlie Wang <charlwan@microsoft.com>
This commit is contained in:
charliewang95 2020-08-06 14:54:40 -05:00 коммит произвёл GitHub
Родитель 03fd0c1707
Коммит 22393d02d1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 459 добавлений и 20 удалений

Просмотреть файл

@ -8,6 +8,7 @@
]
}
],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-runtime"
],

194
package-lock.json сгенерированный
Просмотреть файл

@ -328,6 +328,194 @@
"@babel/plugin-syntax-async-generators": "^7.8.0"
}
},
"@babel/plugin-proposal-class-properties": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz",
"integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==",
"dev": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.10.4",
"@babel/helper-plugin-utils": "^7.10.4"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"dev": true,
"requires": {
"@babel/highlight": "^7.10.4"
}
},
"@babel/generator": {
"version": "7.10.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz",
"integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==",
"dev": true,
"requires": {
"@babel/types": "^7.10.5",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
},
"@babel/helper-create-class-features-plugin": {
"version": "7.10.5",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz",
"integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-member-expression-to-functions": "^7.10.5",
"@babel/helper-optimise-call-expression": "^7.10.4",
"@babel/helper-plugin-utils": "^7.10.4",
"@babel/helper-replace-supers": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.10.4"
}
},
"@babel/helper-function-name": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
"integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.10.4",
"@babel/template": "^7.10.4",
"@babel/types": "^7.10.4"
}
},
"@babel/helper-get-function-arity": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
"integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
"dev": true,
"requires": {
"@babel/types": "^7.10.4"
}
},
"@babel/helper-member-expression-to-functions": {
"version": "7.10.5",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz",
"integrity": "sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA==",
"dev": true,
"requires": {
"@babel/types": "^7.10.5"
}
},
"@babel/helper-optimise-call-expression": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz",
"integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==",
"dev": true,
"requires": {
"@babel/types": "^7.10.4"
}
},
"@babel/helper-plugin-utils": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
"integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
"dev": true
},
"@babel/helper-replace-supers": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz",
"integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==",
"dev": true,
"requires": {
"@babel/helper-member-expression-to-functions": "^7.10.4",
"@babel/helper-optimise-call-expression": "^7.10.4",
"@babel/traverse": "^7.10.4",
"@babel/types": "^7.10.4"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz",
"integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==",
"dev": true,
"requires": {
"@babel/types": "^7.10.4"
}
},
"@babel/helper-validator-identifier": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
"dev": true
},
"@babel/highlight": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.10.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz",
"integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==",
"dev": true
},
"@babel/template": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
"integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/parser": "^7.10.4",
"@babel/types": "^7.10.4"
}
},
"@babel/traverse": {
"version": "7.10.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz",
"integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.10.5",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.10.4",
"@babel/parser": "^7.10.5",
"@babel/types": "^7.10.5",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
"version": "7.10.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz",
"integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}
}
},
"@babel/plugin-proposal-dynamic-import": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz",
@ -3252,9 +3440,9 @@
"integrity": "sha512-jjQ6WkxrOu0rtGqY9/74Z+UEVQ7YmJU2rCX6kH4eidKP0ZK0VKB3/i1avXQ+EDwJAABKGaOAbJrcyz18P8E3aA=="
},
"elliptic": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
"integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",

Просмотреть файл

@ -11,6 +11,7 @@
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-object-rest-spread": "^7.9.0",
"@babel/plugin-transform-runtime": "^7.9.0",
"@babel/preset-env": "^7.9.0",

Просмотреть файл

@ -13,6 +13,8 @@ import Observable, { Observer } from 'core-js/features/observable';
import AbortController from 'abort-controller-es5';
import { IDirectLineActivity } from '../types/DirectLineTypes';
import shareObservable from '../utils/shareObservable';
import { StateKey } from '../types/ic3/IC3AdapterState';
import { TelemetryEvents } from '../types/ic3/TelemetryEvents';
export enum ConnectionStatus {
Uninitialized = 0,
@ -51,6 +53,16 @@ export default function exportDLJSInterface<TAdapterState extends AdapterState>(
await timeout(waitTime);
waitTime = waitTime*2;
}
if (!connectionStatusObserver) {
adapter.getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.ADAPTER_NOT_READY,
Description: `Adapter: Adapter not ready. ConnectionStatusObserver is null`
}
);
}
connectionStatusObserver.next(ConnectionStatus.Connected);
}else{
connectionStatusObserver.next(ConnectionStatus.Connected);

Просмотреть файл

@ -12,6 +12,7 @@ import createEgressEnhancer from './enhancers/egress/index';
import createIngressEnhancer from './enhancers/ingress/index';
import getPlatformBotId from './utils/getPlatformBotId';
import initializeIC3SDK from './initializeIC3SDK';
import { TelemetryEvents } from '../types/ic3/TelemetryEvents';
export default function createIC3Enhancer({
chatToken,
@ -27,7 +28,12 @@ export default function createIC3Enhancer({
conversation,
featureConfig
}: IIC3AdapterOptions & { sdkUrl?: string }): AdapterEnhancer<IC3DirectLineActivity, IC3AdapterState> {
if (!chatToken) {
logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{ Event: TelemetryEvents.CHAT_TOKEN_NOT_FOUND,
Description: `Adapter: "chatToken" must be specified`
});
throw new Error('"chatToken" must be specified.');
}
@ -51,9 +57,14 @@ export default function createIC3Enhancer({
adapter.setState(StateKey.UserDisplayName, undefined);
adapter.setState(StateKey.UserId, undefined);
adapter.setState(StateKey.FeatureConfig, undefined);
adapter.setState(StateKey.Logger, undefined);
(async function () {
if(!conversation){
logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{ Event: TelemetryEvents.IC3_SDK_INITIALIZE_STARTED,
Description: `Adapter: No conversation found; initializing IC3 SDK`
});
const sdk = await initializeIC3SDK(
sdkURL,
{
@ -67,7 +78,16 @@ export default function createIC3Enhancer({
visitor
}
);
logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{ Event: TelemetryEvents.IC3_SDK_JOIN_CONVERSATION_STARTED,
Description: `Adapter: No conversation found; joinging conversation`
});
conversation = await sdk.joinConversation(chatToken.chatId, sendHeartBeat);
logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{ Event: TelemetryEvents.IC3_SDK_JOIN_CONVERSATION_SUCCESS,
Description: `Adapter: No conversation found; join conversation success`
});
}
const botId = await getPlatformBotId(conversation);
@ -77,6 +97,7 @@ export default function createIC3Enhancer({
adapter.setState(StateKey.UserDisplayName, userDisplayName);
adapter.setState(StateKey.UserId, userId);
adapter.setState(StateKey.FeatureConfig, featureConfig);
adapter.setState(StateKey.Logger, logger);
adapter.setReadyState(ReadyState.OPEN);
})();

Просмотреть файл

@ -5,13 +5,14 @@ import { IC3AdapterState, StateKey } from '../../../types/ic3/IC3AdapterState';
import { ActivityType } from '../../../types/DirectLineTypes';
import { EgressMiddleware } from '../../../applyEgressMiddleware';
import { IC3DirectLineActivity } from '../../../types/ic3/IC3DirectLineActivity';
import uniqueId from '../../utils/uniqueId';
import { TelemetryEvents } from '../../../types/ic3/TelemetryEvents';
export default function createEgressMessageActivityMiddleware(): EgressMiddleware<
IC3DirectLineActivity,
IC3AdapterState
> {
return ({ getState }) => next => async (activity: IC3DirectLineActivity) => {
if (activity.type !== ActivityType.Message || !(activity.attachments || []).length) {
return next(activity);
}
@ -19,6 +20,12 @@ export default function createEgressMessageActivityMiddleware(): EgressMiddlewar
const conversation: Microsoft.CRM.Omnichannel.IC3Client.Model.IConversation = getState(StateKey.Conversation);
if (!conversation) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
Description: `Adapter: Failed to egress without an active conversation.`
}
);
throw new Error('IC3: Failed to egress without an active conversation.');
}
@ -37,6 +44,12 @@ export default function createEgressMessageActivityMiddleware(): EgressMiddlewar
const res = await fetch(contentUrl);
if (!res.ok) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.FETCH_ATTACHMENT_FAILED,
Description: `Adapter: Failed to fetch attachment to send.`
}
);
throw new Error('IC3: Failed to fetch attachment to send.');
}

Просмотреть файл

@ -5,12 +5,14 @@ import { IC3AdapterState, StateKey } from '../../../types/ic3/IC3AdapterState';
import { ActivityType } from '../../../types/DirectLineTypes';
import { EgressMiddleware } from '../../../applyEgressMiddleware';
import { IC3DirectLineActivity } from '../../../types/ic3/IC3DirectLineActivity';
import { TelemetryEvents } from '../../../types/ic3/TelemetryEvents';
export default function createEgressMessageActivityMiddleware(): EgressMiddleware<
IC3DirectLineActivity,
IC3AdapterState
> {
return ({ getState }) => next => async (activity: IC3DirectLineActivity) => {
if (activity.type !== ActivityType.Message) {
return next(activity);
}
@ -18,6 +20,12 @@ export default function createEgressMessageActivityMiddleware(): EgressMiddlewar
const conversation: Microsoft.CRM.Omnichannel.IC3Client.Model.IConversation = getState(StateKey.Conversation);
if (!conversation) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
Description: `Adapter: Failed to egress without an active conversation.`
}
);
throw new Error('IC3: Failed to egress without an active conversation.');
}
@ -70,8 +78,20 @@ export default function createEgressMessageActivityMiddleware(): EgressMiddlewar
(channelData.uploadedFileMetadata as unknown) as Microsoft.CRM.Omnichannel.IC3Client.Model.IFileMetadata,
message
);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.SEND_FILE_SUCCESS,
Description: `Adapter: Successfully sent a file with clientmessageid ${message.clientmessageid}`
}
);
} else {
await conversation.sendMessage(message);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.SEND_MESSAGE_SUCCESS,
Description: `Adapter: Successfully sent a message with clientmessageid ${message.clientmessageid}`
}
);
}
};
}

Просмотреть файл

@ -6,6 +6,7 @@ import { ActivityType } from '../../../types/DirectLineTypes';
import { EgressMiddleware } from '../../../applyEgressMiddleware';
import { IC3DirectLineActivity } from '../../../types/ic3/IC3DirectLineActivity';
import { MessageTag } from '../../../types/ic3/MessageTag';
import { TelemetryEvents } from '../../../types/ic3/TelemetryEvents';
const TYPING_INDICATOR_PAYLOAD = '{"isTyping":true}';
@ -18,6 +19,7 @@ export default function createEgressTypingActivityMiddleware(): EgressMiddleware
IC3AdapterState
> {
return ({ getState }) => next => (activity: IC3DirectLineActivity) => {
if (activity.type !== ActivityType.Typing) {
return next(activity);
}
@ -37,5 +39,12 @@ export default function createEgressTypingActivityMiddleware(): EgressMiddleware
botId &&
!isInternalActivity(activity) &&
conversation.sendMessageToBot(botId, { payload: TYPING_INDICATOR_PAYLOAD });
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.SEND_TYPING_SUCCESS,
Description: `Adapter: Successfully sent a typing indication`
}
);
};
}

Просмотреть файл

@ -1,10 +1,11 @@
/// <reference path="../../../types/ic3/external/Model.d.ts" />
import { ActivityType } from '../../../types/DirectLineTypes';
import { IC3AdapterState } from '../../../types/ic3/IC3AdapterState';
import { IC3AdapterState, StateKey } from '../../../types/ic3/IC3AdapterState';
import { IC3DirectLineActivity } from '../../../types/ic3/IC3DirectLineActivity';
import { IngressMiddleware } from '../../../applyIngressMiddleware';
import updateIn from 'simple-update-in';
import { TelemetryEvents } from '../../../types/ic3/TelemetryEvents';
const ADAPTIVE_CARD_ACTION_SUBMIT = 'Action.Submit';
const ADAPTIVE_CARD_ACTION_TYPE_MAP: { [id: string]: string } = {
@ -63,7 +64,8 @@ function processAdaptiveCardAttachments(attachments: any[]): any[] {
}
export default function createExtractAdaptiveCardMiddleware(): IngressMiddleware<IC3DirectLineActivity, IC3AdapterState> {
return () => next => (activity: IC3DirectLineActivity) => {
return ({ getState }) => next => (activity: IC3DirectLineActivity) => {
if (activity.type !== ActivityType.Message) {
return next(activity);
}
@ -77,13 +79,23 @@ export default function createExtractAdaptiveCardMiddleware(): IngressMiddleware
const xmlDoc = new DOMParser().parseFromString(text, CONTENT_TEXT_XML);
if (xmlDoc.getElementsByTagName(TAG_PARSE_ERROR).length) {
console.warn(`IC3: [AdaptiveCard] Unable to parse XML; ignoring attachment.`);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
Description: `Adapter: [AdaptiveCard] Unable to parse XML; ignoring attachment.`
}
);
return next(activity);
}
if (xmlDoc.documentElement.nodeName !== CONTENT_URI_OBJECT) {
console.warn(`IC3: [AdaptiveCard] Wrong XML schema; ignoring attachment.`);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
Description: `Adapter: [AdaptiveCard] Wrong XML schema; ignoring attachment.`
}
);
return next(activity);
}
@ -91,7 +103,12 @@ export default function createExtractAdaptiveCardMiddleware(): IngressMiddleware
const swiftElement = xmlDoc.getElementsByTagName(TAG_SWIFT)[0];
if (!swiftElement) {
console.warn(`IC3: [AdaptiveCard] Did not contains <Swift>; ignoring attachment.`);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
Description: `Adapter: [AdaptiveCard] Does not contain <Swift>; ignoring attachment.`
}
);
return next(activity);
}
@ -100,7 +117,12 @@ export default function createExtractAdaptiveCardMiddleware(): IngressMiddleware
const swiftJSON = base64DecodeAsUnicode(base64);
if (!swiftJSON) {
console.warn(`IC3: [AdaptiveCard] Data is empty; ignoring attachment.`);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
Description: `Adapter: [AdaptiveCard] Data is empty; ignoring attachment.`
}
);
return next(activity);
}
@ -114,7 +136,12 @@ export default function createExtractAdaptiveCardMiddleware(): IngressMiddleware
}
if (!swift.attachments) {
console.warn(`IC3: [AdaptiveCard] Key 'attachments' not found; ignoring attachment.`);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
Description: `Adapter: [AdaptiveCard] Key 'attachments' not found; ignoring attachment.`
}
);
return next(activity);
}
@ -124,7 +151,13 @@ export default function createExtractAdaptiveCardMiddleware(): IngressMiddleware
try {
attachments = processAdaptiveCardAttachments(swift.attachments);
} catch (error) {
console.warn('IC3: [AdaptiveCard] Failed to process attachments; ignoring attachment.', swift);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.ADAPTIVE_CARD_PROCESSING_ERROR,
Description: `Adapter: [AdaptiveCard] Failed to process attachments; ignoring attachment.`,
ExceptionDetails: error
}
);
return next(activity);
}

Просмотреть файл

@ -8,6 +8,7 @@ import { GetStateFunction } from '../../../../types/AdapterTypes';
import { IC3DirectLineActivity } from '../../../../types/ic3/IC3DirectLineActivity';
import { IC3_CHANNEL_ID } from '../../../Constants';
import uniqueId from '../../../utils/uniqueId';
import { TelemetryEvents } from '../../../../types/ic3/TelemetryEvents';
export default function createTypingMessageToDirectLineActivityMapper ({ getState }: { getState: GetStateFunction<IC3AdapterState>;}):
AsyncMapper<Microsoft.CRM.Omnichannel.IC3Client.Model.IThread, IC3DirectLineActivity>
@ -16,6 +17,12 @@ AsyncMapper<Microsoft.CRM.Omnichannel.IC3Client.Model.IThread, IC3DirectLineActi
const conversation: Microsoft.CRM.Omnichannel.IC3Client.Model.IConversation = getState(StateKey.Conversation);
if (!conversation) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
Description: `Adapter: Failed to ingress without an active conversation.`
}
);
throw new Error('IC3: Failed to ingress without an active conversation.');
}

Просмотреть файл

@ -8,6 +8,7 @@ import { GetStateFunction } from '../../../../types/AdapterTypes';
import { IC3DirectLineActivity } from '../../../../types/ic3/IC3DirectLineActivity';
import { IC3_CHANNEL_ID } from '../../../Constants';
import uniqueId from '../../../utils/uniqueId';
import { TelemetryEvents } from '../../../../types/ic3/TelemetryEvents';
export default function createTypingMessageToDirectLineActivityMapper({
getState
@ -15,6 +16,7 @@ export default function createTypingMessageToDirectLineActivityMapper({
getState: GetStateFunction<IC3AdapterState>;
}): AsyncMapper<Microsoft.CRM.Omnichannel.IC3Client.Model.IMessage, IC3DirectLineActivity> {
return next => async (message: Microsoft.CRM.Omnichannel.IC3Client.Model.IMessage) => {
if (message.messageType !== Microsoft.CRM.Omnichannel.IC3Client.Model.MessageType.Typing && message.messageType !== Microsoft.CRM.Omnichannel.IC3Client.Model.MessageType.ClearTyping) {
return next(message);
}
@ -22,6 +24,12 @@ export default function createTypingMessageToDirectLineActivityMapper({
const conversation: Microsoft.CRM.Omnichannel.IC3Client.Model.IConversation = getState(StateKey.Conversation);
if (!conversation) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
Description: `Adapter: Failed to ingress without an active conversation.`
}
);
throw new Error('IC3: Failed to ingress without an active conversation.');
}

Просмотреть файл

@ -8,6 +8,7 @@ import { GetStateFunction } from '../../../../types/AdapterTypes';
import { IC3DirectLineActivity } from '../../../../types/ic3/IC3DirectLineActivity';
import { IC3_CHANNEL_ID } from '../../../Constants';
import uniqueId from '../../../utils/uniqueId';
import { TelemetryEvents } from '../../../../types/ic3/TelemetryEvents';
const IMAGE_CONTENT_TYPES: { [type: string]: string } = {
//image
@ -61,13 +62,26 @@ export default function createUserMessageToDirectLineActivityMapper({
getState: GetStateFunction<IC3AdapterState>;
}): AsyncMapper<Microsoft.CRM.Omnichannel.IC3Client.Model.IMessage, IC3DirectLineActivity> {
return next => async (message: Microsoft.CRM.Omnichannel.IC3Client.Model.IMessage) => {
if (message.messageType !== Microsoft.CRM.Omnichannel.IC3Client.Model.MessageType.UserMessage) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
Description: `Adapter: Failed to ingress without an active conversation.`
}
);
return next(message);
}
const conversation: Microsoft.CRM.Omnichannel.IC3Client.Model.IConversation = getState(StateKey.Conversation);
if (!conversation) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.CONVERSATION_NOT_FOUND,
Description: `Adapter: Failed to ingress without an active conversation.`
}
);
throw new Error('IC3: Failed to ingress without an active conversation.');
}

Просмотреть файл

@ -11,6 +11,7 @@ import { compose } from 'redux';
import createThreadToDirectLineActivityMapper from './mappers/createThreadToDirectLineActivityMapper';
import createTypingMessageToDirectLineActivityMapper from './mappers/createTypingMessageToDirectLineActivityMapper';
import createUserMessageToDirectLineActivityMapper from './mappers/createUserMessageToDirectLineActivityMapper';
import { TelemetryEvents } from '../../../types/ic3/TelemetryEvents';
export default function createSubscribeNewMessageAndThreadUpdateEnhancer(): AdapterEnhancer<
IC3DirectLineActivity,
@ -20,11 +21,23 @@ export default function createSubscribeNewMessageAndThreadUpdateEnhancer(): Adap
const convertMessage = compose(
createUserMessageToDirectLineActivityMapper({ getState }),
createTypingMessageToDirectLineActivityMapper({ getState })
)(message => console.warn('IC3: Unknown type of message; ignoring message.', message));
)(message => {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.UNKNOWN_MESSAGE_TYPE,
Description: `Adapter: Unknown message type; ignoring message ${message}`
}
);
});
const convertThread = createThreadToDirectLineActivityMapper({ getState })(thread =>
console.warn('IC3: Unknown type of thread; ignoring thread.', thread)
);
const convertThread = createThreadToDirectLineActivityMapper({ getState })(thread => {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.WARN,
{
Event: TelemetryEvents.UNKNOWN_THREAD_TYPE,
Description: `Adapter: Unknown thread type; ignoring thread ${thread}`
}
);
});
function timeout(ms: number){
return new Promise(resolve => setTimeout(() => {
@ -39,7 +52,13 @@ export default function createSubscribeNewMessageAndThreadUpdateEnhancer(): Adap
new Observable<IC3DirectLineActivity>(subscriber => {
const conversation = value as Microsoft.CRM.Omnichannel.IC3Client.Model.IConversation;
const next = subscriber.next.bind(subscriber);
window.addEventListener("reinitialize", async (event) => {
window.addEventListener("reinitialize", async (event) => {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.REHYDRATE_MESSAGES,
Description: `Adapter: Re-hydrating received messages`
}
);
if(ConnectivityManager.isInternetConnected()){
(await conversation.getMessages()).forEach(async message => {
let activity = await convertMessage(message);
@ -57,22 +76,62 @@ export default function createSubscribeNewMessageAndThreadUpdateEnhancer(): Adap
await timeout(waitTime);
waitTime *= 2;
}
if (getReadyState() != ReadyState.OPEN) {
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.ADAPTER_NOT_READY,
Description: `Adapter: Adapter not ready. ReadyState is not OPEN`
}
);
}
(await conversation.getMessages()).forEach(async message => {
if (unsubscribed) { return; }
let activity = await convertMessage(message);
!unsubscribed && next(activity);
});
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.GET_MESSAGES_SUCCESS,
Description: `Adapter: Getting messages success`
}
);
conversation.registerOnNewMessage(async message => {
if (unsubscribed) { return; }
let activity: any = await convertMessage(message);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.MESSAGE_RECEIVED,
Description: `Adapter: Received a message with id ${activity.id}`
}
);
!unsubscribed && next(activity);
});
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.REGISTER_ON_NEW_MESSAGE,
Description: `Adapter: Registering on new message success`
}
);
conversation.registerOnThreadUpdate(async thread => {
if (unsubscribed) { return; }
!unsubscribed && next(await convertThread(thread));
let activity: any = await convertThread(thread);
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.THREAD_UPDATE_RECEIVED,
Description: `Adapter: Received a thread update with id ${activity.id}`
}
);
!unsubscribed && next(activity);
});
getState(StateKey.Logger)?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.REGISTER_ON_THREAD_UPDATE,
Description: `Adapter: Registering on thread update success`
}
);
})();
return () => {

Просмотреть файл

@ -1,6 +1,9 @@
/// <reference path="../types/ic3/external/Model.d.ts" />
/// <reference path="../types/ic3/external/SDK.d.ts" />
import { IAdapterLogger } from "./telemetry/IAdapterLogger";
import { TelemetryEvents } from "../types/ic3/TelemetryEvents";
const DEFAULT_SDK_URL = 'https://comms.omnichannelengagementhub.com/release/2019.12.27.1/Scripts/SDK/SDK.min.js';
export default function getSDKFromURL(
@ -16,7 +19,15 @@ export default function getSDKFromURL(
script.addEventListener('load', () => resolve(Microsoft.CRM.Omnichannel.IC3Client.SDK.SDKProvider.getSDK(options)));
script.addEventListener('error', ({ error }) =>
reject(error || new Error(`Failed to load IC3 SDK from URL: ${url}`))
{
options?.logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.IC3_SDK_NOT_FOUND,
Description: `Adapter: Failed to load IC3 SDK from URL: ${url}`
}
);
reject(error || new Error(`Failed to load IC3 SDK from URL: ${url}`))
}
);
document.head.append(script);

Просмотреть файл

@ -1,6 +1,10 @@
import getSDKFromURL from './getSDKFromURL';
import { IAdapterLogger } from './telemetry/IAdapterLogger';
import { TelemetryEvents } from '../types/ic3/TelemetryEvents';
let _sdk: Microsoft.CRM.Omnichannel.IC3Client.Model.ISDK | null = null;
let _sdkInfo: any;
export default async function initializeIC3SDK(
sdkURL: string | undefined,
options: Microsoft.CRM.Omnichannel.IC3Client.Model.IClientSDKInitializationParameters,
@ -16,9 +20,21 @@ export default async function initializeIC3SDK(
try{
const sdk = await getSDKFromURL(sdkURL, options);
await sdk.initialize(sessionInfo);
options?.logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.DEBUG,
{
Event: TelemetryEvents.IC3_SDK_INITIALIZE_SUCCESS,
Description: `Adapter: IC3 SDK initialization success`
}
);
_sdk = sdk;
} catch(error){
_sdk = null;
options?.logger?.logClientSdkTelemetryEvent(Microsoft.CRM.Omnichannel.IC3Client.Model.LogLevel.ERROR,
{
Event: TelemetryEvents.IC3_SDK_INITIALIZE_FAILURE,
Description: `Adapter: IC3 SDK initialization failure`
}
);
throw error;
}

Просмотреть файл

@ -5,7 +5,8 @@ enum StateKey {
Conversation = 'ic3.conversation',
UserDisplayName = 'ic3.userDisplayName',
UserId = 'ic3.userId',
FeatureConfig = 'ic3.featureConfig'
FeatureConfig = 'ic3.featureConfig',
Logger = 'ic3.logger'
}
export { StateKey };
@ -16,4 +17,5 @@ export type IC3AdapterState = {
[StateKey.UserDisplayName]: string;
[StateKey.UserId]: string;
[StateKey.FeatureConfig]: FeatureConfig;
[StateKey.Logger]: Microsoft.CRM.Omnichannel.IC3Client.Model.ILogger;
};

Просмотреть файл

@ -0,0 +1,24 @@
export enum TelemetryEvents {
CHAT_TOKEN_NOT_FOUND = "ADAPTER_CHAT_TOKEN_NOT_FOUND",
IC3_SDK_NOT_FOUND = "ADAPTER_IC3_SDK_NOT_FOUND",
IC3_SDK_INITIALIZE_STARTED = "ADAPTER_IC3_SDK_INITIALIZE_STARTED",
IC3_SDK_INITIALIZE_SUCCESS = "ADAPTER_IC3_SDK_INITIALIZE_SUCCESS",
IC3_SDK_INITIALIZE_FAILURE = "ADAPTER_IC3_SDK_INITIALIZE_FAILURE",
IC3_SDK_JOIN_CONVERSATION_STARTED = "ADAPTER_IC3_SDK_JOIN_CONVERSATION_STARTED",
IC3_SDK_JOIN_CONVERSATION_SUCCESS = "ADAPTER_IC3_SDK_JOIN_CONVERSATION_SUCCESS",
UNKNOWN_MESSAGE_TYPE = "ADAPTER_UNKNOWN_MESSAGE_TYPE",
UNKNOWN_THREAD_TYPE = "ADAPTER_UNKNOWN_THREAD_TYPE",
CONVERSATION_NOT_FOUND = "ADAPTER_CONVERSATION_NOT_FOUND",
FETCH_ATTACHMENT_FAILED = "ADAPTER_FETCH_ATTACHMENT_FAILED",
REHYDRATE_MESSAGES = "ADAPTER_REHYDRATE_MESSAGES",
REGISTER_ON_NEW_MESSAGE = "ADAPTER_REGISTER_ON_NEW_MESSAGE",
REGISTER_ON_THREAD_UPDATE = "ADAPTER_REGISTER_ON_THREAD_UPDATE",
GET_MESSAGES_SUCCESS = "ADAPTER_GET_MESSAGES_SUCCESS",
SEND_MESSAGE_SUCCESS = "ADAPTER_SEND_MESSAGE_SUCCESS",
SEND_FILE_SUCCESS = "ADAPTER_SEND_FILE_SUCCESS",
SEND_TYPING_SUCCESS = "ADAPTER_SEND_TYPING_SUCCESS",
ADAPTIVE_CARD_PROCESSING_ERROR = "ADAPTER_ADAPTIVE_CARD_PROCESSING_ERROR",
MESSAGE_RECEIVED = "ADAPTER_MESSAGE_RECEIVED",
THREAD_UPDATE_RECEIVED = "ADAPTER_THREAD_UPDATE_RECEIVED",
ADAPTER_NOT_READY = "ADAPTER_ADAPTER_NOT_READY"
}