From 3f04cdb0189dd1c679fb8f1f384622bbb69ed0f4 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Mon, 25 Feb 2019 20:37:37 -0800 Subject: [PATCH] Redis Driver for the User Variable Session Manager --- .travis.yml | 1 - README.md | 194 ++++++++++++------------- contrib/redis/index.js | 241 ++++++++++++++++++++++++++++++++ contrib/redis/package-lock.json | 33 +++++ contrib/redis/package.json | 25 ++++ eg/README.md | 2 + eg/redis/README.md | 102 ++++++++++++++ eg/redis/package-lock.json | 33 +++++ eg/redis/package.json | 14 ++ eg/redis/redis-bot.js | 120 ++++++++++++++++ src/rivescript.js | 4 +- 11 files changed, 670 insertions(+), 99 deletions(-) create mode 100644 contrib/redis/index.js create mode 100644 contrib/redis/package-lock.json create mode 100644 contrib/redis/package.json create mode 100644 eg/redis/README.md create mode 100644 eg/redis/package-lock.json create mode 100644 eg/redis/package.json create mode 100644 eg/redis/redis-bot.js diff --git a/.travis.yml b/.travis.yml index 9e433f0..91c2857 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "8" - "7" - "6" - - "5" before_install: - npm install -g babel-cli webpack uglify-js nodeunit script: npm run test diff --git a/README.md b/README.md index bc0387a..7e9f1f4 100644 --- a/README.md +++ b/README.md @@ -11,40 +11,106 @@ pairs for building up a bot's intelligence. This library can be used both in a web browser or as a Node module. See the `eg/` folder for examples. -## NOTICE: CHANGES IN v2.0.0 ALPHA - -This branch is currently the alpha version of RiveScript v2.0.0. The -biggest change was adding the use of async/await throughout the codebase, -which necessarily had to break backwards compatibility with some of the -RiveScript API. - -* `reply()` now returns a Promise instead of a string, like `replyAsync()` - did before. -* `loadFile()` and `loadDirectory()` now are Promise-based instead of - callback-based. -* `replyAsync()` is now deprecated and will be removed soon. - -This means your use of `reply()` will need to be updated to use the -Promise. If you are already using `replyAsync()`, just replace the -function name with `reply()` and it works the same way. - -```diff - var bot = new RiveScript(); -- bot.loadDirectory("./brain", onSuccess, onError); -+ bot.loadDirectory("./brain").then(onReady).catch(onError); - - function onReady() { - bot.sortReplies(); - console.log("Bot is ready!"); - -- var reply = bot.reply(username, message); -- console.log("Bot>", reply); -+ bot.reply(username, message).then(function(reply) { -+ console.log("Bot> ", reply); -+ }); - } +## USAGE + +```javascript +var bot = new RiveScript(); + +// Load a directory full of RiveScript documents (.rive files). This is for +// Node.JS only: it doesn't work on the web! +bot.loadDirectory("brain").then(loading_done).catch(loading_error); + +// Load an individual file. +bot.loadFile("brain/testsuite.rive").then(loading_done).catch(loading_error); + +// Load a list of files all at once (the best alternative to loadDirectory +// for the web!) +bot.loadFile([ + "brain/begin.rive", + "brain/admin.rive", + "brain/clients.rive" +]).then(loading_done).catch(loading_error); + +// All file loading operations are asynchronous, so you need handlers +// to catch when they've finished. If you use loadDirectory (or loadFile +// with multiple file names), the success function is called only when ALL +// the files have finished loading. +function loading_done() { + console.log("Bot has finished loading!"); + + // Now the replies must be sorted! + bot.sortReplies(); + + // And now we're free to get a reply from the brain! + + // RiveScript remembers user data by their username and can tell + // multiple users apart. + let username = "local-user"; + + // NOTE: the API has changed in v2.0.0 and returns a Promise now. + bot.reply(username, "Hello, bot!").then(function(reply) { + console.log("The bot says: " + reply); + }); +} + +// It's good to catch errors too! +function loading_error(error, filename, lineno) { + console.log("Error when loading files: " + error); +} +``` + +The distribution of RiveScript.js includes an interactive shell for testing your +RiveScript bot, `shell.js`. Run it with Node and point it to a folder where you +have your RiveScript documents. Example: + +```bash +node shell.js eg/brain ``` +Once inside the shell you can chat with the bot using the RiveScript files in +that directory. For simple debugging you can type `/eval` to run single lines +of JavaScript code. See `/help` for more. + +Both shell scripts accept command line parameters: + +* `--debug`: enables verbose debug logging. +* `--watch`: watch the reply folder for changes and automatically reload the + bot when files are modified. +* `--utf8`: enables UTF-8 mode. + +When using RiveScript.js as a library, the synopsis is as follows: + +## NOTICE: CHANGES IN v2.0.0 + +RiveScript v2.0.0 comes with a **massive** refactor of the codebase to +implement modern Async/Await features all throughout. This refactor +enables the following **new features**: + +* You can now `` asynchronous object macros inside of `*Condition` + checks. +* You can **actively** store users' variables into a database or + Redis cache. The module `rivescript-redis` provides a Redis cache + driver for this feature and there's an example bot at + [eg/redis](https://github.com/aichaos/rivescript-js/tree/master/eg/redis). + Other drivers (MongoDB, etc.) are up to you to write (send a pull + request! Use the Redis driver as an example) + +Because everything had to upgrade to async functions for this to work, +it necessarily had to break backwards compatibility slightly: + +* **reply()** now returns a Promise instead of a string, like replyAsync() + has always done. +* All user variable functions (getUservars, setUservars, etc.) now return + a Promise rather than their values directly; this change is what makes + it possible to swap out async database drivers instead of the default + in-memory store! +* **loadFile()** and **loadDirectory()** now return Promises. However, the + old callback-based syntax still works but is now deprecated. +* **replyAsync()** is now deprecated in favor of just **reply()** since + they both do the same thing. + +See the [Change Log](https://github.com/aichaos/rivescript-js/blob/master/Changes.md) for more details. + ## DOCUMENTATION There is generated Markdown and HTML documentation of the modules in the @@ -95,70 +161,6 @@ and sharing code with others. -## USAGE - -The distribution of RiveScript.js includes an interactive shell for testing your -RiveScript bot, `shell.js`. Run it with Node and point it to a folder where you -have your RiveScript documents. Example: - -```bash -node shell.js eg/brain -``` - -Once inside the shell you can chat with the bot using the RiveScript files in -that directory. For simple debugging you can type `/eval` to run single lines -of JavaScript code. See `/help` for more. - -Both shell scripts accept command line parameters: - -* `--debug`: enables verbose debug logging. -* `--watch`: watch the reply folder for changes and automatically reload the - bot when files are modified. -* `--utf8`: enables UTF-8 mode. - -When using RiveScript.js as a library, the synopsis is as follows: - -```javascript -var bot = new RiveScript(); - -// Load a directory full of RiveScript documents (.rive files). This is for -// Node.JS only: it doesn't work on the web! -bot.loadDirectory("brain").then(loading_done).catch(loading_error); - -// Load an individual file. -bot.loadFile("brain/testsuite.rive").then(loading_done).catch(loading_error); - -// Load a list of files all at once (the best alternative to loadDirectory -// for the web!) -bot.loadFile([ - "brain/begin.rive", - "brain/admin.rive", - "brain/clients.rive" -]).then(loading_done).catch(loading_error); - -// All file loading operations are asynchronous, so you need handlers -// to catch when they've finished. If you use loadDirectory (or loadFile -// with multiple file names), the success function is called only when ALL -// the files have finished loading. -function loading_done() { - console.log("Bot has finished loading!"); - - // Now the replies must be sorted! - bot.sortReplies(); - - // And now we're free to get a reply from the brain! - // NOTE: the API has changed in v2.0.0 and returns a Promise now. - bot.reply("local-user", "Hello, bot!").then(function(reply) { - console.log("The bot says: " + reply); - }); -} - -// It's good to catch errors too! -function loading_error(error, filename, lineno) { - console.log("Error when loading files: " + error); -} -``` - ## UTF-8 SUPPORT Version 1.0.5 adds **experimental** support for UTF-8 in RiveScript documents. diff --git a/contrib/redis/index.js b/contrib/redis/index.js new file mode 100644 index 0000000..9cb9923 --- /dev/null +++ b/contrib/redis/index.js @@ -0,0 +1,241 @@ +/* +Redis Driver for RiveScript User Variable Session Manager. +*/ + +const redis = require("redis"); + +// debug function +var Debug = false; +function say(arguments) { + if (Debug) { + console.log(arguments); + } +} + +/** + * RedisSessionManager provides a Redis-backed session store for RiveScript. + */ +class RedisSessionManager { + /** + * RedisSessions(redisOptions) + * + * Initialize the Redis session manager. The constructor object is passed + * directly to the underlying Redis module. + */ + constructor(opts) { + this._prefix = typeof(opts) === "object" ? opts.prefix : null; + this._client = redis.createClient(opts); + } + + // init loads the user's session object from Redis. If they don't exist in + // Redis, it returns a new default session (but will not create a Redis + // entry until you actually save variables for the user the first time). + async init(username) { + let self = this; + + let data = await self.redisGet(username); + if (data === null) { + say("init: user ${username} not found, create default session"); + data = self.defaultSession(); + await self.redisSet(username, data); + } + + return data; + } + + // method to retrieve JSON value from a Redis key + async redisGet(key) { + let self = this; + + // Redis module doesn't have a Promise-based API, so wrap it in + // a Promise for easy use. + return new Promise((resolve, reject) => { + self._client.get(key, (err, reply) => { + if (reply === null) { + resolve(null); + return; + } + + let data = JSON.parse(reply.toString()); + resolve(data); + }); + }); + } + + // method to delete a Redis key + async redisDel(key) { + let self = this; + + // Redis module doesn't have a Promise-based API, so wrap it in + // a Promise for easy use. + return new Promise((resolve, reject) => { + self._client.del(key, (err, reply) => { + resolve(); + }); + }); + } + + // method to store a JSON object to a Redis key + async redisSet(key, data) { + let self = this; + let serialized = JSON.stringify(data, null, 2); + return new Promise((resolve, reject) => { + self._client.set(key, serialized, (err, reply) => { + if (err) { + reject(err); + } else { + resolve(); + } + }) + }); + } + + // method to run a KEYS operation in Redis as a Promise + async redisKeys(pattern) { + let self = this; + return new Promise((resolve, reject) => { + self._client.keys(pattern, (err, replies) => { + resolve(replies); + }) + }) + } + + // method to get all usernames in storage + async allUsernames() { + // Redis key search pattern. + let pattern = "*" + if (this._prefix !== null) { + pattern = this._prefix + pattern; + } + + let keys = await this.redisKeys(pattern); + let usernames = keys.map((el) => { + let prefix = this._prefix === null ? "" : this._prefix; + return el.replace(new RegExp("^" + prefix), ""); + }); + + return usernames; + } + + /* + The functions below implement the RiveScript SessionManager interface. + https://github.com/aichaos/rivescript-js/blob/master/src/sessions.js + */ + + defaultSession() { + return { + "topic": "random" + } + } + + async set(username, data) { + // Initialize the user if they don't exist in Redis or load their + // existing session object. + let session = await this.init(username); + + for (var key of Object.keys(data)) { + if (data.hasOwnProperty(key)) { + session[key] = data[key]; + } + } + + await this.redisSet(username, session); + } + + // get a specific user variable key + // returns null if username is not found in session store + // returns the string "undefined" if the user variable was not set + // for that username (but the username does exist) + // otherwise returns the value of the user variable, usually a string type. + async get(username, key) { + let session = await this.redisGet(username); + + // User not found? + if (session === null) { + say(`get(${username},${key}): session did not exist`); + return null; + } + + // Key not set for user? + if (session[key] === undefined) { + say(`get(${username},${key}): username exists, but key not set`); + return "undefined"; // the classic RiveScript undefined string + } + + say(`get(${username},${key}): found value ${session[key]}`); + return session[key]; + } + + // get the entire set of user variables as an object. + // returns null if username not found in session store. + async getAny(username) { + let session = await this.redisGet(username); + return session; + } + + // getAll returns ALL user variables stored in your Redis cache as an array + // of objects. + async getAll() { + let self = this; + + let usernames = await this.allUsernames(); + + let result = {}; + for (let user of usernames) { + result[user] = await self.getAny(user); + } + + return result; + } + + // reset all user data for a user or all users + async reset(username) { + if (username) { + // Nuke only one user. + say(`reset: clear vars for user ${username}`) + return await this.redisDel(username); + } + + // Nuking ALL the users. + let usernames = await this.allUsernames(); + say(`reset: delete users ${usernames}`); + for (let user of usernames) { + await this.redisDel(user); + } + } + + // reset all users data + async resetAll() { + return reset(); + } + + // freeze user variables + async freeze(username) { + let session = await this.redisGet(username); + if (session === null) { + throw `freeze(${username}): user not found`; + } + + await this.redisSet(username+":frozen", session); + } + + // thaw frozen user variables + async thaw(username, action="thaw") { + let frozen = await this.redisGet(username+":frozen"); + if (frozen === null) { + throw `thaw(${username}): no frozen variables found`; + } + + // restore user variables from frozen state + if (action === "thaw" || action == "keep") { + await this.redisSet(username, frozen); + } + + // discard of old frozen state? + if (action === "thaw" || action === "discard") { + await this.redisDel(username+":frozen"); + } + } +} + +module.exports = RedisSessionManager; diff --git a/contrib/redis/package-lock.json b/contrib/redis/package-lock.json new file mode 100644 index 0000000..72a8d99 --- /dev/null +++ b/contrib/redis/package-lock.json @@ -0,0 +1,33 @@ +{ + "name": "rivescript-redis", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + }, + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "requires": { + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" + } + }, + "redis-commands": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", + "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==" + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" + } + } +} diff --git a/contrib/redis/package.json b/contrib/redis/package.json new file mode 100644 index 0000000..aefa008 --- /dev/null +++ b/contrib/redis/package.json @@ -0,0 +1,25 @@ +{ + "name": "rivescript-redis", + "version": "1.0.0", + "description": "A Redis session driver to actively store RiveScript user variables.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/aichaos/rivescript-js.git" + }, + "keywords": [ + "rivescript" + ], + "author": "root@kirsle.net", + "license": "MIT", + "bugs": { + "url": "https://github.com/aichaos/rivescript-js/issues" + }, + "homepage": "https://github.com/aichaos/rivescript-js#readme", + "dependencies": { + "redis": "^2.8.0" + } +} diff --git a/eg/README.md b/eg/README.md index 6ee8c91..680cd04 100644 --- a/eg/README.md +++ b/eg/README.md @@ -29,6 +29,8 @@ RiveScript-js. ## Code Snippets +* [redis](redis/) - Demonstrates storing user variables actively in a Redis + cache server (to recall user variables across bot sessions). * [persistence](persistence/) - Demonstrates persistence for user variables; the bot can be shut down and restarted and it can remember where it left off with its users. diff --git a/eg/redis/README.md b/eg/redis/README.md new file mode 100644 index 0000000..5a34d46 --- /dev/null +++ b/eg/redis/README.md @@ -0,0 +1,102 @@ +# Redis Session Manager Example + +This example implements a simple RiveScript bot that uses a +[Redis](https://redis.io) cache server to **actively** store user variables, +instead of keeping them in memory as default. + +The crucial bit of code for your own use case is like the following: + +```javascript +// Import rivescript and rivescript-redis +const RiveScript = require("rivescript"), + RedisSessionManager = require("rivescript-redis"); + +// Construct your RiveScript bot as normal... +let bot = new RiveScript({ + utf8: true, + + // Give it a new Redis session manager. + sessionManager: new RedisSessionManager({ + // The constructor takes an `opts` object, and mostly passes it + // directly along to the underlying `redis` module. So all these + // parameters come from `redis` + host: "localhost", // default + port: 6369, + + // NOTE: this option is used by `redis` and is also noticed by + // rivescript-redis: it's optional but recommended to set a + // prefix. The Redis keys otherwise are simply the username + // given to RiveScript. + prefix: "rivescript/" + }) +}); + +// And carry on as normal. All user variables will be actively persisted +// in Redis (no need to call `getUservars()` and `setUservars()` to manage +// them yourself -- though these functions DO work and will get you current +// data from your Redis cache!) +``` + +## Requirements + +Install and run a [Redis](https://redis.io) server on localhost before +running this script. + +This script imports the **local copy** of `redis-rivescript` and is intended +to be run from the source code tree of rivescript-js. That is, it expects to +be able to import `../../contrib/redis` relative to itself. + +## Example Output + +``` +% node redis-bot.js +Redis Session Manager Example + +This script will connect to the Redis server at localhost:6379 and store +RiveScript user variables into keys with the prefix "rivescript/" followed +by their username. For example, the default username "soandso" would have +its user variables actively stored at the Redis key "rivescript/soandso". + +Enter any username for yourself> kirsle + +The example chatbot has been loaded and you will now enter a chat session +with it. Trying saying "hello" or "my name is kirsle" + +Type "/help" for some commands to test the Redis system. +Type "/quit" to quit. + + +kirsle> Hello bot +Bot> How do you do. Please state your problem. +kirsle> My name is noah +Bot> Noah, nice to meet you. +kirsle> /dump-users +Dump of all user variables in Redis +{ + "kirsle": { + "topic": "random", + "__initialmatch__": "my name is *", + "name": "Noah", + + ...some spammy keys redacted... + } +} +kirsle> /help +Commands available: +/user + Dump the user variables for a specific username to console. + Note: this data is coming from Redis! + +/dump-users + Dump all data about all users. + +/reset [username] + Reset user variables for a username, or if not provided, reset + all variables. This will clear all "rivescript/*" keys from your + Redis cache. + +/quit + Exit this program + +kirsle> /quit +``` diff --git a/eg/redis/package-lock.json b/eg/redis/package-lock.json new file mode 100644 index 0000000..8dce4a2 --- /dev/null +++ b/eg/redis/package-lock.json @@ -0,0 +1,33 @@ +{ + "name": "redis-bot-example", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + }, + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "requires": { + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" + } + }, + "redis-commands": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", + "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==" + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" + } + } +} diff --git a/eg/redis/package.json b/eg/redis/package.json new file mode 100644 index 0000000..9ff2da0 --- /dev/null +++ b/eg/redis/package.json @@ -0,0 +1,14 @@ +{ + "name": "redis-bot-example", + "version": "1.0.0", + "description": "", + "main": "redis-bot.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "redis": "^2.8.0" + } +} diff --git a/eg/redis/redis-bot.js b/eg/redis/redis-bot.js new file mode 100644 index 0000000..9536b2a --- /dev/null +++ b/eg/redis/redis-bot.js @@ -0,0 +1,120 @@ +/* +Example RiveScript bot that uses a Redis cache to store user variables. +*/ + +const RiveScript = require("../../src/rivescript"), + RedisSessionManager = require("../../contrib/redis"), + readline = require("readline"); + +async function main() { + console.log(`Redis Session Manager Example + +This script will connect to the Redis server at localhost:6379 and store +RiveScript user variables into keys with the prefix "rivescript/" followed +by their username. For example, the default username "soandso" would have +its user variables actively stored at the Redis key "rivescript/soandso". +`); + let bot = new RiveScript({ + utf8: true, + debug: false, + sessionManager: new RedisSessionManager({ + prefix: "rivescript/" + }) + }); + + await bot.loadDirectory("../brain"); + bot.sortReplies(); + + // Set up a command line interface to talk to the bot. + var rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + rl.setPrompt("You> "); + + // Prompt the user for their username. + rl.question("Enter any username for yourself> ", (username) => { + if (!username) { + console.log("No answer? I will call you 'soandso'"); + username = "soandso"; + } + + console.log(` +The example chatbot has been loaded and you will now enter a chat session +with it. Trying saying "hello" or "my name is ${username}" + +Type "/help" for some commands to test the Redis system. +Type "/quit" to quit. + +`); + + // Enter the main prompt loop. + rl.setPrompt(`${username}> `); + rl.prompt(); + rl.on("line", async (message) => { + if (message === "/quit") { + process.exit(0); + } else if (message === "/help") { + console.log(`Commands available: +/user + Dump the user variables for a specific username to console. + Note: this data is coming from Redis! + +/dump-users + Dump all data about all users. + +/reset [username] + Reset user variables for a username, or if not provided, reset + all variables. This will clear all "rivescript/*" keys from your + Redis cache. + +/quit + Exit this program +`); + rl.prompt(); + } else if (message.indexOf("/user ") === 0) { + // "/user ": dump user variables + let value = message.substring("/user ".length); + console.log(`Uservars for ${value}:\n`); + + let data = await bot.getUservars(value); + console.log(JSON.stringify(data, null, 2)); + rl.prompt(); + } else if (message.indexOf("/eval ") === 0) { + // "/eval ": run arbitrary JS code + let value = message.substring("/eval ".length); + eval(value); + rl.prompt(); + } else if (message.indexOf("/dump-users") === 0) { + // "/dump-users" prints out getUservars() on all users. + console.log(`Dump of all user variables in Redis`); + + let data = await bot.getUservars(); + console.log(JSON.stringify(data, null, 2)); + rl.prompt(); + } else if (message.indexOf("/reset") === 0) { + // "/reset [username]": clear user vars for all users or one + let username = message.substring("/reset ".length); + + await bot.clearUservars(username); + + if (username) { + console.log(`Clear uservars for ${username}`); + } else { + console.log(`Clear all uservars`); + } + rl.prompt(); + } else { + bot.reply(username, message).then((reply) => { + console.log("Bot>", reply); + rl.prompt(); + return; + }).catch((err) => { + console.error("Error>", err); + }); + } + }); + }); +} + +main(); diff --git a/src/rivescript.js b/src/rivescript.js index e35d133..00d0d0c 100644 --- a/src/rivescript.js +++ b/src/rivescript.js @@ -991,9 +991,9 @@ const RiveScript = (function() { async getUservars(user) { var self = this; if (user === undefined) { - return self._session.getAny(user); - } else { return self._session.getAll(); + } else { + return self._session.getAny(user); } }