-
Notifications
You must be signed in to change notification settings - Fork 31
/
lualoader.go
99 lines (85 loc) · 2.29 KB
/
lualoader.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
package script
import (
"context"
"errors"
"fmt"
"log"
"time"
loaderpkg "github.com/kelindar/loader"
"github.com/kelindar/lua"
"github.com/kelindar/talaria/internal/encoding/typeof"
)
type LuaLoader struct {
modules []lua.Module // The modules for the scripting environment
Loader
code *lua.Script // The script associated with the column
typ typeof.Type // The type of the column
}
// NewLuaLoader creates a new loader that can be used to load scripts
func NewLuaLoader(luaModules []lua.Module, typ typeof.Type) *LuaLoader {
return &LuaLoader{
modules: luaModules,
Loader: Loader{loaderpkg.New()},
typ: typ,
}
}
func (l *LuaLoader) String() string { return luaType }
// Load creates a new script from code or URL and starts a watching if needed
func (l *LuaLoader) Load(uriOrCode string) (Handler, error) {
log.Println("LuaLoader loadLua: ", uriOrCode)
// Default empty script
const emptyScript = `function main(row)
return null
end`
// Create an empty script, we'll update it right away
var err error
l.code, err = lua.FromString("luaScript", emptyScript, l.modules...)
if err != nil {
return nil, err
}
// If the string is actually a URL, try to download it
if err := l.watch(uriOrCode, l.code.Update); err != nil {
return nil, err
}
return l, nil
}
func (l *LuaLoader) Value(row map[string]interface{}) (interface{}, error) {
if l.code == nil {
return nil, errors.New("LuaLoader's code is not loaded, nil")
}
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
// Run the script
out, err := l.code.Run(ctx, row)
if err != nil {
return nil, err
}
// If there's no new row generated, return nil
if out.Type() == lua.TypeNil {
return nil, nil
}
switch l.typ {
case typeof.Bool:
if v, ok := out.(lua.Bool); ok {
return bool(v), nil
}
case typeof.Int32:
if v, ok := out.(lua.Number); ok {
return int32(v), nil
}
case typeof.Int64, typeof.Timestamp:
if v, ok := out.(lua.Number); ok {
return int64(v), nil
}
case typeof.Float64:
if v, ok := out.(lua.Number); ok {
return float64(v), nil
}
case typeof.String, typeof.JSON:
if v, ok := out.(lua.String); ok {
return string(v), nil
}
}
// Type mismatch
return nil, fmt.Errorf("script expects %s type but got %T", l.typ.String(), out)
}