forked from kabukky/journey
-
Notifications
You must be signed in to change notification settings - Fork 0
/
loading.go
140 lines (136 loc) · 4.37 KB
/
loading.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
package plugins
import (
"errors"
"github.com/kabukky/journey/filenames"
"github.com/kabukky/journey/structure"
"github.com/yuin/gopher-lua"
"log"
"os"
"path/filepath"
)
func Load() error {
// Reset LuaPool for a fresh start
LuaPool = nil
// Make map
nameMap := make(map[string]string, 0)
err := filepath.Walk(filenames.PluginsFilepath, func(filePath string, info os.FileInfo, err error) error {
if !info.IsDir() && filepath.Ext(filePath) == ".lua" {
// Check if the lua file is a plugin entry point by executing it
helperNames, err := getHelperNames(filePath)
if err != nil {
return err
}
// Add all file names of helpers to the name map
for _, helperName := range helperNames {
absPath, err := filepath.Abs(filePath)
if err != nil {
log.Println("Error while determining absolute path to lua file:", err)
return err
}
nameMap[helperName] = absPath
}
}
return nil
})
if err != nil {
return err
}
if len(nameMap) == 0 {
return errors.New("No plugins were loaded.")
}
// If plugins were loaded, create LuaPool and assign name map to LuaPool
LuaPool = newLuaPool()
LuaPool.m.Lock()
defer LuaPool.m.Unlock()
LuaPool.files = nameMap
return nil
}
func getHelperNames(fileName string) ([]string, error) {
// Make a slice to hold all helper names
helperList := make([]string, 0)
// Create a new lua state
vm := lua.NewState()
defer vm.Close()
// Set up vm functions
values := &structure.RequestData{}
helper := &structure.Helper{}
absDir, err := filepath.Abs(fileName)
if err != nil {
log.Println("Error while determining absolute path to lua file:", err)
return helperList, err
}
setUpVm(vm, helper, values, absDir)
// Execute plugin
// TODO: Is there a better way to just load the file? We only need to execute the register function (see below)
err = vm.DoFile(absDir)
if err != nil {
// TODO: We are not returning upon error here. Keep it like this?
log.Println("Error while loading plugin:", err)
}
err = vm.CallByParam(lua.P{Fn: vm.GetGlobal("register"), NRet: 1, Protect: true})
if err != nil {
// Fail silently since this is probably just a lua file without a register function
return helperList, nil
}
// Get return value
table := vm.ToTable(-1)
// Check if return value is a table
if table != nil {
// Iterate the table for every helper name to be registered
table.ForEach(func(key lua.LValue, value lua.LValue) {
if str, ok := value.(lua.LString); ok {
if string(str) != "" {
helperList = append(helperList, string(str))
}
}
})
}
return helperList, nil
}
// Creates all methods that can be used from Lua.
func setUpVm(vm *lua.LState, helper *structure.Helper, values *structure.RequestData, absPathToLuaFile string) {
luaPath := filepath.Dir(absPathToLuaFile)
// Function to get the directory of the current file (to add to LUA_PATH in Lua)
vm.SetGlobal("getCurrentDir", vm.NewFunction(func(vm *lua.LState) int {
vm.Push(lua.LString(luaPath))
return 1 // Number of results
}))
// Function to print to the log
vm.SetGlobal("print", vm.NewFunction(func(vm *lua.LState) int {
log.Println(vm.Get(-1).String())
return 0 // Number of results
}))
// Function to get helper arguments
vm.SetGlobal("getArguments", vm.NewFunction(func(vm *lua.LState) int {
vm.Push(convertArguments(vm, helper.Arguments))
return 1 // Number of results
}))
// Function to get number of posts in values
vm.SetGlobal("getNumberOfPosts", vm.NewFunction(func(vm *lua.LState) int {
vm.Push(lua.LNumber(len(values.Posts)))
return 1 // Number of results
}))
// Function to get a post by its index
vm.SetGlobal("getPost", vm.NewFunction(func(vm *lua.LState) int {
postIndex := vm.ToInt(-1)
vm.Push(convertPost(vm, &values.Posts[postIndex-1]))
return 1 // Number of results
}))
// Function to get a user by post
vm.SetGlobal("getAuthorForPost", vm.NewFunction(func(vm *lua.LState) int {
postIndex := vm.ToInt(-1)
vm.Push(convertUser(vm, values.Posts[postIndex-1].Author))
return 1 // Number of results
}))
// Function to get tags by post
vm.SetGlobal("getTagsForPost", vm.NewFunction(func(vm *lua.LState) int {
postIndex := vm.ToInt(-1)
vm.Push(convertTags(vm, values.Posts[postIndex-1].Tags))
return 1 // Number of results
}))
// Function to get blog
vm.SetGlobal("getBlog", vm.NewFunction(func(vm *lua.LState) int {
vm.Push(convertBlog(vm, values.Blog))
return 1 // Number of results
}))
}