Skip to content

Commit

Permalink
Merge pull request #12 from aichaos/feature/session-store
Browse files Browse the repository at this point in the history
Implement pluggable session store and make it threadsafe
  • Loading branch information
kirsle authored Dec 11, 2016
2 parents ffebfa3 + a2415a5 commit 7f29a68
Show file tree
Hide file tree
Showing 28 changed files with 779 additions and 234 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export GOPATH="$(pwd)/.gopath"
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ setup:
run: gopath
GOPATH=$(GOPATH) GO15VENDOREXPERIMENT=1 go run cmd/rivescript/main.go eg/brain

# `make debug` to run the rivescript cmd in debug mode
debug: gopath
GOPATH=$(GOPATH) GO15VENDOREXPERIMENT=1 go run cmd/rivescript/main.go -debug eg/brain

# `make fmt` to run gofmt
fmt:
gofmt -w .
Expand Down
40 changes: 36 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,12 @@ package main

import (
"fmt"
rivescript "github.com/aichaos/rivescript-go"
"github.com/aichaos/rivescript-go"
"github.com/aichaos/rivescript-go/config"
)

func main() {
bot := rivescript.New()
bot := rivescript.New(config.Basic())

// Load a directory full of RiveScript documents (.rive files)
err := bot.LoadDirectory("eg/brain")
Expand All @@ -103,6 +104,35 @@ func main() {
}
```

## Configuration

The constructor takes an optional `Config` struct. Here is a full example with
all the supported options. You only need to provide keys that are different to
the defaults.

```go
bot := rs.New(&config.Config{
Debug: false, // Debug mode, off by default
Strict: false, // No strict syntax checking
UTF8: false, // No UTF-8 support enabled by default
Depth: 50, // Becomes default 50 if Depth is <= 0
SessionManager: memory.New(), // Default in-memory session manager
})
```

For convenience, the `config` package provides two config templates:

```go
// Basic has all the defaults, plus Strict=true
bot := rs.New(config.Basic())

// UTF8 has all of Basic's settings, plus UTF8=true
bot := rs.New(config.UTF8())

// You can also provide a nil configuration, which defaults to Basic()
bot := rs.New(nil)
```

## Object Macros

A common feature in many RiveScript implementations is the object macro, which
Expand Down Expand Up @@ -136,8 +166,7 @@ string literal to the `RiveScript.SetUnicodePunctuation` function. Example:

```go
// Make a new bot with UTF-8 mode enabled.
bot := rivescript.New()
bot.SetUTF8(true)
bot := rivescript.New(config.UTF8())

// Override the punctuation characters that get stripped from the
// user's message.
Expand Down Expand Up @@ -221,6 +250,9 @@ The distributable directory contains only the following types of files:
code and returning an "abstract syntax tree."
* [rivescript-go/macro](./macro) - Contains an interface for creating your own
object macro handlers for foreign programming languages.
* [rivescript-go/sessions](./sessions) - Contains the interface for user
variable session managers as well as the default in-memory manager and the
`NullStore` for testing.

## License

Expand Down
22 changes: 13 additions & 9 deletions cmd/rivescript/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,21 @@ import (
"bufio"
"flag"
"fmt"
rivescript "github.com/aichaos/rivescript-go"
js "github.com/aichaos/rivescript-go/lang/javascript"
"os"
"strings"

"github.com/aichaos/rivescript-go"
"github.com/aichaos/rivescript-go/config"
"github.com/aichaos/rivescript-go/lang/javascript"
)

func main() {
// Collect command line arguments.
version := flag.Bool("version", false, "Show the version number and exit.")
debug := flag.Bool("debug", false, "Enable debug mode.")
utf8 := flag.Bool("utf8", false, "Enable UTF-8 mode.")
depth := flag.Int("depth", 50, "Recursion depth limit (default 50)")
depth := flag.Uint("depth", 50, "Recursion depth limit (default 50)")
nostrict := flag.Bool("nostrict", false, "Disable strict syntax checking")
flag.Parse()
args := flag.Args()

Expand All @@ -48,14 +51,15 @@ func main() {
root := args[0]

// Initialize the bot.
bot := rivescript.New()
bot.SetDebug(*debug)
bot.SetUTF8(*utf8)
bot.SetDepth(*depth)
bot := rivescript.New(&config.Config{
Debug: *debug,
Strict: !*nostrict,
Depth: *depth,
UTF8: *utf8,
})

// JavaScript object macro handler.
jsHandler := js.New(bot)
bot.SetHandler("javascript", jsHandler)
bot.SetHandler("javascript", javascript.New(bot))

// Load the target directory.
err := bot.LoadDirectory(root)
Expand Down
54 changes: 54 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Package config provides the RiveScript configuration type.
package config

import (
"github.com/aichaos/rivescript-go/sessions"
"github.com/aichaos/rivescript-go/sessions/memory"
)

// Type Config configures a RiveScript instance.
type Config struct {
// Debug enables verbose debug logging to your standard output.
Debug bool

// Strict enables strict syntax checking.
Strict bool

// Depth sets the recursion depth limit. The zero value will default to
// 50 levels deep.
Depth uint

// UTF8 enables UTF-8 support for user messages and triggers.
UTF8 bool

// SessionManager chooses a session manager for user variables.
SessionManager sessions.SessionManager
}

// Basic creates a default configuration:
//
// - Strict: true
// - Depth: 50
// - UTF8: false
func Basic() *Config {
return &Config{
Strict: true,
Depth: 50,
UTF8: false,
SessionManager: memory.New(),
}
}

// UTF8 creates a default configuration with UTF-8 mode enabled.
//
// - Strict: true
// - Depth: 50
// - UTF8: true
func UTF8() *Config {
return &Config{
Strict: true,
Depth: 50,
UTF8: true,
SessionManager: memory.New(),
}
}
3 changes: 1 addition & 2 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ set being `/[.,!?;:]/g`. This can be overridden by providing a new regexp
string literal to the `RiveScript.SetUnicodePunctuation` function. Example:
// Make a new bot with UTF-8 mode enabled.
bot := rivescript.New()
bot.SetUTF8(true)
bot := rivescript.New(config.UTF8())
// Override the punctuation characters that get stripped from the
// user's message.
Expand Down
15 changes: 8 additions & 7 deletions doc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package rivescript_test

import (
"fmt"
rivescript "github.com/aichaos/rivescript-go"
js "github.com/aichaos/rivescript-go/lang/javascript"

"github.com/aichaos/rivescript-go"
"github.com/aichaos/rivescript-go/config"
"github.com/aichaos/rivescript-go/lang/javascript"
rss "github.com/aichaos/rivescript-go/src"
)

func ExampleRiveScript() {
bot := rivescript.New()
bot := rivescript.New(config.Basic())

// Load a directory full of RiveScript documents (.rive files)
bot.LoadDirectory("eg/brain")
Expand All @@ -27,11 +29,10 @@ func ExampleRiveScript() {
func ExampleRiveScript_javascript() {
// Example for configuring the JavaScript object macro handler via Otto.

bot := rivescript.New()
bot := rivescript.New(config.Basic())

// Create the JS handler.
jsHandler := js.New(bot)
bot.SetHandler("javascript", jsHandler)
bot.SetHandler("javascript", javascript.New(bot))

// Now we can use object macros written in JS!
bot.Stream(`
Expand Down Expand Up @@ -66,7 +67,7 @@ func ExampleRiveScript_subroutine() {
// Example for defining a Go function as an object macro.
// import rss "github.com/aichaos/rivescript-go/src"

bot := rivescript.New()
bot := rivescript.New(config.Basic())

// Define an object macro named `setname`
bot.SetSubroutine("setname", func(rs *rss.RiveScript, args []string) string {
Expand Down
7 changes: 4 additions & 3 deletions lang/javascript/javascript.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Usage is simple. In your Golang code:
)
func main() {
bot := rivescript.New()
bot := rivescript.New(nil)
jsHandler := javascript.New(bot)
bot.SetHandler("javascript", jsHandler)
Expand Down Expand Up @@ -49,9 +49,10 @@ package javascript

import (
"fmt"
rivescript "github.com/aichaos/rivescript-go"
"github.com/robertkrimen/otto"
"strings"

"github.com/aichaos/rivescript-go"
"github.com/robertkrimen/otto"
)

type JavaScriptHandler struct {
Expand Down
20 changes: 11 additions & 9 deletions rivescript.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ package rivescript
*/

import (
"github.com/aichaos/rivescript-go/config"
"github.com/aichaos/rivescript-go/macro"
"github.com/aichaos/rivescript-go/sessions"
"github.com/aichaos/rivescript-go/src"
)

const VERSION string = "0.0.3"

type RiveScript struct {
rs *src.RiveScript
rs *rivescript.RiveScript
}

func New() *RiveScript {
func New(config *config.Config) *RiveScript {
bot := new(RiveScript)
bot.rs = src.New()
bot.rs = rivescript.New(config)
return bot
}

Expand Down Expand Up @@ -62,12 +64,12 @@ func (self *RiveScript) SetUnicodePunctuation(value string) {
}

// SetDepth lets you override the recursion depth limit (default 50).
func (self *RiveScript) SetDepth(value int) {
func (self *RiveScript) SetDepth(value uint) {
self.rs.Depth = value
}

// GetDepth returns the current recursion depth limit.
func (self *RiveScript) GetDepth() int {
func (self *RiveScript) GetDepth() uint {
return self.rs.Depth
}

Expand Down Expand Up @@ -167,7 +169,7 @@ Parameters
name: The name of your subroutine for the `<call>` tag in RiveScript.
fn: A function with a prototype `func(*RiveScript, []string) string`
*/
func (self *RiveScript) SetSubroutine(name string, fn src.Subroutine) {
func (self *RiveScript) SetSubroutine(name string, fn rivescript.Subroutine) {
self.rs.SetSubroutine(name, fn)
}

Expand Down Expand Up @@ -277,7 +279,7 @@ GetUservars gets all the variables for a user.
This returns a `map[string]string` containing all the user's variables.
*/
func (self *RiveScript) GetUservars(username string) (map[string]string, error) {
func (self *RiveScript) GetUservars(username string) (*sessions.UserData, error) {
return self.rs.GetUservars(username)
}

Expand All @@ -287,7 +289,7 @@ GetAllUservars gets all the variables for all the users.
This returns a map of username (strings) to `map[string]string` of their
variables.
*/
func (self *RiveScript) GetAllUservars() map[string]map[string]string {
func (self *RiveScript) GetAllUservars() map[string]*sessions.UserData {
return self.rs.GetAllUservars()
}

Expand Down Expand Up @@ -319,7 +321,7 @@ The `action` can be one of the following:
* discard: Don't restore the variables, just delete the frozen copy.
* keep: Keep the frozen copy after restoring.
*/
func (self *RiveScript) ThawUservars(username, action string) error {
func (self *RiveScript) ThawUservars(username string, action sessions.ThawAction) error {
return self.rs.ThawUservars(username, action)
}

Expand Down
Loading

0 comments on commit 7f29a68

Please sign in to comment.