Now, after we have successfully generated our Chatbot TypeScript code with Yeoman, we must take a closer look to understand what’s happening.
index.ts
src/index.ts is responsible for setting up the bot and provide a web-server that we can send chat requests to. Our bot logic - and by that I mean instructions what the bot is actually supposed to do - is handled in src/bot.ts instead.
src/index.ts imports the required bot services and bot configuration, loads environment files and sets environment constants.
import { config } from 'dotenv';import * as path from 'path';import * as restify from 'restify';
import { BotFrameworkAdapter } from 'botbuilder';import { BotConfiguration, IEndpointService } from 'botframework-config';import { MyBot } from './bot';
const ENV_FILE = path.join(__dirname, '..', '.env');config({ path: ENV_FILE });
const DEV_ENVIRONMENT = 'development';const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);It creates a web server (using the package restify) by default on port 3978
const server = restify.createServer();server.listen(process.env.port || process.env.PORT || 3978, () => { console.log(`\n${server.name} listening to ${server.url}`); console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`); console.log(`\nTo talk to your bot, open bothe-bot.bot file in the Emulator.`);});tries to load bot configuration
const BOT_FILE = path.join(__dirname, '..', (process.env.botFilePath || ''));
let botConfig;try { botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);} catch (err) { console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`); console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`); console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.`); console.error(`\n - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.\n\n`); process.exit();}
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION) as IEndpointService;The file also creates an adapter from the bot configuration:
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION) as IEndpointService;
const adapter = new BotFrameworkAdapter({ appId: endpointConfig.appId || process.env.microsoftAppID, appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,});Then it creates a catch-all error handler:
adapter.onTurnError = async (context, error) => { console.error(`\n [onTurnError]: ${ error }`); await context.sendActivity(`Oops. Something went wrong!`);};Finally it calls our bot logic whenever there is a request to /api/messages
const myBot = new MyBot();
server.post('/api/messages', (req, res) => { adapter.processActivity(req, res, async (context) => { await myBot.onTurn(context); });});src/bot.ts
import { ActivityTypes, TurnContext } from 'botbuilder';
export class MyBot { /** * Use onTurn to handle an incoming activity, received from a user, process it, and reply as needed * * @param {TurnContext} context on turn context object. */ public onTurn = async (turnContext: TurnContext) => { if (turnContext.activity.type === ActivityTypes.Message) { await turnContext.sendActivity(`You said '${ turnContext.activity.text }'`); } else { await turnContext.sendActivity(`[${ turnContext.activity.type } event detected]`); } }}As you can see we use the TurnContext to get information and also to send an activity back to the user. Very powerful, that’s why is worth having a closer look at TurnContext in the next post.