-
Notifications
You must be signed in to change notification settings - Fork 15
/
config.go
357 lines (288 loc) · 8.85 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
package rivescript
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/aichaos/rivescript-go/macro"
"github.com/aichaos/rivescript-go/sessions"
)
/*
Config provides options to configure the RiveScript bot.
Create a pointer to this type and send it to the New() constructor to change
the default settings. You only need to provide settings you want to override;
the zero-values of all the options are handled appropriately by the RiveScript
library.
The default values are documented below.
*/
type Config struct {
// Debug enables verbose logging to standard output. Default false.
Debug bool
// Strict enables strict syntax checking, where a syntax error in RiveScript
// code is considered fatal at parse time. Default true.
Strict bool
// UTF8 enables UTF-8 mode within the bot. Default false.
//
// When UTF-8 mode is enabled, triggers in the RiveScript source files are
// allowed to contain foreign characters. Additionally, the user's incoming
// messages are left *mostly* intact, so that they send messages with
// foreign characters to the bot.
UTF8 bool
// Depth controls the global limit for recursive functions within
// RiveScript. Default 50.
Depth uint
// Random number seed, if you'd like to customize it. The default is for
// RiveScript to choose its own seed, `time.Now().UnixNano()`
Seed int64
// Preserve the capitalization on a user's message instead of lowercasing it.
// By default RiveScript will lowercase all messages coming in - set this and
// the original casing will be preserved through wildcards and star tags.
CaseSensitive bool
// SessionManager is an implementation of the same name for managing user
// variables for the bot. The default is the in-memory session handler.
SessionManager sessions.SessionManager
}
// WithUTF8 provides a Config object that enables UTF-8 mode.
func WithUTF8() *Config {
return &Config{
UTF8: true,
}
}
/*
SetHandler sets a custom language handler for RiveScript object macros.
Parameters
lang: What your programming language is called, e.g. "javascript"
handler: An implementation of macro.MacroInterface.
*/
func (rs *RiveScript) SetHandler(lang string, handler macro.MacroInterface) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
rs.handlers[lang] = handler
}
/*
RemoveHandler removes an object macro language handler.
If the handler has already loaded object macros, they will be deleted from
the bot along with the handler.
Parameters
lang: The programming language for the handler to remove.
*/
func (rs *RiveScript) RemoveHandler(lang string) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
// Purge all loaded objects for this handler.
for name, language := range rs.objlangs {
if language == lang {
delete(rs.objlangs, name)
}
}
// And delete the handler itself.
delete(rs.handlers, lang)
}
/*
SetSubroutine defines a Go object macro from your program.
Parameters
name: The name of your subroutine for the `<call>` tag in RiveScript.
fn: A function with a prototype `func(*RiveScript, []string) string`
*/
func (rs *RiveScript) SetSubroutine(name string, fn Subroutine) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
rs.subroutines[name] = fn
}
/*
DeleteSubroutine removes a Go object macro.
Parameters
name: The name of the object macro to be deleted.
*/
func (rs *RiveScript) DeleteSubroutine(name string) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
delete(rs.subroutines, name)
}
/*
SetGlobal sets a global variable.
This is equivalent to `! global` in RiveScript. Set the value to `undefined`
to delete a global.
*/
func (rs *RiveScript) SetGlobal(name, value string) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
// Special globals that reconfigure the interpreter.
if name == "debug" {
switch strings.ToLower(value) {
case "true", "t", "on", "yes":
rs.Debug = true
default:
rs.Debug = false
}
} else if name == "depth" {
depth, err := strconv.Atoi(value)
if err != nil {
rs.warn("Can't set global `depth` to `%s`: %s\n", value, err)
} else {
rs.Depth = uint(depth)
}
}
if value == UNDEFINED {
delete(rs.global, name)
} else {
rs.global[name] = value
}
}
/*
SetVariable sets a bot variable.
This is equivalent to `! var` in RiveScript. Set the value to `undefined`
to delete a bot variable.
*/
func (rs *RiveScript) SetVariable(name, value string) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
if value == UNDEFINED {
delete(rs.vars, name)
} else {
rs.vars[name] = value
}
}
/*
SetSubstitution sets a substitution pattern.
This is equivalent to `! sub` in RiveScript. Set the value to `undefined`
to delete a substitution.
*/
func (rs *RiveScript) SetSubstitution(name, value string) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
if value == UNDEFINED {
delete(rs.sub, name)
} else {
rs.sub[name] = value
}
}
/*
SetPerson sets a person substitution pattern.
This is equivalent to `! person` in RiveScript. Set the value to `undefined`
to delete a person substitution.
*/
func (rs *RiveScript) SetPerson(name, value string) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
if value == UNDEFINED {
delete(rs.person, name)
} else {
rs.person[name] = value
}
}
/*
SetUservar sets a variable for a user.
This is equivalent to `<set>` in RiveScript. Set the value to `undefined`
to delete a substitution.
*/
func (rs *RiveScript) SetUservar(username, name, value string) {
rs.sessions.Set(username, map[string]string{
name: value,
})
}
/*
SetUservars sets a map of variables for a user.
Set multiple user variables by providing a map[string]string of key/value pairs.
Equivalent to calling `SetUservar()` for each pair in the map.
*/
func (rs *RiveScript) SetUservars(username string, data map[string]string) {
rs.sessions.Set(username, data)
}
/*
GetGlobal gets a global variable.
This is equivalent to `<env name>` in RiveScript. Returns `undefined` if the
variable isn't defined.
*/
func (rs *RiveScript) GetGlobal(name string) (string, error) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
// Special globals.
if name == "debug" {
return fmt.Sprintf("%v", rs.Debug), nil
} else if name == "depth" {
return strconv.Itoa(int(rs.Depth)), nil
}
if _, ok := rs.global[name]; ok {
return rs.global[name], nil
}
return UNDEFINED, fmt.Errorf("global variable %s not found", name)
}
/*
GetVariable gets a bot variable.
This is equivalent to `<bot name>` in RiveScript. Returns `undefined` if the
variable isn't defined.
*/
func (rs *RiveScript) GetVariable(name string) (string, error) {
rs.cLock.Lock()
defer rs.cLock.Unlock()
if _, ok := rs.vars[name]; ok {
return rs.vars[name], nil
}
return UNDEFINED, fmt.Errorf("bot variable %s not found", name)
}
/*
GetUservar gets a user variable.
This is equivalent to `<get name>` in RiveScript. Returns `undefined` if the
variable isn't defined.
*/
func (rs *RiveScript) GetUservar(username, name string) (string, error) {
return rs.sessions.Get(username, name)
}
/*
GetUservars gets all the variables for a user.
This returns a `map[string]string` containing all the user's variables.
*/
func (rs *RiveScript) GetUservars(username string) (*sessions.UserData, error) {
return rs.sessions.GetAny(username)
}
/*
GetAllUservars gets all the variables for all the users.
This returns a map of username (strings) to `map[string]string` of their
variables.
*/
func (rs *RiveScript) GetAllUservars() map[string]*sessions.UserData {
return rs.sessions.GetAll()
}
// ClearUservars deletes all the variables that belong to a user.
func (rs *RiveScript) ClearUservars(username string) {
rs.sessions.Clear(username)
}
// ClearAllUservars deletes all variables for all users.
func (rs *RiveScript) ClearAllUservars() {
rs.sessions.ClearAll()
}
/*
FreezeUservars freezes the variable state of a user.
This will clone and preserve the user's entire variable state, so that it
can be restored later with `ThawUservars()`.
*/
func (rs *RiveScript) FreezeUservars(username string) error {
return rs.sessions.Freeze(username)
}
/*
ThawUservars unfreezes a user's variables.
The `action` can be one of the following:
* thaw: Restore the variables and delete the frozen copy.
* discard: Don't restore the variables, just delete the frozen copy.
* keep: Keep the frozen copy after restoring.
*/
func (rs *RiveScript) ThawUservars(username string, action sessions.ThawAction) error {
return rs.sessions.Thaw(username, action)
}
// LastMatch returns the user's last matched trigger.
func (rs *RiveScript) LastMatch(username string) (string, error) {
return rs.sessions.GetLastMatch(username)
}
/*
CurrentUser returns the current user's ID.
This is only useful from within an object macro, to get the ID of the user who
invoked the macro. This value is set at the beginning of `Reply()` and unset
at the end, so this function will return empty outside of a reply context.
*/
func (rs *RiveScript) CurrentUser() (string, error) {
if rs.inReplyContext {
return rs.currentUser, nil
}
return "", errors.New("CurrentUser() can only be called inside a reply context")
}