You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
6.2 KiB
294 lines
6.2 KiB
/*
|
|
* Copyright 2020-2021 the original author(https://github.com/wj596)
|
|
*
|
|
* <p>
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
* </p>
|
|
*/
|
|
package luaengine
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sync"
|
|
|
|
luaJson "github.com/layeh/gopher-json"
|
|
"github.com/siddontang/go-mysql/canal"
|
|
"github.com/yuin/gopher-lua"
|
|
|
|
"go-mysql-transfer/util/byteutil"
|
|
"go-mysql-transfer/util/httpclient"
|
|
"go-mysql-transfer/util/stringutil"
|
|
)
|
|
|
|
const (
|
|
_globalRET = "___RET___"
|
|
_globalROW = "___ROW___"
|
|
_globalACT = "___ACT___"
|
|
)
|
|
|
|
var (
|
|
_pool *luaStatePool
|
|
_ds *canal.Canal
|
|
|
|
_httpClient *httpclient.HttpClient
|
|
)
|
|
|
|
type luaStatePool struct {
|
|
lock sync.Mutex
|
|
saved []*lua.LState
|
|
}
|
|
|
|
func InitActuator(ds *canal.Canal) {
|
|
_ds = ds
|
|
_pool = &luaStatePool{
|
|
saved: make([]*lua.LState, 0, 3),
|
|
}
|
|
}
|
|
|
|
func (p *luaStatePool) Get() *lua.LState {
|
|
p.lock.Lock()
|
|
defer p.lock.Unlock()
|
|
|
|
n := len(p.saved)
|
|
if n == 0 {
|
|
return p.New()
|
|
}
|
|
x := p.saved[n-1]
|
|
p.saved = p.saved[0 : n-1]
|
|
return x
|
|
}
|
|
|
|
func (p *luaStatePool) New() *lua.LState {
|
|
_httpClient = httpclient.NewClient()
|
|
|
|
L := lua.NewState()
|
|
|
|
luaJson.Preload(L)
|
|
|
|
L.PreloadModule("scriptOps", scriptModule)
|
|
L.PreloadModule("dbOps", dbModule)
|
|
L.PreloadModule("httpOps", httpModule)
|
|
|
|
L.PreloadModule("redisOps", redisModule)
|
|
L.PreloadModule("mqOps", mqModule)
|
|
L.PreloadModule("mongodbOps", mongoModule)
|
|
L.PreloadModule("esOps", esModule)
|
|
|
|
return L
|
|
}
|
|
|
|
func (p *luaStatePool) Put(L *lua.LState) {
|
|
p.lock.Lock()
|
|
defer p.lock.Unlock()
|
|
|
|
p.saved = append(p.saved, L)
|
|
}
|
|
|
|
func (p *luaStatePool) Shutdown() {
|
|
for _, L := range p.saved {
|
|
L.Close()
|
|
}
|
|
}
|
|
|
|
func rawRow(L *lua.LState) int {
|
|
row := L.GetGlobal(_globalROW)
|
|
L.Push(row)
|
|
return 1
|
|
}
|
|
|
|
func rawAction(L *lua.LState) int {
|
|
act := L.GetGlobal(_globalACT)
|
|
L.Push(act)
|
|
return 1
|
|
}
|
|
|
|
func paddingTable(l *lua.LState, table *lua.LTable, kv map[string]interface{}) {
|
|
for k, v := range kv {
|
|
switch v.(type) {
|
|
case float64:
|
|
ft := v.(float64)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case float32:
|
|
ft := v.(float32)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case int:
|
|
ft := v.(int)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case uint:
|
|
ft := v.(uint)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case int8:
|
|
ft := v.(int8)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case uint8:
|
|
ft := v.(uint8)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case int16:
|
|
ft := v.(int16)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case uint16:
|
|
ft := v.(uint16)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case int32:
|
|
ft := v.(int32)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case uint32:
|
|
ft := v.(uint32)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case int64:
|
|
ft := v.(int64)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case uint64:
|
|
ft := v.(uint64)
|
|
l.SetTable(table, lua.LString(k), lua.LNumber(ft))
|
|
case string:
|
|
ft := v.(string)
|
|
l.SetTable(table, lua.LString(k), lua.LString(ft))
|
|
case []byte:
|
|
ft := string(v.([]byte))
|
|
l.SetTable(table, lua.LString(k), lua.LString(ft))
|
|
case nil:
|
|
l.SetTable(table, lua.LString(k), lua.LNil)
|
|
default:
|
|
jsonValue, _ := json.Marshal(v)
|
|
l.SetTable(table, lua.LString(k), lua.LString(jsonValue))
|
|
}
|
|
}
|
|
}
|
|
|
|
func lvToString(lv lua.LValue) string {
|
|
if lua.LVCanConvToString(lv) {
|
|
return lua.LVAsString(lv)
|
|
}
|
|
|
|
return lv.String()
|
|
}
|
|
|
|
func lvToByteArray(lv lua.LValue) []byte {
|
|
switch lv.Type() {
|
|
case lua.LTNil:
|
|
return nil
|
|
case lua.LTBool:
|
|
return byteutil.JsonBytes(lua.LVAsBool(lv))
|
|
case lua.LTNumber:
|
|
return []byte(lv.String())
|
|
case lua.LTString:
|
|
return []byte(lua.LVAsString(lv))
|
|
case lua.LTTable:
|
|
ret := lvToInterface(lv, false)
|
|
return byteutil.JsonBytes(ret)
|
|
default:
|
|
return byteutil.JsonBytes(lv)
|
|
}
|
|
}
|
|
|
|
func lvToInterface(lv lua.LValue, tableToJson bool) interface{} {
|
|
switch lv.Type() {
|
|
case lua.LTNil:
|
|
return nil
|
|
case lua.LTBool:
|
|
return lua.LVAsBool(lv)
|
|
case lua.LTNumber:
|
|
return float64(lua.LVAsNumber(lv))
|
|
case lua.LTString:
|
|
return lua.LVAsString(lv)
|
|
case lua.LTTable:
|
|
t, _ := lv.(*lua.LTable)
|
|
len := t.MaxN()
|
|
if len == 0 { // table
|
|
ret := make(map[string]interface{})
|
|
t.ForEach(func(key, value lua.LValue) {
|
|
ret[lvToString(key)] = lvToInterface(value, false)
|
|
})
|
|
if tableToJson {
|
|
return stringutil.ToJsonString(ret)
|
|
}
|
|
return ret
|
|
} else { // array
|
|
ret := make([]interface{}, 0, len)
|
|
for i := 1; i <= len; i++ {
|
|
ret = append(ret, lvToInterface(t.RawGetInt(i), false))
|
|
}
|
|
if tableToJson {
|
|
return stringutil.ToJsonString(ret)
|
|
}
|
|
return ret
|
|
}
|
|
default:
|
|
return lv
|
|
}
|
|
}
|
|
|
|
func lvToMap(lv lua.LValue) (map[string]interface{}, bool) {
|
|
switch lv.Type() {
|
|
case lua.LTTable:
|
|
t := lvToInterface(lv, false)
|
|
ret := t.(map[string]interface{})
|
|
return ret, true
|
|
default:
|
|
return nil, false
|
|
}
|
|
}
|
|
|
|
func interfaceToLv(v interface{}) lua.LValue {
|
|
switch v.(type) {
|
|
case float64:
|
|
ft := v.(float64)
|
|
return lua.LNumber(ft)
|
|
case float32:
|
|
ft := v.(float32)
|
|
return lua.LNumber(ft)
|
|
case int:
|
|
ft := v.(int)
|
|
return lua.LNumber(ft)
|
|
case uint:
|
|
ft := v.(uint)
|
|
return lua.LNumber(ft)
|
|
case int8:
|
|
ft := v.(int8)
|
|
return lua.LNumber(ft)
|
|
case uint8:
|
|
ft := v.(uint8)
|
|
return lua.LNumber(ft)
|
|
case int16:
|
|
ft := v.(int16)
|
|
return lua.LNumber(ft)
|
|
case uint16:
|
|
ft := v.(uint16)
|
|
return lua.LNumber(ft)
|
|
case int32:
|
|
ft := v.(int32)
|
|
return lua.LNumber(ft)
|
|
case uint32:
|
|
ft := v.(uint32)
|
|
return lua.LNumber(ft)
|
|
case int64:
|
|
ft := v.(int64)
|
|
return lua.LNumber(ft)
|
|
case uint64:
|
|
ft := v.(uint64)
|
|
return lua.LNumber(ft)
|
|
case string:
|
|
ft := v.(string)
|
|
return lua.LString(ft)
|
|
case []byte:
|
|
ft := string(v.([]byte))
|
|
return lua.LString(ft)
|
|
case nil:
|
|
return lua.LNil
|
|
default:
|
|
jsonValue, _ := json.Marshal(v)
|
|
return lua.LString(jsonValue)
|
|
}
|
|
|
|
}
|
|
|