How to store session data in custom storage in bot builder
I am using node js to create a chat.
I currently store session data in Microsoft's default store, which is limited to 64KB per user session. I want to use my own storage to store session data. Here, I got help from a Microsoft developer.
I can store in document DB and Azure table.
However, I am confused. How do we implement an interface IStorageClient
for storing in our own database?
Whenever I install session.UserData.name=""
it has to be stored in its own DB.
source to share
I wrote some code to store bot data in Mongo Db. Full code and details can be found in BotBuilder-MongoDB
IstorageClient interface implementation code:
"use strict";
var Consts = require('./Consts');
var mongodb_1 = require("mongodb");
var replaceDot_Atrate = require("./replaceDot");
var mongoDbConnection = require('./connection.js');
var conf = require('../config');
var conversational_collname = conf.db.conversationalCollection;
var IStorageClient = (function () {
function IStorageClient(options) {
this.options = options;
}
IStorageClient.prototype.retrieve = function (partitionKey, rowKey, callback) {
var id = partitionKey + ',' + rowKey;
if(rowKey!=="userData"){
var query={"$and":[{"userid":id}]}
mongoDbConnection(function(err,db) {
var iterator= db.collection(conversational_collname).find(query);
iterator.toArray(function (error, result, responseHeaders) {
if (error) {
console.log("Error",error)
callback(error, null, null);
}
else if (result.length == 0) {
callback(null, null, null);
}
else {
var document_1 = result[0];
var finaldoc=replaceDot_Atrate.substituteKeyDeep(document_1, /\@/g, '.');
finaldoc["id"]=id
callback(null, finaldoc, null);
}
});
});
}
else{
var query={"$and":[{"userid":partitionKey}]}
mongoDbConnection(function(err,db) {
var iterator= db.collection(conversational_collname).find(query);
iterator.toArray(function (error, result, responseHeaders) {
if (error) {
callback(error, null, null);
}
else if (result.length == 0) {
//console.log("result length 0")
callback(null, null, null);
}
else {
var document_1 = result[0];
callback(null, document_1, null);
}
});
});
}
};
IStorageClient.prototype.initialize = function (callback) {
var _this = this;
var client=mongodb_1.MongoClient;
this.client = client;
mongoDbConnection(function(err,database) {
_this.database = database;
_this.collection = database.collection(conversational_collname);
callback(null);
});
};
IStorageClient.prototype.insertOrReplace = function (partitionKey, rowKey, entity, isCompressed, callback) {
var id=partitionKey + ',' + rowKey
var docDbEntity = { id: partitionKey + ',' + rowKey, data: entity, isCompressed: isCompressed };
if(rowKey!=="userData"){
var newEntitiy=replaceDot_Atrate.substituteKeyDeep(entity, /\./g, '@');
var conditions1 = {
'userid': id
};
var updateobj1 = {
"$set": {"data":newEntitiy,"isCompressed":false}
};
mongoDbConnection(function(error,db) {
db.collection(conversational_collname).update(conditions1,updateobj1,{upsert: true},function(err,res){
callback(error, null,"");
});
});
}
else{
var conditions = {
'userid': partitionKey
};
var update = {
"$set": {"data":entity}
}
mongoDbConnection(function(error,db) {
db.collection(conversational_collname).update(conditions,update,{upsert: true},function(err,res){
callback(error, null,"");
})
});
}
};
IStorageClient.getError = function (error) {
if (!error)
return null;
return new Error('Error Code: ' + error.code + ' Error Body: ' + error.body);
};
return IStorageClient;
}());
exports.IStorageClient = IStorageClient;
source to share
I'm not sure what my problem is; I understand what you are trying to do and it seems like you have all the parts in place.
You must first implement the IStorageClient interface . In your implementation, you write logic to store things in your DB.
You can browse DocumentDB and Azure Tables to get an idea of how this can be done.
Now the question is, if your custom storage is in Azure ... you can use AzureBotStorage with your custom storage client. You instantiate your client client, pass the link to AzureBotStorage
and set it as repository in the bot
// Azure DocumentDb State Store
var docDbClient = new azure.DocumentDbClient({
host: process.env.DOCUMENT_DB_HOST,
masterKey: process.env.DOCUMENT_DB_MASTER_KEY,
database: process.env.DOCUMENT_DB_DATABASE,
collection: process.env.DOCUMENT_DB_COLLECTION
});
var botStorage = new azure.AzureBotStorage({ gzipData: false }, docDbClient);
// Set Custom Store
bot.set('storage', botStorage);
If your custom storage is located anywhere other than Azure, then it AzureBotStorage
may not work for you. Please note that I am not sure about this, you will need to check the code for confirmation. From what I've seen it looks pretty versatile and so you can reuse it and just implement it IStorageClient
. If it is not, you will also need to implement the interface
source to share
Here's another example of this library: mongo-bot-storage
import {MongoDbBotStorage, MongoDBStorageClient} from "mongo-bot-storage";
// use it like this
bot.set("storage", new MongoDbBotStorage(new MongoDBStorageClient({
url: "mongodb://localhost/mydb",
mongoOptions: {}
})));
// or like this
MongoClient.connect("mongodb://localhost/mydb", (error, db) => {
bot.set("storage", new MongoDbBotStorage(new MongoDBStorageClient({db})));
});
and then use the default session.userData
, etc.
Do not forget
// Enable Conversation Data persistence
bot.set('persistConversationData', true);
source to share
I am posting this answer on a very, very old thread just because it seems to give better results for implementing custom storage options for the Bot Framework.
There is a much simpler solution that does not involve using npms that have not been updated for some time, which runs the risk of not being validated in corporate environments or can lead to a huge amount of log entries.
The easiest way - to create a custom data warehouse code for your bot using the most modern driver for the selected database by following the steps described in this undocumented instructions for the user data store to Microsoft Bot Framework.
It took me about an hour to implement MongoDB, including some learning curve for their latest driver.
In short, in case a link dies at some point, you can create middleware that exports two main features that the Bot Framework is looking for: getData
and saveData
. Each of them should have the following rough structure (by reference, using Redis):
var storageKey = 'conversationId';
module.exports = {
getData : (data, callback) => {
redisClient.get(data[storageKey], (err, reply) => {
if (err || !reply) {
callback(err, null);
} else {
callback(null, JSON.parse(reply));
}
})
},
saveData : (data, value, callback) => {
redisClient.set(data[storageKey], JSON.stringify(value), (err, reply) => {
if (err) {
callback(err);
} else if (reply === 'OK') {
callback(null);
}
})
}
}
Then in your app.js
necessarily app.js
require()
your middleware and install it accordingly:
const dbMiddleware = require('./path/to/middleware')
bot.set('storage', dbMiddleware)
source to share