forked from microsoft/BotBuilder-Samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request microsoft#87 from southworkscom/node-directline-we…
…bsockets [Node] DirectLine + WebSockets sample
- Loading branch information
Showing
9 changed files
with
672 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Bot Framework Credentials | ||
|
||
MICROSOFT_APP_ID= | ||
MICROSOFT_APP_PASSWORD= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// This loads the environment variables from the .env file | ||
require('dotenv-extended').load(); | ||
|
||
var builder = require('botbuilder'); | ||
var restify = require('restify'); | ||
|
||
// Setup Restify Server | ||
var server = restify.createServer(); | ||
server.listen(process.env.port || process.env.PORT || 3978, function () { | ||
console.log('%s listening to %s', server.name, server.url); | ||
}); | ||
|
||
// Create connector and listen for messages | ||
var connector = new builder.ChatConnector({ | ||
appId: process.env.MICROSOFT_APP_ID, | ||
appPassword: process.env.MICROSOFT_APP_PASSWORD | ||
}); | ||
server.post('/api/messages', connector.listen()); | ||
|
||
var instructions = 'Welcome to the Bot to showcase the DirectLine API. Send \'Show me a hero card\' or \'Send me a BotFramework image\' to see how the DirectLine client supports custom channel data. Any other message will be echoed.'; | ||
|
||
var bot = new builder.UniversalBot(connector, function (session) { | ||
|
||
var reply = new builder.Message() | ||
.address(session.message.address); | ||
|
||
var text = session.message.text.toLocaleLowerCase(); | ||
|
||
console.log('[' + session.message.address.conversation.id + '] Message received: ' + text); | ||
|
||
switch (text) { | ||
case 'show me a hero card': | ||
reply.text('Sample message with a HeroCard attachment') | ||
.addAttachment(new builder.HeroCard(session) | ||
.title('Sample Hero Card') | ||
.text('Displayed in the DirectLine client')); | ||
break; | ||
|
||
case 'send me a botframework image': | ||
reply.text('Sample message with an Image attachment') | ||
.addAttachment({ | ||
contentUrl: 'https://docs.botframework.com/en-us/images/faq-overview/botframework_overview_july.png', | ||
contentType: 'image/png', | ||
name: 'BotFrameworkOverview.png' | ||
}); | ||
|
||
break; | ||
|
||
default: | ||
reply.text('You said \'' + session.message.text + '\''); | ||
break; | ||
} | ||
|
||
session.send(reply); | ||
|
||
}); | ||
|
||
|
||
bot.on('conversationUpdate', function (activity) { | ||
// when user joins conversation, send instructions | ||
if (activity.membersAdded) { | ||
activity.membersAdded.forEach(function (identity) { | ||
if (identity.id === activity.address.bot.id) { | ||
var reply = new builder.Message() | ||
.address(activity.address) | ||
.text(instructions); | ||
bot.send(reply); | ||
} | ||
}); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "botbuilder-sample-directline-bot", | ||
"version": "1.0.0", | ||
"description": "Bot Builder Sample - DirectLine Sample - Bot", | ||
"scripts": { | ||
"start": "node app.js" | ||
}, | ||
"author": "Microsoft Corp.", | ||
"license": "MIT", | ||
"keywords": [ | ||
"botbuilder", | ||
"bots", | ||
"chatbots", | ||
"botbuilder-samples" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/Microsoft/BotBuilder-Samples/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Microsoft/BotBuilder-Samples.git" | ||
}, | ||
"dependencies": { | ||
"botbuilder": "^3.7.0", | ||
"dotenv-extended": "^1.0.4", | ||
"restify": "^4.3.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
var Swagger = require('swagger-client'); | ||
var open = require('open'); | ||
var rp = require('request-promise'); | ||
|
||
// Config settings | ||
var directLineSecret = 'DIRECTLINE_SECRET'; | ||
|
||
// directLineUserId is the field that identifies which user is sending activities to the Direct Line service. | ||
// Because this value is created and sent within your Direct Line client, your bot should not | ||
// trust the value for any security-sensitive operations. Instead, have the user log in and | ||
// store any sign-in tokens against the Conversation or Private state fields. Those fields | ||
// are secured by the conversation ID, which is protected with a signature. | ||
var directLineUserId = 'DirectLineClient'; | ||
|
||
var useW3CWebSocket = false; | ||
process.argv.forEach(function (val, index, array) { | ||
if (val === 'w3c') { | ||
useW3CWebSocket = true; | ||
} | ||
}); | ||
|
||
var directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'; | ||
var directLineClient = rp(directLineSpecUrl) | ||
.then(function (spec) { | ||
// Client | ||
return new Swagger({ | ||
spec: JSON.parse(spec.trim()), | ||
usePromise: true | ||
}); | ||
}) | ||
.then(function (client) { | ||
// Obtain a token using the Direct Line secret | ||
// First, add the Direct Line Secret to the client's auth header | ||
client.clientAuthorizations.add('AuthorizationBotConnector', new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header')); | ||
|
||
// Second, request a token for a new conversation | ||
return client.Tokens.Tokens_GenerateTokenForNewConversation().then(function (response) { | ||
// Then, replace the client's auth secret with the new token | ||
var token = response.obj.token; | ||
client.clientAuthorizations.add('AuthorizationBotConnector', new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + token, 'header')); | ||
return client; | ||
}); | ||
}) | ||
.catch(function (err) { | ||
console.error('Error initializing DirectLine client', err); | ||
}); | ||
|
||
// Once the client is ready, create a new conversation | ||
directLineClient.then(function (client) { | ||
client.Conversations.Conversations_StartConversation() | ||
.then(function (response) { | ||
var responseObj = response.obj; | ||
|
||
// Start console input loop from stdin | ||
sendMessagesFromConsole(client, responseObj.conversationId); | ||
|
||
if (useW3CWebSocket) { | ||
// Start receiving messages from WS stream - using W3C client | ||
startReceivingW3CWebSocketClient(responseObj.streamUrl, responseObj.conversationId); | ||
} else { | ||
// Start receiving messages from WS stream - using Node client | ||
startReceivingWebSocketClient(responseObj.streamUrl, responseObj.conversationId); | ||
} | ||
}); | ||
}); | ||
|
||
// Read from console (stdin) and send input to conversation using DirectLine client | ||
function sendMessagesFromConsole(client, conversationId) { | ||
var stdin = process.openStdin(); | ||
process.stdout.write('Command> '); | ||
stdin.addListener('data', function (e) { | ||
var input = e.toString().trim(); | ||
if (input) { | ||
if (input.toLowerCase() === 'exit') { | ||
return process.exit(); | ||
} | ||
|
||
// Send message | ||
client.Conversations.Conversations_PostActivity( | ||
{ | ||
conversationId: conversationId, | ||
activity: { | ||
textFormat: 'plain', | ||
text: input, | ||
type: 'message', | ||
from: { | ||
id: directLineUserId, | ||
name: directLineUserId | ||
} | ||
} | ||
}).catch(function (err) { | ||
console.error('Error sending message:', err); | ||
}); | ||
|
||
process.stdout.write('Command> '); | ||
} | ||
}); | ||
} | ||
|
||
function startReceivingWebSocketClient(streamUrl, conversationId) { | ||
console.log('Starting WebSocket Client for message streaming on conversationId: ' + conversationId); | ||
|
||
var ws = new (require('websocket').client)(); | ||
|
||
ws.on('connectFailed', function (error) { | ||
console.log('Connect Error: ' + error.toString()); | ||
}); | ||
|
||
ws.on('connect', function (connection) { | ||
console.log('WebSocket Client Connected'); | ||
connection.on('error', function (error) { | ||
console.log("Connection Error: " + error.toString()); | ||
}); | ||
connection.on('close', function () { | ||
console.log('WebSocket Client Disconnected'); | ||
}); | ||
connection.on('message', function (message) { | ||
// Occasionally, the Direct Line service sends an empty message as a liveness ping | ||
// Ignore these messages | ||
if (message.type === 'utf8' && message.utf8Data.length > 0) { | ||
var data = JSON.parse(message.utf8Data); | ||
printMessages(data.activities); | ||
// var watermark = data.watermark; | ||
} | ||
}); | ||
}); | ||
|
||
ws.connect(streamUrl); | ||
} | ||
|
||
function startReceivingW3CWebSocketClient(streamUrl, conversationId) { | ||
console.log('Starting W3C WebSocket Client for message streaming on conversationId: ' + conversationId); | ||
|
||
var ws = new (require('websocket').w3cwebsocket)(streamUrl); | ||
|
||
ws.onerror = function () { | ||
console.log('Connection Error'); | ||
}; | ||
|
||
ws.onopen = function () { | ||
console.log('W3C WebSocket Client Connected'); | ||
}; | ||
|
||
ws.onclose = function () { | ||
console.log('W3C WebSocket Client Disconnected'); | ||
}; | ||
|
||
ws.onmessage = function (e) { | ||
// Occasionally, the Direct Line service sends an empty message as a liveness ping | ||
// Ignore these messages | ||
if (typeof e.data === 'string' && e.data.length > 0) { | ||
var data = JSON.parse(e.data); | ||
printMessages(data.activities); | ||
// var watermark = data.watermark; | ||
} | ||
}; | ||
} | ||
|
||
// Helpers methods | ||
function printMessages(activities) { | ||
if (activities && activities.length) { | ||
// Ignore own messages | ||
activities = activities.filter(function (m) { return m.from.id !== directLineUserId }); | ||
|
||
if (activities.length) { | ||
process.stdout.clearLine(); | ||
process.stdout.cursorTo(0); | ||
|
||
// Print other messages | ||
activities.forEach(printMessage); | ||
|
||
process.stdout.write('Command> '); | ||
} | ||
} | ||
} | ||
|
||
function printMessage(activity) { | ||
if (activity.text) { | ||
console.log(activity.text); | ||
} | ||
|
||
if (activity.attachments) { | ||
activity.attachments.forEach(function (attachment) { | ||
switch (attachment.contentType) { | ||
case "application/vnd.microsoft.card.hero": | ||
renderHeroCard(attachment); | ||
break; | ||
|
||
case "image/png": | ||
console.log('Opening the requested image ' + attachment.contentUrl); | ||
open(attachment.contentUrl); | ||
break; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
function renderHeroCard(attachment) { | ||
var width = 70; | ||
var contentLine = function (content) { | ||
return ' '.repeat((width - content.length) / 2) + | ||
content + | ||
' '.repeat((width - content.length) / 2); | ||
} | ||
|
||
console.log('/' + '*'.repeat(width + 1)); | ||
console.log('*' + contentLine(attachment.content.title) + '*'); | ||
console.log('*' + ' '.repeat(width) + '*'); | ||
console.log('*' + contentLine(attachment.content.text) + '*'); | ||
console.log('*'.repeat(width + 1) + '/'); | ||
} |
30 changes: 30 additions & 0 deletions
30
Node/core-DirectLineWebSockets/DirectLineClient/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "botbuilder-sample-directline-client", | ||
"version": "1.0.0", | ||
"description": "Bot Builder Sample - DirectLine Sample - Client", | ||
"scripts": { | ||
"start": "node app.js" | ||
}, | ||
"author": "Microsoft Corp.", | ||
"license": "MIT", | ||
"keywords": [ | ||
"botbuilder", | ||
"bots", | ||
"chatbots", | ||
"botbuilder-samples" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/Microsoft/BotBuilder-Samples/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Microsoft/BotBuilder-Samples.git" | ||
}, | ||
"dependencies": { | ||
"open": "0.0.5", | ||
"request": "^2.79.0", | ||
"request-promise": "^4.1.1", | ||
"swagger-client": "^2.1.18", | ||
"websocket": "^1.0.24" | ||
} | ||
} |
Oops, something went wrong.