mirror of
https://github.com/bbernhard/signal-cli-rest-api.git
synced 2026-07-30 01:19:22 +00:00
230 lines
5.4 KiB
Go
230 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
gluasql "github.com/bbernhard/gluasql"
|
|
"github.com/bbernhard/signal-cli-rest-api/api"
|
|
"github.com/bbernhard/signal-cli-rest-api/utils"
|
|
"github.com/cjoudrey/gluahttp"
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
lua "github.com/yuin/gopher-lua"
|
|
luajson "layeh.com/gopher-json"
|
|
luar "layeh.com/gopher-luar"
|
|
)
|
|
|
|
type PluginInputData struct {
|
|
Params map[string]string
|
|
QueryParams map[string]string
|
|
Payload string
|
|
}
|
|
|
|
type PluginOutputData struct {
|
|
payload string
|
|
httpStatusCode int
|
|
}
|
|
|
|
func (p *PluginOutputData) SetPayload(payload string) {
|
|
p.payload = payload
|
|
}
|
|
|
|
func (p *PluginOutputData) Payload() string {
|
|
return p.payload
|
|
}
|
|
|
|
func (p *PluginOutputData) SetHttpStatusCode(httpStatusCode int) {
|
|
p.httpStatusCode = httpStatusCode
|
|
}
|
|
|
|
func (p *PluginOutputData) HttpStatusCode() int {
|
|
return p.httpStatusCode
|
|
}
|
|
|
|
func execPluginV1(c *gin.Context, pluginConfig utils.PluginConfig) {
|
|
jsonData, err := io.ReadAll(c.Request.Body)
|
|
if err != nil {
|
|
c.JSON(400, api.Error{Msg: "Couldn't process request - invalid input data"})
|
|
log.Error(err.Error())
|
|
return
|
|
}
|
|
|
|
pluginInputData := &PluginInputData{
|
|
Params: make(map[string]string),
|
|
QueryParams: make(map[string]string),
|
|
Payload: string(jsonData),
|
|
}
|
|
|
|
pluginOutputData := &PluginOutputData{
|
|
payload: "",
|
|
httpStatusCode: 200,
|
|
}
|
|
|
|
parts := strings.Split(pluginConfig.Endpoint, "/")
|
|
for _, part := range parts {
|
|
if strings.HasPrefix(part, ":") {
|
|
paramName := strings.TrimPrefix(part, ":")
|
|
pluginInputData.Params[paramName] = c.Param(paramName)
|
|
}
|
|
}
|
|
|
|
queryParams := c.Request.URL.Query()
|
|
for key, values := range queryParams {
|
|
pluginInputData.QueryParams[key] = values[0]
|
|
}
|
|
|
|
l := lua.NewState()
|
|
l.SetGlobal("pluginInputData", luar.New(l, pluginInputData))
|
|
l.SetGlobal("pluginOutputData", luar.New(l, pluginOutputData))
|
|
l.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
|
|
luajson.Preload(l)
|
|
gluasql.Preload(l)
|
|
defer l.Close()
|
|
if err := l.DoFile(pluginConfig.ScriptPath); err != nil {
|
|
log.Error("Error executing lua script: ", err)
|
|
c.JSON(400, api.Error{Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(pluginOutputData.HttpStatusCode(), pluginOutputData.Payload())
|
|
}
|
|
|
|
func execPluginV2(c *gin.Context, pluginConfig utils.PluginConfig) {
|
|
jsonData, err := io.ReadAll(c.Request.Body)
|
|
if err != nil {
|
|
c.JSON(400, api.Error{Msg: "Couldn't process request - invalid input data"})
|
|
log.Error(err.Error())
|
|
return
|
|
}
|
|
|
|
pluginInputData := &PluginInputData{
|
|
Params: make(map[string]string),
|
|
QueryParams: make(map[string]string),
|
|
Payload: string(jsonData),
|
|
}
|
|
|
|
pluginOutputData := &PluginOutputData{
|
|
payload: "",
|
|
httpStatusCode: 200,
|
|
}
|
|
|
|
parts := strings.Split(pluginConfig.Endpoint, "/")
|
|
for _, part := range parts {
|
|
if strings.HasPrefix(part, ":") {
|
|
paramName := strings.TrimPrefix(part, ":")
|
|
pluginInputData.Params[paramName] = c.Param(paramName)
|
|
}
|
|
}
|
|
|
|
queryParams := c.Request.URL.Query()
|
|
for key, values := range queryParams {
|
|
pluginInputData.QueryParams[key] = values[0]
|
|
}
|
|
|
|
l := lua.NewState()
|
|
l.SetGlobal("pluginInputData", luar.New(l, pluginInputData))
|
|
l.SetGlobal("pluginOutputData", luar.New(l, pluginOutputData))
|
|
l.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
|
|
luajson.Preload(l)
|
|
gluasql.Preload(l)
|
|
defer l.Close()
|
|
if err := l.DoFile(pluginConfig.ScriptPath); err != nil {
|
|
log.Error("Error executing lua script: ", err)
|
|
c.JSON(400, api.Error{Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
// Get global "exec"
|
|
lv := l.GetGlobal("exec")
|
|
|
|
// Check if it exists and is a function
|
|
if fn, ok := lv.(*lua.LFunction); ok {
|
|
err := l.CallByParam(lua.P{
|
|
Fn: fn,
|
|
NRet: 1, // exec function returns one value
|
|
Protect: true,
|
|
})
|
|
|
|
if err != nil {
|
|
log.Error("Couldn't execute plugin: ", err.Error())
|
|
c.JSON(400, "Couldn't execute plugin: "+err.Error())
|
|
return
|
|
}
|
|
|
|
ret := l.Get(-1)
|
|
l.Pop(1)
|
|
|
|
if ret != lua.LNil {
|
|
log.Error("Couldn't execute plugin")
|
|
c.JSON(400, "Couldn't execute plugin")
|
|
}
|
|
c.Data(
|
|
pluginOutputData.HttpStatusCode(),
|
|
"application/json",
|
|
[]byte(pluginOutputData.Payload()),
|
|
)
|
|
} else {
|
|
log.Error("Couldn't execute plugin. No exec function implemented!")
|
|
c.JSON(400, "Couldn't execute plugin. No exec function implemented!")
|
|
}
|
|
}
|
|
|
|
type plugHandler struct {
|
|
}
|
|
|
|
func (p plugHandler) ExecutePlugin(pluginConfig utils.PluginConfig) gin.HandlerFunc {
|
|
fn := func(c *gin.Context) {
|
|
if pluginConfig.Version == 1 {
|
|
execPluginV1(c, pluginConfig)
|
|
} else {
|
|
execPluginV2(c, pluginConfig)
|
|
}
|
|
}
|
|
|
|
return gin.HandlerFunc(fn)
|
|
}
|
|
|
|
func (p plugHandler) InitPlugin(pluginConfig utils.PluginConfig) error {
|
|
l := lua.NewState()
|
|
l.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
|
|
luajson.Preload(l)
|
|
gluasql.Preload(l)
|
|
defer l.Close()
|
|
err := l.DoFile(pluginConfig.ScriptPath)
|
|
if err != nil {
|
|
log.Error("Error executing lua script: ", err)
|
|
}
|
|
|
|
// Get global "init"
|
|
lv := l.GetGlobal("init")
|
|
|
|
// Check if it exists and is a function
|
|
if fn, ok := lv.(*lua.LFunction); ok {
|
|
err := l.CallByParam(lua.P{
|
|
Fn: fn,
|
|
NRet: 2, // init function returns two values
|
|
Protect: true,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_ = l.Get(-2)
|
|
errVal := l.Get(-1)
|
|
l.Pop(2)
|
|
|
|
if errVal != lua.LNil {
|
|
return errors.New("Couldn't initialize lua script: " + errVal.String())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// exported
|
|
var PluginHandler plugHandler
|