TEAMS bot. "TypeError: source.on is not a function" in 'createConversation' method
TEAMS bot. "TypeError: source.on is not a function" in 'createConversation' method
我在本地有一个 TEAMS node.js 机器人 运行(使用 ngrok)。我收到来自 TEAMS 客户端的消息并且 echo 有效
context.sendActivity(`You said '${context.activity.text}'`);
我需要主动发送消息,但创建对话对象时出错。
我的代码:
...
await BotConnector.MicrosoftAppCredentials.trustServiceUrl(sServiceUrl);
var credentials = new BotConnector.MicrosoftAppCredentials({
appId: "XXXXXXXXXXXX",
appPassword: "YYYYYYYYYYYYY"
});
var connectorClient = new BotConnector.ConnectorClient(credentials, { baseUri: sServiceUrl });
const parameters = {
members: [{ id: sUserId }],
isGroup: false,
channelData:
{
tenant: {
id: sTenantId
}
}
};
// Here I get the error: "TypeError: source.on is not a function"
var conversationResource = await connectorClient.conversations.createConversation(parameters);
await connectorClient.conversations.sendToConversation(conversationResource.id, {
type: "message",
from: { id: credentials.appId },
recipient: { id: sUserId },
text: 'This a message from Bot Connector Client (NodeJS)'
});
字符串值正确,我有一个有效的 connectorClient。
提前致谢,
迭戈
我认为你已经很接近了,但只需要做一些修改。很难说,因为我看不到你所有的代码。
在这里,我将 Teams 中间件添加到 index.js
中的适配器,并在 mainDialog.js
中进行调用以从瀑布步骤中触发主动消息。只要您可以将 context
传入.
,代码的位置应该无关紧要
此外,关于您的消息构造,仅发送文本就足够了。收件人已在参数中指定,其余 activity 属性通过连接器分配。没有必要重建activity(除非你真的需要)。
最后,请务必相信serviceUrl
。我通过 mainBot.js
.
中的 onTurn
方法执行此操作
希望得到帮助!
index.js
const teams = require('botbuilder-teams');
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
})
.use(new teams.TeamsMiddleware())
mainDialog.js
const { ConnectorClient, MicrosoftAppCredentials } = require('botframework-connector');
async teamsProactiveMessage ( stepContext ) {
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: stepContext.context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(stepContext.context.activity.conversation.id);
const parameters = {
members: [
{
id: roster[0].id
}
],
channelData: {
tenant: {
id: roster[0].tenantId
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
return stepContext.next();
}
mainBot.js
this.onTurn(async (context, next) => {
if (context.activity.channelId === 'msteams') {
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
}
await next();
});
我用 Yeoman 创建了我的机器人,所以我有一个 运行 可以响应传入消息的示例。
https://docs.microsoft.com/es-es/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0
有了它,我可以回复收到的消息并且它有效
我的完整代码:
index.js: // 自动创建,未修改
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const dotenv = require('dotenv');
const path = require('path');
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter } = require('botbuilder');
// This bot's main dialog.
const { MyBot } = require('./bot');
// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
dotenv.config({ path: ENV_FILE });
// Create HTTP server
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 test your bot, see: https://aka.ms/debug-with-emulator`);
});
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${ error }`);
// Send a message to the user
await context.sendActivity(`Oops. Something went wrong!`);
};
// Create the main dialog.
const myBot = new MyBot();
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.run(context);
});
});
我的机器人文件。 bot.js // 自动创建,修改为添加主动消息
const { ConnectorClient, MicrosoftAppCredentials, BotConnector } = require('botframework-connector');
const { ActivityHandler } = require('botbuilder');
class MyBot extends ActivityHandler {
constructor() {
super();
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
this.onMessage(async (context, next) => {
//await context.sendActivity(`You said '${context.activity.text}'`); // It works
var activity = context.activity;
await MicrosoftAppCredentials.trustServiceUrl(activity.serviceUrl);
var connectorClient = new ConnectorClient(credentials, { baseUri: activity.serviceUrl });
const parameters = {
members: [{ id: activity.from.id }],
isGroup: false,
channelData:
{
tenant: {
id: activity.conversation.tenantId
}
}
};
var conversationResource = await connectorClient.conversations.createConversation(parameters);
});
}
module.exports.MyBot = MyBot;
在 'createConversation' 是我得到错误的地方:
[onTurnError]: TypeError: source.on is not a function
这段代码会放在一个方法里,需要的时候调用,我放在'onMessage'里只是为了简化
我想我的代码和你的一样...但恐怕我遗漏了什么或做错了什么...
感谢您的帮助,
迭戈
我有错误的堆栈跟踪,它似乎与 'delayed stream' 节点模块有关。我添加为回复,因为评论太长了:
(node:28248) UnhandledPromiseRejectionWarning: TypeError: source.on is not a function
at Function.DelayedStream.create ([Bot Project Path]\node_modules\delayed-stream\lib\delayed_stream.js:33:10)
at FormData.CombinedStream.append ([Bot Project Path]\node_modules\combined-stream\lib\combined_stream.js:45:37)
at FormData.append ([Bot Project Path]\node_modules\form-data\lib\form_data.js:74:3)
at MicrosoftAppCredentials.refreshToken ([Bot Project Path]\node_modules\botframework-connector\lib\auth\microsoftAppCredentials.js:127:20)
at MicrosoftAppCredentials.getToken ([Bot Project Path]\node_modules\botframework-connector\lib\auth\microsoftAppCredentials.js:91:32)
at MicrosoftAppCredentials.signRequest ([Bot Project Path]\node_modules\botframework-connector\lib\auth\microsoftAppCredentials.js:71:38)
at SigningPolicy.signRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:2980:44)
at SigningPolicy.sendRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:2984:21)
at ConnectorClient.ServiceClient.sendRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:3230:29)
at ConnectorClient.ServiceClient.sendOperationRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:3352:27)
我发现了我的问题。我必须以正确的顺序设置 credentials/conector/trust:
credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
connectorClient = new ConnectorClient(credentials, { baseUri: activity.serviceUrl });
MicrosoftAppCredentials.trustServiceUrl(activity.serviceUrl);
我在本地有一个 TEAMS node.js 机器人 运行(使用 ngrok)。我收到来自 TEAMS 客户端的消息并且 echo 有效
context.sendActivity(`You said '${context.activity.text}'`);
我需要主动发送消息,但创建对话对象时出错。
我的代码:
...
await BotConnector.MicrosoftAppCredentials.trustServiceUrl(sServiceUrl);
var credentials = new BotConnector.MicrosoftAppCredentials({
appId: "XXXXXXXXXXXX",
appPassword: "YYYYYYYYYYYYY"
});
var connectorClient = new BotConnector.ConnectorClient(credentials, { baseUri: sServiceUrl });
const parameters = {
members: [{ id: sUserId }],
isGroup: false,
channelData:
{
tenant: {
id: sTenantId
}
}
};
// Here I get the error: "TypeError: source.on is not a function"
var conversationResource = await connectorClient.conversations.createConversation(parameters);
await connectorClient.conversations.sendToConversation(conversationResource.id, {
type: "message",
from: { id: credentials.appId },
recipient: { id: sUserId },
text: 'This a message from Bot Connector Client (NodeJS)'
});
字符串值正确,我有一个有效的 connectorClient。
提前致谢,
迭戈
我认为你已经很接近了,但只需要做一些修改。很难说,因为我看不到你所有的代码。
在这里,我将 Teams 中间件添加到 index.js
中的适配器,并在 mainDialog.js
中进行调用以从瀑布步骤中触发主动消息。只要您可以将 context
传入.
此外,关于您的消息构造,仅发送文本就足够了。收件人已在参数中指定,其余 activity 属性通过连接器分配。没有必要重建activity(除非你真的需要)。
最后,请务必相信serviceUrl
。我通过 mainBot.js
.
onTurn
方法执行此操作
希望得到帮助!
index.js
const teams = require('botbuilder-teams');
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
})
.use(new teams.TeamsMiddleware())
mainDialog.js
const { ConnectorClient, MicrosoftAppCredentials } = require('botframework-connector');
async teamsProactiveMessage ( stepContext ) {
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: stepContext.context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(stepContext.context.activity.conversation.id);
const parameters = {
members: [
{
id: roster[0].id
}
],
channelData: {
tenant: {
id: roster[0].tenantId
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
return stepContext.next();
}
mainBot.js
this.onTurn(async (context, next) => {
if (context.activity.channelId === 'msteams') {
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
}
await next();
});
我用 Yeoman 创建了我的机器人,所以我有一个 运行 可以响应传入消息的示例。 https://docs.microsoft.com/es-es/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0
有了它,我可以回复收到的消息并且它有效
我的完整代码:
index.js: // 自动创建,未修改
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const dotenv = require('dotenv');
const path = require('path');
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter } = require('botbuilder');
// This bot's main dialog.
const { MyBot } = require('./bot');
// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
dotenv.config({ path: ENV_FILE });
// Create HTTP server
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 test your bot, see: https://aka.ms/debug-with-emulator`);
});
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${ error }`);
// Send a message to the user
await context.sendActivity(`Oops. Something went wrong!`);
};
// Create the main dialog.
const myBot = new MyBot();
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.run(context);
});
});
我的机器人文件。 bot.js // 自动创建,修改为添加主动消息
const { ConnectorClient, MicrosoftAppCredentials, BotConnector } = require('botframework-connector');
const { ActivityHandler } = require('botbuilder');
class MyBot extends ActivityHandler {
constructor() {
super();
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
this.onMessage(async (context, next) => {
//await context.sendActivity(`You said '${context.activity.text}'`); // It works
var activity = context.activity;
await MicrosoftAppCredentials.trustServiceUrl(activity.serviceUrl);
var connectorClient = new ConnectorClient(credentials, { baseUri: activity.serviceUrl });
const parameters = {
members: [{ id: activity.from.id }],
isGroup: false,
channelData:
{
tenant: {
id: activity.conversation.tenantId
}
}
};
var conversationResource = await connectorClient.conversations.createConversation(parameters);
});
}
module.exports.MyBot = MyBot;
在 'createConversation' 是我得到错误的地方:
[onTurnError]: TypeError: source.on is not a function
这段代码会放在一个方法里,需要的时候调用,我放在'onMessage'里只是为了简化
我想我的代码和你的一样...但恐怕我遗漏了什么或做错了什么...
感谢您的帮助,
迭戈
我有错误的堆栈跟踪,它似乎与 'delayed stream' 节点模块有关。我添加为回复,因为评论太长了:
(node:28248) UnhandledPromiseRejectionWarning: TypeError: source.on is not a function
at Function.DelayedStream.create ([Bot Project Path]\node_modules\delayed-stream\lib\delayed_stream.js:33:10)
at FormData.CombinedStream.append ([Bot Project Path]\node_modules\combined-stream\lib\combined_stream.js:45:37)
at FormData.append ([Bot Project Path]\node_modules\form-data\lib\form_data.js:74:3)
at MicrosoftAppCredentials.refreshToken ([Bot Project Path]\node_modules\botframework-connector\lib\auth\microsoftAppCredentials.js:127:20)
at MicrosoftAppCredentials.getToken ([Bot Project Path]\node_modules\botframework-connector\lib\auth\microsoftAppCredentials.js:91:32)
at MicrosoftAppCredentials.signRequest ([Bot Project Path]\node_modules\botframework-connector\lib\auth\microsoftAppCredentials.js:71:38)
at SigningPolicy.signRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:2980:44)
at SigningPolicy.sendRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:2984:21)
at ConnectorClient.ServiceClient.sendRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:3230:29)
at ConnectorClient.ServiceClient.sendOperationRequest ([Bot Project Path]\node_modules\@azure\ms-rest-js\dist\msRest.node.js:3352:27)
我发现了我的问题。我必须以正确的顺序设置 credentials/conector/trust:
credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
connectorClient = new ConnectorClient(credentials, { baseUri: activity.serviceUrl });
MicrosoftAppCredentials.trustServiceUrl(activity.serviceUrl);