Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement pluggable session store and make it threadsafe #12

Merged
merged 4 commits into from
Dec 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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