I love the bot framework, but I want to scale to support hundreds if not thousands of Facebook pages all pointing to my single bot instance. My bot instance differentiates functionality by the incoming page id, or I guess by the MSFT App/Secret IDs.
The framework appears to require a 1:1 correspondence between logical bot hosted by MSFT and a FB page, but my single bot instance can handle thousands of such pages and apps.
It looks like I might need to create a unique ChatConnector and associated UniversalBot instance for every logical bot-page. This is horribly inefficient at the scale I'm suggesting.
One way to solve this might be to extend UniversalBot to accept a list of all MSFT App and Secret IDs that I create, but I haven't tried this yet. After reviewing the API, looks like it might be possible to register more connectors with a single UniversalBot instance.
UniversalBot:
/**
* Registers or returns a connector for a specific channel.
* #param channelId Unique ID of the channel. Use a channelId of '*' to reference the default connector.
* #param connector (Optional) connector to register. If ommited the connector for __channelId__ will be returned.
*/
connector(channelId: string, connector?: IConnector): IConnector;
But not sure what I pass for channelId unless that's an arbitrary unique local value.
I have reviewed other/similar posts here, but not found specifically anything that I believe addresses my issue. If I'm mistaken I apologize and would appreciate a reference.
I am hoping someone might have a better idea. I am using Node btw. Thanks.
Taken from here:
Creating a Single Bot Service to Support Multiple Bot Applications
var express = require('express');
var builder = require('botbuilder');
var port = process.env.PORT || 3978;
var app = express();
// a list of client ids, with their corresponding
// appids and passwords from the bot developer portal.
// get this from the configuration, a remote API, etc.
var customersBots = [
{ cid: 'cid1', appid: '', passwd: '' },
{ cid: 'cid2', appid: '', passwd: '' },
{ cid: 'cid3', appid: '', passwd: '' },
];
// expose a designated Messaging Endpoint for each of the customers
customersBots.forEach(cust => {
// create a connector and bot instances for
// this customer using its appId and password
var connector = new builder.ChatConnector({
appId: cust.appid,
appPassword: cust.passwd
});
var bot = new builder.UniversalBot(connector);
// bing bot dialogs for each customer bot instance
bindDialogsToBot(bot, cust.cid);
// bind connector for each customer on it's dedicated Messaging Endpoint.
// bot framework entry should use the customer id as part of the
// endpoint url to map to the right bot instance
app.post(`/api/${cust.cid}/messages`, connector.listen());
});
// this is where you implement all of your dialogs
// and add them on the bot instance
function bindDialogsToBot (bot, cid) {
bot.dialog('/', [
session => {
session.send(`Hello... I'm a bot for customer id: '${cid}'`);
}
]);
}
// start listening for incoming requests
app.listen(port, () => {
console.log(`listening on port ${port}`);
});
We are creating different bot and connector instances that capture the App ID and password for each customer, and binding it to the corresponding REST API that is used by the Bot Framework as the Messaging Endpoint.
When we create the bot instance, we call the bindDialogsToBot method, passing the bot instance and the customer ID. By doing that, we capture the customer ID in its closure making it accessible to the internal dialogs.
When a call is made to one of the REST APIs, the relevant bot instance is used, and the correct customer ID can be utilized by the dialog’s internal logic to process the request (for example, to retrieve a customer’s configuration/rules and act upon them).
Related
Using Plaid version "2020-09-14". I am following these instructions https://plaid.com/docs/auth/coverage/same-day/
I'm using node js to generate a link token and i successfully do:
var plaid = require('plaid');
const client = new plaid.Client({
clientID: process.env.PLAID_CLIENT_ID,
secret: process.env.PLAID_SECRET,
env: process.env.PLAID_ENV
});
console.log('client is ',client)
app.post('/api/create_link_token', async function (req, res) {
try{
const response = await client.createLinkToken({
user: {
client_user_id: '123-test-user-id',
},
client_name: 'Plaid Test App',
products: ['auth'],
country_codes: ['US'],
webhook: 'https://webhook.example.com',
language: 'en'
})
return res.send({link_token: response.link_token})
} catch (error) {
// handle error
console.log('error',error)
return res.send({err: error.message})
}
});
I get a link token everytime I run this. Then, i use said link token to try to authenticate the user's bank by using same day micro deposits (my company is setup for this through Plaid).
What keeps happening is the screen pops up that asks you to search for your bank and I do not want that. I want the screen to popup just like the one at the top of the page in the link I listed above. It asks the user for their name first, then routing, then account numbers.
How do I make the Plaid api show me the screen that prompts the user for their accounting/routing numbers without trying to authenticate them automatically with their bank username and password?
Thanks
You can't, at least right now, using publicly released Plaid APIs. (You're not the first person to ask for this, and we're working on some stuff that should help, but it isn't yet available to the developer general public.)
Is it possible to get subscription alerts for live queries on a single client instead of everyone. I am using the following code to get update alerts for the object 'obj' on class 'class-name'. But the alert message comes on every client( i.e every instance of running app).
let query_add = new Parse.Query("class-name");
let subscription = query_add.subscribe();
subscription.on('update', (obj) => {
alert('object updated');
});
How can I modify this to notify only the single client.
Server side there is a function to delete a payment method (result = Braintree::PaymentMethod.delete("the_token")) but it takes a payment method token. How do I get the payment methods token with the nonce from the client?
edit: I'm not using the drop in UI. I have a custom list of credit cards the user has (using the Javascript v3 SDK). I want to have a button to delete cards. The JS SDK dosnt give the credit cards token, just a nonce. What is the process for turning the data available to the client into something I can use to delete the card on the server?
edit2: The list of credit cards on the clent side uses the VaultManager from the JavaScript v3 SDK. It returns a fetchPaymentMethodsPayload.
This is the client side code:
_loadPaymentMethods() {
this.paymentService.getBraintreeToken().then( token => {
this.braintreeClient.create({
authorization: token
}, (clientErr, clientInstance) => {
if (clientErr) {
// Handle error in client creation
return;
}
var options = {
client: clientInstance,
};
this.vaultManager.create(options, (err, vaultInstance) => {
if (err) {
console.log(err);
return;
}
vaultInstance.fetchPaymentMethods({ defaultFirst: true }, (err, paymentMethods) => {
paymentMethods.forEach( paymentMethod => {
if(paymentMethod.type == 'CreditCard') {
this.cards.push(paymentMethod);
if(paymentMethod.default) {
this.card = paymentMethod;
}
}
});
});
});
});
});
}
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
If using VaultManager on the client-side to populate your cards, you will not have the functionality to allow a user to delete one of those cards. The reason for this goes back to what you said, that nonces are what's returned on the fetchPaymentMethodsPayload method. VaultManager can populate a nonce that's associated with an already created card, since it's only passing that nonce into a Transaction.sale() call. Since the nonce is populated when the form is rendered, you can not search for that nonce compared to a payment method in the vault, since it will not exist previously and nonces are meant for one time use. This is why nonces aren't passed into PaymentMethod.find() calls.
To accomplish your task you would need to build out custom logic that mimics what Vault Manager does; however, would need to returns the tokens. One way would be as mentioned in my comment: by finding the customer object and grabbing the customer's payment methods, and then pulling out the tokens associated with those payment methods.
I noticed that when you create a payment method with same creds, it won't get duplicated. So it's kinda like "find or create", you can then use that result to get the token and then do a gateway.payment_method.delete( result.payment_method.token )
Here's the scenario: we're using yammer connect on an internal website for a specific team that has it's own yammer group. This website displays thousands of "items" and yammer is used to manage discussions about each item using the url (e.g. http://somesite/item?id=123). All was going well until someone in a different yammer group created a conversation and used a URL that points to a page in my internal website (e.g. http://somesite/item?id=123). So now when users go to that item they see a conversation for a different group.
I'm using the defaultGroupID in the config argument, but is there a way to tell yammer to ristrict it to a specific group id - and create a new conversation for that group only for the given URL (if one doesn't exist)? Can yammer even create multiple conversations in different groups regarding the same url - but keep the conversations restricted to each group?
Here's a code sample of how I'm creating the conversations:
var varYammerTargetUrl = $('#hidYammerTargetUrl').val();
var varYammerGroupId = $('#hidYammerGroupId').val();
var objProps = { url: varYammerTargetUrl, type: 'page', title: document.title };
yam.connect.embedFeed({
container: '#yammerFeed', network: 'mycompany.com', feedType: 'open-graph', feedId: '',
config: {
use_sso: false
, header: false
, footer: false
, showOpenGraphPreview: false
, defaultToCanonical: false
, hideNetworkName: false
, defaultGroupId: varYammerGroupId
, promptText: 'Start a conversation about this concession'
}
, objectProperties: objProps
});
When URLs are posted into Yammer there is an open graph object created. These objects don't live in groups by design and thus can be created anywhere within Yammer and are not restricted to certain groups.
Here is some additional documentation.
I have an app where one user can invite other users to join an event by push notification. Let's say when creating an event, the user add other users to this event, then save the event to Parse.
So basically I have an array of user_id and I will call a function from cloud code to push notification to those Id, after saving the event.
1)Will the following Cloud code work?
Parse.Cloud.afterSave( "Event", function(request) {
//Get value from Ticket Object
var ids = request.object.get("inviteeIds");
//Set push query
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.containedIn("objectId",ids);
//Send Push message
Parse.Push.send({
where: pushQuery,
data: {
alert: "New Event Added",
sound: "default"
}
},{
success: function(){
response.success('true');
},
error: function (error) {
response.error(error);
}
});
});
I am not sure if the containedIn function exist or not:
pushQuery.containedIn("objectId",ids);
When I search I only find documentation about equalTo function, e.g:
query.equalTo('injuryReports', true);
2) I also read about Channel, but I still not understand how to apply it in my situation. From the documentation:
Devices start by subscribing to one or more channels, and
notifications can later be sent to these subscribers.
In my case how can I create a Channel and then add ids of friends who I want to invite to this Channel?
If possible, I would like to use Cloud Code rather than pushing from mobile device.
1)Will the following Cloud code work?
Why don't you try it and see for yourself, then come back with the errors, if any? Anyway, there's no response in afterSave. It will return a success regardless of what happens in it.
Otherwise it may work. Try running it.
I am not sure if the containedIn function exist or not:
Parse.Query.containedIn
2) I also read about Channel, but I still not understand how to apply it in my situation
Basically you subscribe to a particular channel in the client. Like this (Android)
ParsePush.subscribeInBackground("channelName");
Then in the Cloud
Parse.Push.send({
channels: channelList,
data: {
// etc
}
});
Obviously you'll need to know the channels you want to target.
You can subscribe multiple users to the same channel (for example you can have a dedicated channel for a particular event) or you can have one channel per user (for example you can name it something like channel_<userId> and only subscribe that user to it). Up to you what you need or what you want.
One last thing...
So basically I have an array of user_id
Keep in mind that objects stored in the database have a limited size. If your object gets too big and has too much data, you won't be able to add any more to it.