/**
 * Copyright(c) Microsoft Corporation.All rights reserved.
 * Licensed under the MIT License.
 */ import { BotFrameworkAdapterSettings , BotTelemetryClient , ChannelServiceRoutes , ConversationState , NullTelemetryClient , StatePropertyAccessor , TurnContext , UserState , TelemetryLoggerMiddleware , SkillHttpClient , SkillConversationIdFactory , BotFrameworkSkill } from 'botbuilder' ; import { ApplicationInsightsTelemetryClient , ApplicationInsightsWebserverMiddleware } from 'botbuilder-applicationinsights' ; import { CosmosDbPartitionedStorage } from 'botbuilder-azure' ; import { Dialog , SkillDialog , SkillDialogOptions } from 'botbuilder-dialogs' ; import { CognitiveModelConfiguration , CosmosDbPartitionedStorageOptions , LocaleTemplateManager , SwitchSkillDialog , IEnhancedBotFrameworkSkill , SkillsConfiguration } from 'bot-solutions' ; import { SimpleCredentialProvider , AuthenticationConfiguration , allowedCallersClaimsValidator } from 'botframework-connector' ; import { join } from 'path' ; import * as restify from 'restify' ; import { DefaultAdapter } from './adapters/defaultAdapter' ; import * as appsettings from './appsettings.json' ; import { DefaultActivityHandler } from './bots/defaultActivityHandler' ; import * as cognitiveModelsRaw from './cognitivemodels.json' ; import { MainDialog } from './dialogs/mainDialog' ; import { OnboardingDialog } from './dialogs/onboardingDialog' ; import { BotServices } from './services/botServices' ; import { IBotSettings } from './services/botSettings' ; import { Activity } from 'botframework-schema' ; import { TelemetryInitializerMiddleware } from 'botbuilder-applicationinsights' ; import { IUserProfileState } from './models/userProfileState' ; import { ITokenExchangeConfig , TokenExchangeSkillHandler } from './tokenExchange' ; function getTelemetryClient ( settings ) { if ( settings !== undefined && settings . appInsights !== undefined && settings . appInsights . instrumentationKey !== undefined ) { const instrumentationKey = settings . appInsights . instrumentationKey ; return new ApplicationInsightsTelemetryClient ( instrumentationKey ) ; } return new NullTelemetryClient ( ) ; } const cognitiveModels = new Map ( ) ; const cognitiveModelDictionary = cognitiveModelsRaw . cognitiveModels ; const cognitiveModelMap = new Map ( Object . entries ( cognitiveModelDictionary ) ) ; cognitiveModelMap . forEach ( ( value , key ) : void => { cognitiveModels . set ( key , value as CognitiveModelConfiguration ) ; } ) ; const settings = { appInsights : appsettings . appInsights , blobStorage : appsettings . blobStorage , cognitiveModels : cognitiveModels , cosmosDb : appsettings . cosmosDb , defaultLocale : cognitiveModelsRaw . defaultLocale , microsoftAppId : appsettings . microsoftAppId , microsoftAppPassword : appsettings . microsoftAppPassword , tokenExchangeConfig : appsettings . tokenExchangeConfig } ; const credentialProvider = new SimpleCredentialProvider ( appsettings . microsoftAppId , appsettings . microsoftAppPassword ) ; const skillsConfig = new SkillsConfiguration ( appsettings . botFrameworkSkills as IEnhancedBotFrameworkSkill [ ] , appsettings . skillHostEndpoint ) ; let authenticationConfiguration = new AuthenticationConfiguration ( ) ; if ( skillsConfig . skills . size > 0 ) { const allowedCallers = [ ... skillsConfig . skills . values ( ) ] . map ( skill => skill . appId ) ; authenticationConfiguration = new AuthenticationConfiguration ( undefined , allowedCallersClaimsValidator ( allowedCallers ) ) ; } const telemetryClient = getTelemetryClient ( settings ) ; const telemetryLoggerMiddleware = new TelemetryLoggerMiddleware ( telemetryClient ) ; const telemetryInitializerMiddleware = new TelemetryInitializerMiddleware ( telemetryLoggerMiddleware ) ; const botServices = new BotServices ( settings as IBotSettings , telemetryClient ) ; if ( settings . cosmosDb === undefined ) { throw new Error ( ) ; } const cosmosDbStorageOptions = { authKey : settings . cosmosDb . authKey , containerId : settings . cosmosDb . containerId , databaseId : settings . cosmosDb . databaseId , cosmosDbEndpoint : settings . cosmosDb . cosmosDbEndpoint } ; const storage = new CosmosDbPartitionedStorage ( cosmosDbStorageOptions ) ; const userState = new UserState ( storage ) ; const conversationState = new ConversationState ( storage ) ; const localizedTemplates = new Map < string , string > ( ) ; const templateFile = 'AllResponses' ; const supportedLocales = [ 'en-us' , 'de-de' , 'es-es' , 'fr-fr' , 'it-it' , 'zh-cn' ] ; supportedLocales . forEach ( ( locale ) => { const localTemplateFile = locale === 'en-us' ? join ( __dirname , 'responses' , `${ templateFile }.lg` ) : join ( __dirname , 'responses' , `${ templateFile }.${ locale }.lg` ) ; localizedTemplates . set ( locale , localTemplateFile ) ; } ) ; const localeTemplateManager = new LocaleTemplateManager ( localizedTemplates , settings . defaultLocale || 'en-us' ) ; const skillConversationIdFactory = new SkillConversationIdFactory ( storage ) ; const skillClient = new SkillHttpClient ( credentialProvider , skillConversationIdFactory ) ; const adapterSettings = { appId : settings . microsoftAppId , appPassword : settings . microsoftAppPassword } ; const adapter = new DefaultAdapter ( settings , localeTemplateManager , conversationState , adapterSettings , telemetryInitializerMiddleware , telemetryClient , skillsConfig , skillClient ) ; let bot ; try { const botId = appsettings . microsoftAppId ; if ( botId === undefined || botId . trim ( ) . length === 0 ) { throw new Error ( 'microsoftAppId is not in the configuration' ) ; } const skillDialogs = [ ] ; skillsConfig . skills . forEach ( ( skill , skillId ) => { const skillDialogOptions = { botId : botId , conversationIdFactory : skillConversationIdFactory , skillClient : skillClient , skillHostEndpoint : skillsConfig . skillHostEndpoint , skill : skill , conversationState : conversationState } ; skillDialogs . push ( new SkillDialog ( skillDialogOptions , skillId ) ) ; } ) ; const previousResponseAccesor = userState . createProperty < Partial < Activity > [ ] > ( 'Activity' ) ; const activeSkillProperty = conversationState . createProperty < BotFrameworkSkill > ( MainDialog . activeSkillPropertyName ) ; const userProfileStateAccesor = userState . createProperty < IUserProfileState > ( 'IUserProfileState' ) ; const onboardingDialog = new OnboardingDialog ( userProfileStateAccesor , botServices , localeTemplateManager ) ; const switchSkillDialog = new SwitchSkillDialog ( conversationState ) ; const mainDialog = new MainDialog ( botServices , localeTemplateManager , userProfileStateAccesor , previousResponseAccesor , onboardingDialog , switchSkillDialog , skillDialogs , skillsConfig , activeSkillProperty ) ; bot = new DefaultActivityHandler ( conversationState , userState , localeTemplateManager , mainDialog , telemetryClient ) ; } catch ( err ) { throw err ; } const server = restify . createServer ( { maxParamLength : 1000 } ) ; server . use ( restify . plugins . bodyParser ( ) ) ; server . use ( restify . plugins . queryParser ( ) ) ; server . use ( restify . plugins . authorizationParser ( ) ) ; server . use ( ApplicationInsightsWebserverMiddleware ) ; server . listen ( process . env . port || process . env . PORT || '3979' , ( ) : void => { console . log ( ` ${ server . name } listening to ${ server . url } ` ) ; console . log ( `Get the Emulator: https://aka.ms/botframework-emulator` ) ; console . log ( `To talk to your bot, open your '.bot' file in the Emulator` ) ; } ) ; server . post ( '/api/messages' , async ( req , res ) : Promise < void > => { await adapter . processActivity ( req , res , async ( turnContext ) : Promise < void > => { await bot . run ( turnContext ) ; } ) ; } ) ; const handler = new TokenExchangeSkillHandler ( adapter , bot , settings as IBotSettings , skillConversationIdFactory , skillsConfig , skillClient , credentialProvider , authenticationConfiguration , settings . tokenExchangeConfig as ITokenExchangeConfig ) ; const skillEndpoint = new ChannelServiceRoutes ( handler ) ; skillEndpoint . register ( server , '/api/skills' ) ;