-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from kabukky/development
Added Plugins.
- Loading branch information
Showing
16 changed files
with
544 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# content/plugins | ||
|
||
Place your plugins here. | ||
|
||
Read https://github.com/kabukky/journey/wiki/Creating-a-Journey-Plugin for a tutorial on how to create your own Journey plugin. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package helpers | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
func GetFilenameWithoutExtension(path string) string { | ||
return filepath.Base(path)[0 : len(filepath.Base(path))-len(filepath.Ext(path))] | ||
} | ||
|
||
func IsDirectory(path string) bool { | ||
fileInfo, err := os.Stat(path) | ||
if err != nil { | ||
return false | ||
} | ||
return fileInfo.IsDir() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package plugins | ||
|
||
import ( | ||
"github.com/kabukky/journey/structure" | ||
"github.com/yuin/gopher-lua" | ||
) | ||
|
||
func convertPost(vm *lua.LState, structurePost *structure.Post) *lua.LTable { | ||
post := vm.NewTable() | ||
post.RawSet(lua.LString("id"), lua.LNumber(structurePost.Id)) | ||
post.RawSet(lua.LString("uuid"), lua.LString(structurePost.Uuid)) | ||
post.RawSet(lua.LString("title"), lua.LString(structurePost.Title)) | ||
post.RawSet(lua.LString("slug"), lua.LString(structurePost.Slug)) | ||
post.RawSet(lua.LString("markdown"), lua.LString(structurePost.Markdown)) | ||
post.RawSet(lua.LString("html"), lua.LString(structurePost.Html)) | ||
post.RawSet(lua.LString("isfeatured"), lua.LBool(structurePost.IsFeatured)) | ||
post.RawSet(lua.LString("ispage"), lua.LBool(structurePost.IsPage)) | ||
post.RawSet(lua.LString("ispublished"), lua.LBool(structurePost.IsPublished)) | ||
post.RawSet(lua.LString("date"), lua.LNumber(structurePost.Date.Unix())) | ||
post.RawSet(lua.LString("image"), lua.LString(structurePost.Image)) | ||
return post | ||
} | ||
|
||
func convertUser(vm *lua.LState, structureUser *structure.User) *lua.LTable { | ||
user := vm.NewTable() | ||
user.RawSet(lua.LString("id"), lua.LNumber(structureUser.Id)) | ||
user.RawSet(lua.LString("name"), lua.LString(structureUser.Name)) | ||
user.RawSet(lua.LString("slug"), lua.LString(structureUser.Slug)) | ||
user.RawSet(lua.LString("email"), lua.LString(structureUser.Email)) | ||
user.RawSet(lua.LString("image"), lua.LString(structureUser.Image)) | ||
user.RawSet(lua.LString("cover"), lua.LString(structureUser.Cover)) | ||
user.RawSet(lua.LString("bio"), lua.LString(structureUser.Bio)) | ||
user.RawSet(lua.LString("website"), lua.LString(structureUser.Website)) | ||
user.RawSet(lua.LString("location"), lua.LString(structureUser.Location)) | ||
user.RawSet(lua.LString("role"), lua.LNumber(structureUser.Role)) | ||
return user | ||
} | ||
|
||
func convertTags(vm *lua.LState, structureTags []structure.Tag) *lua.LTable { | ||
table := make([]*lua.LTable, 0) | ||
for index, _ := range structureTags { | ||
tag := vm.NewTable() | ||
tag.RawSet(lua.LString("id"), lua.LNumber(structureTags[index].Id)) | ||
tag.RawSet(lua.LString("name"), lua.LString(structureTags[index].Name)) | ||
tag.RawSet(lua.LString("slug"), lua.LString(structureTags[index].Slug)) | ||
table = append(table, tag) | ||
} | ||
return makeTable(vm, table) | ||
} | ||
|
||
func convertBlog(vm *lua.LState, structureBlog *structure.Blog) *lua.LTable { | ||
blog := vm.NewTable() | ||
blog.RawSet(lua.LString("url"), lua.LString(structureBlog.Url)) | ||
blog.RawSet(lua.LString("title"), lua.LString(structureBlog.Title)) | ||
blog.RawSet(lua.LString("description"), lua.LString(structureBlog.Description)) | ||
blog.RawSet(lua.LString("logo"), lua.LString(structureBlog.Logo)) | ||
blog.RawSet(lua.LString("cover"), lua.LString(structureBlog.Cover)) | ||
blog.RawSet(lua.LString("assetpath"), lua.LString(structureBlog.AssetPath)) | ||
blog.RawSet(lua.LString("postcount"), lua.LNumber(structureBlog.PostCount)) | ||
blog.RawSet(lua.LString("postsperpage"), lua.LNumber(structureBlog.PostsPerPage)) | ||
blog.RawSet(lua.LString("activetheme"), lua.LString(structureBlog.ActiveTheme)) | ||
return blog | ||
} | ||
|
||
func makeTable(vm *lua.LState, tables []*lua.LTable) *lua.LTable { | ||
table := vm.NewTable() | ||
for index, _ := range tables { | ||
table.Append(tables[index]) | ||
} | ||
return table | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package plugins | ||
|
||
import ( | ||
"github.com/kabukky/journey/structure" | ||
"github.com/yuin/gopher-lua" | ||
"log" | ||
) | ||
|
||
func Execute(name string, values *structure.RequestData) ([]byte, error) { | ||
// Retrieve the lua state | ||
vm := values.PluginVMs[name] | ||
// Execute plugin | ||
err := vm.CallByParam(lua.P{Fn: vm.GetGlobal(name), NRet: 1, Protect: true}) | ||
if err != nil { | ||
log.Println("Error while executing plugin for helper "+name+":", err) | ||
// Since the vm threw an error, close all vms and don't put the map back into the pool | ||
for _, luavm := range values.PluginVMs { | ||
luavm.Close() | ||
} | ||
values.PluginVMs = nil | ||
return []byte{}, err | ||
} | ||
// Get return value from vm | ||
ret := vm.ToString(-1) | ||
return []byte(ret), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
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{} | ||
absDir, err := filepath.Abs(fileName) | ||
if err != nil { | ||
log.Println("Error while determining absolute path to lua file:", err) | ||
return helperList, err | ||
} | ||
setUpVm(vm, 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, 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 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 | ||
})) | ||
} |
Oops, something went wrong.