Skip to main content
Version: 1.0.5

Session

Introduction

Bottender provides a mechanism for you to recognize each conversation and store temporary data on ecah conversation. just like session of the web server.

Session State

State is widely used in flow control of daily mahcines, e.g. traffic light. The change of state is in response to external inputs and/or conditions is satisfied. For example, a green traffic light (a state) changes to yellow traffic light after 60 sec (a satisfied time condition).

A Counting Bot Example

Considering a couting bot which responds the number of message events it received, for example:

You > Hi
Bot > Count: 1
You > Hi
Bot > Count: 2

In this section, we will explain how to use state correctly to build a counter. It begins with a count state variable, which will be updated when the bot receives an event.

Let's start with a static action like this:

async function EventCount(context) {
await context.sendText('Count: 1');
}

Adding State to the Conversation

  1. Set initial state in bottender.config.js file:
module.exports = {
initialState: {
count: 0,
},
};

After adding this, Bottender will set initial state to this object for the new conversation session.

  1. Access state value using context.state:
async function EventCount(context) {
const count = context.state.count + 1;
await context.sendText(`Count: ${count}`);
}

Even though we use state variable to render the message content, it always gets Count: 1 as result. That's why step 3 is necessary.

  1. Set state value using context.setState():
async function EventCount(context) {
const count = context.state.count + 1;

context.setState({
count,
});

await context.sendText(`Count: ${count}`);
}

Then it works as expected.

Note: don't modify state directly using this.state.stateKey = stateValue;, it may cause unexpected behavior in the future.

State Updates are Merged

When you call setState(), Bottender shallow merges the object you provide into the current state.

context.state; // { count: 1 }

context.setState({
myObject: {},
});

context.state; // { count: 1, myObject: {} }

But if you want to do a deeper merge, you need to do it explicitly:

context.setState({
myObject: {
...context.myObject,
key: value,
},
});

Debug State in Console Mode

In "Console Mode", you can leverage the convenient built-in command - /state to help you debugging you state transition:

You > /state

This commmand formats the state with JSON.stringify() and send the result as a bot message to you:

Bot > { "count": 1 }

Session Id

Bottender provides a consistent interface session.id as a unique identifier for all platform in all kinds of request.

Usage

The following code is a demo to reply session.id to user:

module.exports = async function App(context) {
await context.sendText(`session.platform: ${context.session.platform}`);
await context.sendText(`session.id: ${context.session.id}`);
};

session.id includes the platform name and channel id to avoid any confiction when a bot connect to multiple platform.

The defination of session.id in Bottender is:

sessionId = `${platform}:${sessionKey}`

platform is the platform name, the sessionKey come from different sources in different situations.

Session Key of LINE

there are 3 type of source in LINE playform defined in the LINE official document, Source user, Source group and Source room.

if a request come from source user, then the sessionKey will be source.userId, for example:

line:U4af4980629...

if a request come from source group, then the sessionKey will be source.groupId, for example:

line:Ca56f94637c...

if a request come from source room, then the sessionKey will be source.roomId, for example:

line:Ra8dbf4673c...

you can read the implement detail here

Session Key in Telegram

The sessionKey represent for the chat.id in Telegram platform. The principal is the same as the LINE platform, but the implement is more complicated.

this is an example of session.id:

telegram:16423...

you can read the implement detail here

Session Key in Messenger

The sessionKey represent for the recipient.id or sender.id in Slack platform.

you can read the implement detail here

Session Key in Slack

The sessionKey represent for the channel.id in Slack platform.

you can read the implement detail here

Session Key in Viper

The sessionKey represent for the user.id or sender.id in Slack platform.

you can read the implement detail here

Session Storage

Since HTTP driven applications are stateless, the mission of sessions is to store context of users during conversations. Bottender offers a variety of session drivers right out of the box, e.g. memory, file, redis, and mongo. These drivers could be accessed through an expressive, unified API.

From connectors, the information of session could be accessed, e.g. session id, plus, whether the session is between a bot and single user, or between a bot and a group of users. One bot could support multiple messaging platforms at once, and one connector refers to one messaging platform.

You can specify an explicit session expiration time to reset the state. It makes a bot more human-like by forgetting (initializing) the state after conversation has been inactive for a while

Configuring Session Driver

Session driver can be set by session.driver value in the bottender.config.js file:

// bottender.config.js

module.exports = {
session: {
driver: 'memory',
stores: {
memory: {
maxSize: 500,
},
file: {
dirname: '.session',
},
redis: {
port: 6379,
host: '127.0.0.1',
password: 'auth',
db: 0,
},
mongo: {
url: 'mongodb://localhost:27017',
collectionName: 'sessions',
},
},
},
};

The four valid drivers are as follows:

  • memory - sessions are stored in memory with LRU cache and not persistent.
  • file - sessions are stored in files placed in .session directory by default.
  • redis - sessions are stored in a redis database.
  • mongo - sessions are stored in a mongo database.

Using Different Session Driver Based on NODE_ENV

It is recommended to use memory as the session driver in the development for shorter iteration. By restarting the process, the session store could be reset completely.

You can determine which session driver to use in the development or production by env variable:

// bottender.config.js

module.exports = {
session: {
driver: process.env.NODE_ENV === 'production' ? 'mongo' : 'memory',
// ...
},
};

Setting the Session Expiration Time

By default, the sessions stored by Bottender never expire. To set explicit session expiration time, add the session.expiresIn setting in your bottender.config.js file:

// bottender.config.js

module.exports = {
session: {
driver: 'memory',
expiresIn: 15, // 15 minutes
// ...
},
};

With settings above, the user will get a new session and new session state after inactive for 15 minutes.