0.0.2 • Published 6 years ago

botbuilder-storage-rethinkdb v0.0.2

Weekly downloads
3
License
MIT
Repository
github
Last release
6 years ago

Bot Builder RethinkDB Storage

Attention: Bot Framework State Service will cease operating on March 31st 2018, so you should switch your bot to another storage adapter - like this one - soon!

NPM

Codeship Status for codeforequity-at/botbuilder-storage-rethinkdb npm version license

A module to use RethinkDB as storage adapter for Microsoft Bot Builder SDK for Node.js. Configure your bot to automatically save conversation state data in Rethinkdb.

Installation

npm install --save botbuilder-storage-rethinkdb

Usage

Instantiate a new storage, configure connection details to your RethinkDB and plug it into Bot Builder.

const RethinkDbStorage = require('botbuilder-storage-rethinkdb').RethinkDbStorage;

// BotBuilder setup code
const connector = new builder.ChatConnector({
   ...
});
const bot = new builder.UniversalBot(connector, {
   ...
});

const storage = new RethinkDbStorage({
  // add your settings here
  host: '127.0.0.1',
  tablePrefix: 'botstorage_' + process.env.NODE_ENV
});
bot.set('storage', storage);

Configuration

The constructor take an "options" argument. All options for connecting to RethinkDb are supported, and some additional ones.

host

Default: 'localhost' Well, the hostname of your RethinkDB instance ...

port

Default: 28015 The port your RethinkDB instance is listening.

db

Default: 'botstorage' The name of the database to store the conversation state data. If this database doesn't exist, it will be created.

tablePrefix

Default: 'botstorage__' The table prefix for the conversation state tables, which are created automatically. In case you are sharing one RethinkDB instance among several environments or bots, you should change this table prefix.

There are 3 tables created automatically, one for each storage container:

  • botstorage_userData
  • botstorage_conversationData
  • botstorageprivateConversationData (botstorage is the table prefix)

All 3 of these tables include:

  • a secondary index for fast lookup
  • a "created_at" column
  • a "updated_at" column

Data Migration

Here are some hints how I migrated existing conversation state data from the Bot Framework State Service to my local RethinkDB.

First, I enabled a special "migration" mode by setting an environment variable. In migration mode, the old storage adapter is used, but the RethinkDB storage adapter is initialized and connected:

const storage = new RethinkDbStorage({
  ...
});

if (process.env.MIGRATE_STORAGE) {
  require('./migrate')(bot, storage);
} else {
  bot.set('storage', storage);
}
...

The migrate.js file loads all existing user addresses from my Redis session store, starts an empty dialog of each of them, making the conversation state data available in the session, and finally stores the conversation state data in RethinkDB.

const async = require('async');
const Redis = require('ioredis');

module.exports = (bot, storage) => {

  var migratedCount = 0;
  var errorCount = 0;

  const redis = new Redis({
    host: ...,
    port: ...,
    showFriendlyErrorStack: true
  });

  bot.dialog('/migrate', (session) => {
    console.log('MIGRATING USER ' + session.message.address.user.name);
  
    const context = {
      persistUserData: true,
      userId: session.message.address.user.id,
      persistConversationData: true,
      conversationId: session.message.address.conversation.id
    };
    const data = {
      userData: session.userData,
      conversationData: session.conversationData,
      privateConversationData: session.privateConversationData
    }
    
    storage.saveData(context, data, (err) => {
      if (err) {
        console.log('SAVEDATA FAILED: ' + err)
        errorCount++;
      } else {
        migratedCount++;
      }
      console.log('CURRENTLY MIGRATED: ' + migratedCount + ', ERRORS: ' + errorCount);
    })
  })

  async.waterfall([

    (getKeysDone) => {
      redis.keys('bot:user:*', getKeysDone);
    },
    
    (keys, getValuesDone) => {
      redis.mget(keys, getValuesDone);
    },

    (values, done) => {
      console.log('MIGRATING ' + values.length + ' bot users');
      
      values.forEach((address) => {
        bot.beginDialog(JSON.parse(address), '/migrate');
      })
      done()
    }
  ], (err) => {
    if (err) {
      console.log('MIGRATE FAILED: ' + err);
    }
  });
};

License

MIT