diff --git a/.gitignore b/.gitignore index 66fd13c..2ac7c1c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,9 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +go.sum + +.idea + # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/constDef.go b/constDef.go new file mode 100644 index 0000000..ab4623e --- /dev/null +++ b/constDef.go @@ -0,0 +1,13 @@ +package luaInGo + +import lua "github.com/yuin/gopher-lua" + +const ( + InitPoolSize = 128 + NaxPoolSize = 512 +) + +//初始化lua LState连接池 +var LuaStatePool = &lStatePool{ + saved: make([]*lua.LState, 0, InitPoolSize), +} diff --git a/file_util.go b/file_util.go new file mode 100644 index 0000000..2167280 --- /dev/null +++ b/file_util.go @@ -0,0 +1,75 @@ +package luaInGo + +import ( + "fmt" + "io/ioutil" + "os" + "path" +) + +// LuaFile lua文件 +type LuaFile struct { + FileName string +} + +// LuaFileExist 判断某lua脚本是否存在 +func LuaFileExist(fileName string) bool { + fileList := GetAllLuaFile() + for _, file := range fileList { + if file.FileName == fileName { + return true + } + } + return false +} + +// GetAllLuaFile 获取所有文件 +func GetAllLuaFile() []LuaFile { + // 声明一个文件列表切片 + var fileList []LuaFile + rd, err := ioutil.ReadDir("luafile") + if err != nil { + fmt.Println("GetAllLuaFile error", err) + return fileList + } + + for _, fi := range rd { + fileList = append(fileList, LuaFile{fi.Name()}) + } + return fileList +} + +// DeleteLuaFile 删除文件 +func DeleteLuaFile(fileName string) bool { + err := os.Remove("luafile/" + fileName) + if err != nil { + fmt.Println("DeleteLuaFile error", err) + return false + } + return true +} + +func ListLuaFile(folder string, luas []string) { + files, _ := ioutil.ReadDir(folder) + for _, file := range files { + if file.IsDir() { + ListLuaFile(folder+"/"+file.Name(), luas) + } else { + var filenameWithSuffix string = path.Base(file.Name()) //获取文件名带后缀 + var fileSuffix string = path.Ext(filenameWithSuffix) //获取文件后缀 + if fileSuffix == ".lua" { + filePath := fmt.Sprintf("%s%s%s", folder, "/", file.Name()) + luas = append(luas, filePath) + } + } + } +} + +func GetFileModtime(file string) (int64, error) { + stat, err := os.Stat(file) + if err != nil { + fmt.Printf("stat fail, file=%v err=%v", file, err) + return 0, err + } + return stat.ModTime().Unix(), nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..113315d --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module luaInGo + +go 1.14 + +require ( + github.com/vadv/gopher-lua-libs v0.1.0 + github.com/yuin/gopher-lua v0.0.0-20200603152657-dc2b0ca8b37e +) diff --git a/goApis/crypto/README.md b/goApis/crypto/README.md new file mode 100644 index 0000000..5bf5011 --- /dev/null +++ b/goApis/crypto/README.md @@ -0,0 +1,18 @@ +## Usage + +origin code: https://github.com/vadv/gopher-lua-libs/tree/master/crypto + +```lua +local crypto = require("crypto") + +-- md5 +if not(crypto.md5("1\n") == "b026324c6904b2a9cb4b88d6d61c81d1") then + error("md5") +end + +-- sha256 +if not(crypto.sha256("1\n") == "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865") then + error("sha256") +end +``` + diff --git a/goApis/crypto/api.go b/goApis/crypto/api.go new file mode 100644 index 0000000..1d515f4 --- /dev/null +++ b/goApis/crypto/api.go @@ -0,0 +1,23 @@ +package crypto + +import ( + "crypto/md5" + "crypto/sha256" + "fmt" + + lua "github.com/yuin/gopher-lua" +) + +func MD5(L *lua.LState) int { + str := L.CheckString(1) + hash := md5.Sum([]byte(str)) + L.Push(lua.LString(fmt.Sprintf("%x", hash))) + return 1 +} + +func SHA256(L *lua.LState) int { + str := L.CheckString(1) + hash := sha256.Sum256([]byte(str)) + L.Push(lua.LString(fmt.Sprintf("%x", hash))) + return 1 +} diff --git a/goApis/crypto/api_test.go b/goApis/crypto/api_test.go new file mode 100644 index 0000000..1e0e0cd --- /dev/null +++ b/goApis/crypto/api_test.go @@ -0,0 +1,20 @@ +package crypto + +import ( + "io/ioutil" + "testing" + + lua "github.com/yuin/gopher-lua" +) + +func TestApi(t *testing.T) { + data, err := ioutil.ReadFile("../testScript/test_crypto_api.lua") + if err != nil { + t.Fatalf("%s\n", err.Error()) + } + state := lua.NewState() + PreLoadGo(state) + if err := state.DoString(string(data)); err != nil { + t.Fatalf("execute test: %s\n", err.Error()) + } +} diff --git a/goApis/crypto/loader.go b/goApis/crypto/loader.go new file mode 100644 index 0000000..96f443c --- /dev/null +++ b/goApis/crypto/loader.go @@ -0,0 +1,21 @@ +package crypto + +import ( + lua "github.com/yuin/gopher-lua" +) + +func PreLoadGo(L *lua.LState) { + L.PreloadModule("crypto", Loader) +} + +func Loader(L *lua.LState) int { + t := L.NewTable() + L.SetFuncs(t, api) + L.Push(t) + return 1 +} + +var api = map[string]lua.LGFunction{ + "md5": MD5, + "sha256": SHA256, +} diff --git a/goApis/goApilibs.go b/goApis/goApilibs.go new file mode 100644 index 0000000..a573646 --- /dev/null +++ b/goApis/goApilibs.go @@ -0,0 +1,70 @@ +package goApis + +import ( + lua "github.com/yuin/gopher-lua" + + cloudwatch "github.com/vadv/gopher-lua-libs/aws/cloudwatch" + cert_util "github.com/vadv/gopher-lua-libs/cert_util" + chef "github.com/vadv/gopher-lua-libs/chef" + cmd "github.com/vadv/gopher-lua-libs/cmd" + crypto "github.com/vadv/gopher-lua-libs/crypto" + db "github.com/vadv/gopher-lua-libs/db" + filepath "github.com/vadv/gopher-lua-libs/filepath" + goos "github.com/vadv/gopher-lua-libs/goos" + http "github.com/vadv/gopher-lua-libs/http" + humanize "github.com/vadv/gopher-lua-libs/humanize" + inspect "github.com/vadv/gopher-lua-libs/inspect" + ioutil "github.com/vadv/gopher-lua-libs/ioutil" + json "github.com/vadv/gopher-lua-libs/json" + log "github.com/vadv/gopher-lua-libs/log" + plugin "github.com/vadv/gopher-lua-libs/plugin" + pprof "github.com/vadv/gopher-lua-libs/pprof" + prometheus "github.com/vadv/gopher-lua-libs/prometheus/client" + regexp "github.com/vadv/gopher-lua-libs/regexp" + runtime "github.com/vadv/gopher-lua-libs/runtime" + "github.com/vadv/gopher-lua-libs/stats" + storage "github.com/vadv/gopher-lua-libs/storage" + strings "github.com/vadv/gopher-lua-libs/strings" + tac "github.com/vadv/gopher-lua-libs/tac" + tcp "github.com/vadv/gopher-lua-libs/tcp" + telegram "github.com/vadv/gopher-lua-libs/telegram" + template "github.com/vadv/gopher-lua-libs/template" + time "github.com/vadv/gopher-lua-libs/time" + xmlpath "github.com/vadv/gopher-lua-libs/xmlpath" + yaml "github.com/vadv/gopher-lua-libs/yaml" + zabbix "github.com/vadv/gopher-lua-libs/zabbix" +) + +// 这里封装一个函数 统一load go中提供给lua调用的函数 +func PreLoadLibs(L *lua.LState) { + time.Preload(L) + strings.Preload(L) + filepath.Preload(L) + ioutil.Preload(L) + http.Preload(L) + regexp.Preload(L) + tac.Preload(L) + inspect.Preload(L) + yaml.Preload(L) + plugin.Preload(L) + cmd.Preload(L) + json.Preload(L) + tcp.Preload(L) + xmlpath.Preload(L) + db.Preload(L) + cert_util.Preload(L) + runtime.Preload(L) + telegram.Preload(L) + zabbix.Preload(L) + pprof.Preload(L) + prometheus.Preload(L) + crypto.Preload(L) + goos.Preload(L) + storage.Preload(L) + humanize.Preload(L) + chef.Preload(L) + template.Preload(L) + cloudwatch.Preload(L) + log.Preload(L) + stats.Preload(L) +} diff --git a/goApis/json/README.md b/goApis/json/README.md new file mode 100644 index 0000000..6ac7d29 --- /dev/null +++ b/goApis/json/README.md @@ -0,0 +1,23 @@ +# json + + origin code: https://github.com/vadv/gopher-lua-libs/tree/master/json + +## Usage + +```lua +local json = require("json") + +-- json.encode() +local jsonString = [[ + { + "a": {"b":1} + } +]] +local result, err = json.decode(jsonString) +if err then error(err) end + +-- json.decode() +local table = {a={b=1}} +local result, err = json.encode(table) +if err then error(err) end +``` diff --git a/goApis/json/api.go b/goApis/json/api.go new file mode 100644 index 0000000..c363fdc --- /dev/null +++ b/goApis/json/api.go @@ -0,0 +1,31 @@ +package json + +import ( + lua "github.com/yuin/gopher-lua" +) + +func Decode(L *lua.LState) int { + str := L.CheckString(1) + + value, err := ValueDecode(L, []byte(str)) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString(err.Error())) + return 2 + } + L.Push(value) + return 1 +} + +func Encode(L *lua.LState) int { + value := L.CheckAny(1) + + data, err := ValueEncode(value) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString(err.Error())) + return 2 + } + L.Push(lua.LString(string(data))) + return 1 +} diff --git a/goApis/json/api_test.go b/goApis/json/api_test.go new file mode 100644 index 0000000..ceab9a1 --- /dev/null +++ b/goApis/json/api_test.go @@ -0,0 +1,15 @@ +package json + +import ( + "testing" + + lua "github.com/yuin/gopher-lua" +) + +func TestApi(t *testing.T) { + state := lua.NewState() + PreloadGo(state) + if err := state.DoFile("../testScript/test_json_api.lua"); err != nil { + t.Fatalf("execute test: %s\n", err.Error()) + } +} diff --git a/goApis/json/loader.go b/goApis/json/loader.go new file mode 100644 index 0000000..fbdb494 --- /dev/null +++ b/goApis/json/loader.go @@ -0,0 +1,21 @@ +package json + +import ( + lua "github.com/yuin/gopher-lua" +) + +func PreloadGo(L *lua.LState) { + L.PreloadModule("json", Loader) +} + +func Loader(L *lua.LState) int { + t := L.NewTable() + L.SetFuncs(t, api) + L.Push(t) + return 1 +} + +var api = map[string]lua.LGFunction{ + "decode": Decode, + "encode": Encode, +} diff --git a/goApis/json/value.go b/goApis/json/value.go new file mode 100644 index 0000000..657b8cb --- /dev/null +++ b/goApis/json/value.go @@ -0,0 +1,127 @@ +package json + +import ( + "encoding/json" + "errors" + + lua "github.com/yuin/gopher-lua" +) + +var ( + errNested = errors.New("cannot encode recursively nested tables to JSON") + errSparseArray = errors.New("cannot encode sparse array") + errInvalidKeys = errors.New("cannot encode mixed or invalid key types") +) + +type invalidTypeError lua.LValueType + +func (i invalidTypeError) Error() string { + return `cannot encode ` + lua.LValueType(i).String() + ` to JSON` +} + +type jsonValue struct { + lua.LValue + visited map[*lua.LTable]bool +} + +func (j jsonValue) MarshalJSON() (data []byte, err error) { + switch converted := j.LValue.(type) { + case lua.LBool: + data, err = json.Marshal(bool(converted)) + case lua.LNumber: + data, err = json.Marshal(float64(converted)) + case *lua.LNilType: + data = []byte(`null`) + case lua.LString: + data, err = json.Marshal(string(converted)) + case *lua.LTable: + if j.visited[converted] { + return nil, errNested + } + j.visited[converted] = true + + key, value := converted.Next(lua.LNil) + + switch key.Type() { + case lua.LTNil: // empty table + data = []byte(`[]`) + case lua.LTNumber: + arr := make([]jsonValue, 0, converted.Len()) + expectedKey := lua.LNumber(1) + for key != lua.LNil { + if key.Type() != lua.LTNumber { + err = errInvalidKeys + return + } + if expectedKey != key { + err = errSparseArray + return + } + arr = append(arr, jsonValue{value, j.visited}) + expectedKey++ + key, value = converted.Next(key) + } + data, err = json.Marshal(arr) + case lua.LTString: + obj := make(map[string]jsonValue) + for key != lua.LNil { + if key.Type() != lua.LTString { + err = errInvalidKeys + return + } + obj[key.String()] = jsonValue{value, j.visited} + key, value = converted.Next(key) + } + data, err = json.Marshal(obj) + default: + err = errInvalidKeys + } + default: + err = invalidTypeError(j.LValue.Type()) + } + return +} + +// ValueDecode converts the JSON encoded data to Lua values. +func ValueDecode(L *lua.LState, data []byte) (lua.LValue, error) { + var value interface{} + err := json.Unmarshal(data, &value) + if err != nil { + return nil, err + } + return decode(L, value), nil +} + +func decode(L *lua.LState, value interface{}) lua.LValue { + switch converted := value.(type) { + case bool: + return lua.LBool(converted) + case float64: + return lua.LNumber(converted) + case string: + return lua.LString(converted) + case []interface{}: + arr := L.CreateTable(len(converted), 0) + for _, item := range converted { + arr.Append(decode(L, item)) + } + return arr + case map[string]interface{}: + tbl := L.CreateTable(0, len(converted)) + for key, item := range converted { + tbl.RawSetH(lua.LString(key), decode(L, item)) + } + return tbl + case nil: + return lua.LNil + } + panic("unreachable") +} + +// ValueEncode returns the JSON encoding of value. +func ValueEncode(value lua.LValue) ([]byte, error) { + return json.Marshal(jsonValue{ + LValue: value, + visited: make(map[*lua.LTable]bool), + }) +} diff --git a/goApis/strings/README.md b/goApis/strings/README.md new file mode 100644 index 0000000..85cf897 --- /dev/null +++ b/goApis/strings/README.md @@ -0,0 +1,30 @@ +# strings + +origin code: https://github.com/vadv/gopher-lua-libs/tree/master/strings + +## Usage + +```lua +local strings = require("strings") + +-- strings.split(string, sep) +local result = strings.split("a b c d", " ") +-- Output: { "a", "b", "c", "d" } + +-- strings.has_prefix(string, prefix) +local result = strings.has_prefix("abcd", "a") +-- Output: true + +-- strings.has_suffix(string, suffix) +local result = strings.has_suffix("abcd", "d") +-- Output: true + +-- strings.trim(string, cutset) +local result = strings.trim("abcd", "d") +-- Output: abc + +-- strings.contains(string, substring) +local result = strings.contains("abcd", "d") +-- Output: true +``` + diff --git a/goApis/strings/api.go b/goApis/strings/api.go new file mode 100644 index 0000000..10d4436 --- /dev/null +++ b/goApis/strings/api.go @@ -0,0 +1,74 @@ +package strings + +import ( + "strings" + + lua "github.com/yuin/gopher-lua" +) + +// Split(): lua strings.split(string, sep): port of go string.Split() returns table +func Split(L *lua.LState) int { + str := L.CheckString(1) + delim := L.CheckString(2) + strSlice := strings.Split(str, delim) + result := L.CreateTable(len(strSlice), 0) + for _, str := range strSlice { + result.Append(lua.LString(str)) + } + L.Push(result) + return 1 +} + +// HasPrefix(): lua strings.has_prefix(string, suffix): port of go string.HasPrefix() return bool +func HasPrefix(L *lua.LState) int { + str1 := L.CheckString(1) + str2 := L.CheckString(2) + result := strings.HasPrefix(str1, str2) + L.Push(lua.LBool(result)) + return 1 +} + +// HasSuffix(): lua strings.has_suffix(string, prefix): port of go string.HasSuffix() returns bool +func HasSuffix(L *lua.LState) int { + str1 := L.CheckString(1) + str2 := L.CheckString(2) + result := strings.HasSuffix(str1, str2) + L.Push(lua.LBool(result)) + return 1 +} + +// Trim(): lua strings.trim(string, cutset) Port of go string.Trim() returns string +func Trim(L *lua.LState) int { + str1 := L.CheckString(1) + str2 := L.CheckString(2) + result := strings.Trim(str1, str2) + L.Push(lua.LString(result)) + return 1 +} + +// TrimPrefix(): lua strings.trim_prefix(string, cutset) Port of go string.TrimPrefix() returns string +func TrimPrefix(L *lua.LState) int { + str1 := L.CheckString(1) + str2 := L.CheckString(2) + result := strings.TrimPrefix(str1, str2) + L.Push(lua.LString(result)) + return 1 +} + +// TrimSuffix(): lua strings.trim_suffix(string, cutset) Port of go string.TrimSuffix() returns string +func TrimSuffix(L *lua.LState) int { + str1 := L.CheckString(1) + str2 := L.CheckString(2) + result := strings.TrimSuffix(str1, str2) + L.Push(lua.LString(result)) + return 1 +} + +// Contains(): lua strings.contains(string, cutset) Port of go string.Contains() returns bool +func Contains(L *lua.LState) int { + str1 := L.CheckString(1) + str2 := L.CheckString(2) + result := strings.Contains(str1, str2) + L.Push(lua.LBool(result)) + return 1 +} diff --git a/goApis/strings/api_test.go b/goApis/strings/api_test.go new file mode 100644 index 0000000..f95fded --- /dev/null +++ b/goApis/strings/api_test.go @@ -0,0 +1,15 @@ +package strings + +import ( + "testing" + + lua "github.com/yuin/gopher-lua" +) + +func TestApi(t *testing.T) { + state := lua.NewState() + PreLoadGo(state) + if err := state.DoFile("../testScript/test_strings_api.lua"); err != nil { + t.Fatalf("execute test: %s\n", err.Error()) + } +} diff --git a/goApis/strings/loader.go b/goApis/strings/loader.go new file mode 100644 index 0000000..35a97ba --- /dev/null +++ b/goApis/strings/loader.go @@ -0,0 +1,26 @@ +package strings + +import ( + lua "github.com/yuin/gopher-lua" +) + +func PreLoadGo(L *lua.LState) { + L.PreloadModule("strings", Loader) +} + +func Loader(L *lua.LState) int { + t := L.NewTable() + L.SetFuncs(t, api) + L.Push(t) + return 1 +} + +var api = map[string]lua.LGFunction{ + "split": Split, + "trim": Trim, + "trim_prefix": TrimPrefix, + "trim_suffix": TrimSuffix, + "has_prefix": HasPrefix, + "has_suffix": HasSuffix, + "contains": Contains, +} diff --git a/goApis/testScript/test_crypto_api.lua b/goApis/testScript/test_crypto_api.lua new file mode 100644 index 0000000..7a214fa --- /dev/null +++ b/goApis/testScript/test_crypto_api.lua @@ -0,0 +1,4 @@ +local crypto = require("crypto") + +if not(crypto.md5("1\n") == "b026324c6904b2a9cb4b88d6d61c81d1") then error("md5") end +if not(crypto.sha256("1\n") == "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865") then error("sha256") end diff --git a/goApis/testScript/test_json_api.lua b/goApis/testScript/test_json_api.lua new file mode 100644 index 0000000..cb38f09 --- /dev/null +++ b/goApis/testScript/test_json_api.lua @@ -0,0 +1,14 @@ +local json = require("json") + +local jsonStringWithNull = [[{"a":{"b":1, "c":null}}]] +local jsonString = [[{"a":{"b":1}}]] + +local result, err = json.decode(jsonStringWithNull) +if err then error(err) end +if not(result["a"]["b"] == 1) then error("must be decode") end +print("done: json.decode()") + +local result, err = json.encode(result) +if err then error(err) end +if not(result==jsonString) then error("must be encode "..result) end +print("done: json.encode()") diff --git a/goApis/testScript/test_strings_api.lua b/goApis/testScript/test_strings_api.lua new file mode 100644 index 0000000..8b85188 --- /dev/null +++ b/goApis/testScript/test_strings_api.lua @@ -0,0 +1,26 @@ +local strings = require("strings") + +local str = "hello world" + +local t = strings.split(str, " ") +local count_t = 0 +for k, v in pairs(t) do + count_t = count_t + 1 + if k == 1 then if not(v == "hello") then error("strings.split()") end end + if k == 2 then if not(v == "world") then error("strings.split()") end end +end +if not(count_t == 2) then error("string.split()") end +print("done: strings.split()") + +if not(strings.has_prefix(str, "hello")) then error("strings.has_prefix()") end +if not(strings.has_suffix(str, "world")) then error("strings.has_suffix()") end +print("done: strings.has_suffix, strings.has_prefix") + +if not(strings.trim(str, "world") == "hello ") then error("strings.trim()") end +if not(strings.trim(str, "hello ") == "world") then error("strings.trim()") end +if not(strings.trim_prefix(str, "hello ") == "world") then error("strings.trim()") end +if not(strings.trim_suffix(str, "hello ") == "hello world") then error("strings.trim()") end +print("done: strings.trim()") + +if not(strings.contains(str, "hello ") == true) then error("strings.contains()") end +print("done: strings.contains()") diff --git a/goApis/testScript/test_time_api.lua b/goApis/testScript/test_time_api.lua new file mode 100644 index 0000000..202dbc5 --- /dev/null +++ b/goApis/testScript/test_time_api.lua @@ -0,0 +1,24 @@ +local time = require("time") + +local lua_before = os.clock() +local before = time.unix() +time.sleep(2) +local after = time.unix() +local lua_after = os.clock() +if after - before < 1 then error("time.unix()") end +if lua_after - lua_before < 2 then error("time.sleep()") end +print("done: time.sleep(), time.unix()") + +local parse, err = time.parse("Dec 2 03:33:05 2018", "Jan 2 15:04:05 2006") +if err then error(err) end +if not(parse == 1543721585) then error("time.parse(): 1") end +print("done: time.parse(): 1") + +local _, err = time.parse("Dec 32 03:33:05 2018", "Jan 2 15:04:05 2006") +if (err == nil) then error("time.parse(): must be error") end +print("done: time.parse(): 2") + +local result, err = time.format(1543721585, "Jan 2 15:04:05 2006", "Europe/Moscow") +if err then error(err) end +if not(result == "Dec 2 06:33:05 2018") then error("time.format()") end +print("done: time.format(): 1") diff --git a/goApis/time/README.md b/goApis/time/README.md new file mode 100644 index 0000000..be57e7d --- /dev/null +++ b/goApis/time/README.md @@ -0,0 +1,28 @@ +# time + +origin code: https://github.com/vadv/gopher-lua-libs/tree/master/time + +## Usage + +```lua +local time = require("time") + +-- time.unix(), time.sleep() +local begin = time.unix() +time.sleep(1.2) +local stop = time.unix() +local result = stop - begin +result = math.floor(result * 10^2 + 0.5) / 10^2 +if not(result == 1) then error("time.sleep()") end + +-- time.parse(value, layout) +local result, err = time.parse("Dec 2 03:33:05 2018", "Jan 2 15:04:05 2006") +if err then error(err) end +if not(result == 1543721585) then error("time.parse()") end + +-- time.format(value, layout, location) +local result, err = time.format(1543721585, "Jan 2 15:04:05 2006", "Europe/Moscow") +if err then error(err) end +if not(result == "Dec 2 06:33:05 2018") then error("time.format()") end +``` + diff --git a/goApis/time/api.go b/goApis/time/api.go new file mode 100644 index 0000000..7930a0f --- /dev/null +++ b/goApis/time/api.go @@ -0,0 +1,62 @@ +package time + +import ( + "time" + + lua "github.com/yuin/gopher-lua" +) + +func Unix(L *lua.LState) int { + now := float64(time.Now().UnixNano()) / float64(time.Second) + L.Push(lua.LNumber(now)) + return 1 +} + +func UnixNano(L *lua.LState) int { + L.Push(lua.LNumber(time.Now().UnixNano())) + return 1 +} + +func Sleep(L *lua.LState) int { + val := L.CheckNumber(1) + time.Sleep(time.Duration(val) * time.Second) + return 0 +} + +func Parse(L *lua.LState) int { + layout, value := L.CheckString(2), L.CheckString(1) + result, err := time.Parse(layout, value) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString(err.Error())) + return 2 + } + resultFloat := float64(result.UTC().UnixNano()) / float64(time.Second) + L.Push(lua.LNumber(resultFloat)) + return 1 +} + +func Format(L *lua.LState) int { + tt := float64(L.CheckNumber(1)) + sec := int64(tt) + nsec := int64((tt - float64(sec)) * 1000000000) + result := time.Unix(sec, nsec) + layout := "Mon Jan 2 15:04:05 -0700 MST 2006" + if L.GetTop() > 1 { + layout = L.CheckString(2) + } + if L.GetTop() < 3 { + L.Push(lua.LString(result.Format(layout))) + return 1 + } + location := L.CheckString(3) + loc, err := time.LoadLocation(location) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString(err.Error())) + return 2 + } + result = result.In(loc) + L.Push(lua.LString(result.Format(layout))) + return 1 +} diff --git a/goApis/time/api_test.go b/goApis/time/api_test.go new file mode 100644 index 0000000..0196a35 --- /dev/null +++ b/goApis/time/api_test.go @@ -0,0 +1,15 @@ +package time + +import ( + "testing" + + lua "github.com/yuin/gopher-lua" +) + +func TestApi(t *testing.T) { + state := lua.NewState() + PreLoadGo(state) + if err := state.DoFile("../testScript/test_time_api.lua"); err != nil { + t.Fatalf("execute test: %s\n", err.Error()) + } +} diff --git a/goApis/time/loader.go b/goApis/time/loader.go new file mode 100644 index 0000000..5da7b77 --- /dev/null +++ b/goApis/time/loader.go @@ -0,0 +1,24 @@ +package time + +import ( + lua "github.com/yuin/gopher-lua" +) + +func PreLoadGo(L *lua.LState) { + L.PreloadModule("time", Loader) +} + +func Loader(L *lua.LState) int { + t := L.NewTable() + L.SetFuncs(t, api) + L.Push(t) + return 1 +} + +var api = map[string]lua.LGFunction{ + "unix": Unix, + "unix_nano": UnixNano, + "sleep": Sleep, + "parse": Parse, + "format": Format, +} diff --git a/hotfix.go b/hotfix.go new file mode 100644 index 0000000..97b1eeb --- /dev/null +++ b/hotfix.go @@ -0,0 +1,199 @@ +package luaInGo + +// import ( +// "context" +// "sync" +// "sync/atomic" +// "time" +// +// log "github.com/iglev/ilog" +// ) +// +// type hotfixMgr interface { +// reg(file string) +// check(L *LState) *hotfixList +// } +// +// func newHotfixMgr(ctx context.Context, needCoro bool, hotfixTime int64) hotfixMgr { +// var ht hotfixMgr +// if needCoro { +// htco := &hotfixMgrCoro{ +// ctx: ctx, +// ch: make(chan *hotfixList, 16), +// hotfixTime: hotfixTime, +// } +// go htco.loop() +// ht = htco +// } else { +// ht = &hotfixMgrLocal{ +// mp: make(map[string]int64), +// lasttime: time.Now().Unix(), +// hotfixTime: hotfixTime, +// } +// } +// return ht +// } +// +// type hotfixList struct { +// files []string +// } +// +// func hotfixDoFile(L *LState, ht hotfixMgr, up *hotfixList) { +// size := len(up.files) +// for i := 0; i < size; i++ { +// err := L.L().DoFile(up.files[i]) +// if err != nil { +// log.Error("DoFile fail, file=%v err=%v", up.files[i], err) +// } else { +// log.Info("reload file=%v success", up.files[i]) +// } +// } +// } +// +// ////////////////////////////////////////////////////////////////// +// // hotfixMgrLocal +// +// type hotfixMgrLocal struct { +// mp map[string]int64 +// lasttime int64 +// hotfixTime int64 +// } +// +// func (ht *hotfixMgrLocal) reg(file string) { +// mt, err := getFileModtime(file) +// if err != nil { +// return +// } +// ht.mp[file] = mt +// } +// +// func (ht *hotfixMgrLocal) check(L *LState) *hotfixList { +// curr := time.Now().Unix() +// lasttime := atomic.LoadInt64(&ht.lasttime) +// if curr < (lasttime + ht.hotfixTime) { +// return nil +// } +// atomic.StoreInt64(&ht.lasttime, curr) +// up := ht.getHotfixList() +// if up != nil { +// hotfixDoFile(L, ht, up) +// } +// return up +// } +// +// func (ht *hotfixMgrLocal) getHotfixList() *hotfixList { +// size := len(ht.mp) +// if size <= 0 { +// return nil +// } +// up := &hotfixList{ +// files: make([]string, 0, size), +// } +// tmp := make(map[string]int64) +// for k, v := range ht.mp { +// mt, err := getFileModtime(k) +// if err != nil { +// log.Error("getFileModtime fail, file=%v err=%v", k, err) +// continue +// } +// if v != mt { +// up.files = append(up.files, k) +// tmp[k] = mt +// } +// } +// for k, v := range tmp { +// ht.mp[k] = v +// } +// return up +// } +// +// ////////////////////////////////////////////////////////////////// +// // hotfixMgrCoro +// +// type hotfixMgrCoro struct { +// ctx context.Context +// mp sync.Map +// ch chan *hotfixList +// hotfixTime int64 +// } +// +// func (ht *hotfixMgrCoro) reg(file string) { +// mt, err := getFileModtime(file) +// if err != nil { +// return +// } +// ht.mp.Store(file, mt) +// } +// +// func (ht *hotfixMgrCoro) check(L *LState) *hotfixList { +// up := ht.getHotfixList() +// if up != nil { +// hotfixDoFile(L, ht, up) +// } +// return up +// } +// +// func (ht *hotfixMgrCoro) getHotfixList() *hotfixList { +// select { +// case up := <-ht.ch: +// return up +// default: +// return nil +// } +// } +// +// func (ht *hotfixMgrCoro) loop() { +// timer := time.NewTimer(time.Duration(ht.hotfixTime) * time.Second) +// defer timer.Stop() +// Loop: +// for { +// select { +// case <-timer.C: +// ht.loopCheck() +// timer.Reset(time.Duration(ht.hotfixTime) * time.Second) +// case <-ht.ctx.Done(): +// break Loop +// } +// } +// } +// +// func (ht *hotfixMgrCoro) loopCheck() { +// var up *hotfixList +// mp := make(map[string]int64) +// ht.mp.Range(func(k, v interface{}) bool { +// file, ok := k.(string) +// if !ok { +// return false +// } +// oldmt, mtOK := v.(int64) +// if !mtOK { +// return false +// } +// newmt, err := getFileModtime(file) +// if err != nil { +// log.Error("getFileModtime fail, file=%v err=%v", file, err) +// return false +// } +// if newmt != oldmt { +// mp[file] = newmt +// } +// return true +// }) +// size := len(mp) +// if size > 0 { +// up = &hotfixList{ +// files: make([]string, 0, size), +// } +// for k, v := range mp { +// ht.mp.Store(k, v) +// up.files = append(up.files, k) +// } +// select { +// case ht.ch <- up: +// return +// default: +// log.Error("hotfix send to channel fail, up=%v", up) +// } +// } +// } +// diff --git a/luaScript/bit.lua b/luaScript/bit.lua new file mode 100644 index 0000000..60e9481 --- /dev/null +++ b/luaScript/bit.lua @@ -0,0 +1,136 @@ +require ("math") +module('bit', package.seeall) -- 实现按位运算 + +--默认按32位 +local __bitNum = 32 + +--设置位数 +function setBitNum(bitNum) + __bitNum = bitNum +end + +--按位同或 +function bxnor(int1, int2) + return __operaByBit(__bitxnor, int1, int2) +end + +--按位异或 +function bxor(int1, int2) + return __operaByBit(__bitxor, int1, int2) +end + +--按位与 +function band(int1, int2) + return __operaByBit(__bitand, int1, int2) +end + +--按位或 +function bor(int1, int2) + return __operaByBit(__bitor, int1, int2) +end + +--按位非 +function bnot(integer) + return __operaByBit(__bitnot, integer) +end + +--按位操作 +function __operaByBit(bitFunc, ...) + local bDataLst = {} + + for i = 1, select("#", ...) do + local bData = itob(select(i, ...)) + table.insert(bDataLst, bData) + end + + for _, bData in ipairs(bDataLst) do + for i = #bData + 1, __bitNum do + table.insert(bData, 1, 0) + end + end + + local resData = {} + for i = 1, __bitNum do + local args = {} + for _, bData in ipairs(bDataLst) do + table.insert(args, bData[i]) + end + table.insert(resData, bitFunc(unpack(args))) + end + + return btoi(resData) +end + +--按位同或 +function __bitxnor(bit1, bit2) + return (bit1 == bit2) and 1 or 0 +end + +--按位异或 +function __bitxor(bit1, bit2) + return (bit1 == bit2) and 0 or 1 +end + +--按位与 +function __bitand(bit1, bit2) + return (bit1 == 1 and bit2 == 1) and 1 or 0 +end + +--按位或 +function __bitor(bit1, bit2) + return (bit1 == 1 or bit2 == 1) and 1 or 0 +end + +--按位非 +function __bitnot(bit) + return 1 - bit +end + +--2进制转换成10进制 +function btoi(bData) + return __ntoi(bData, 2) +end + +--10进制转换成2进制 +function itob(integer) + return __iton(integer, 2) +end + +--10进制转换成N进制 +function __iton(integer, num) + assert(type(integer) == "number") + + if integer == 0 then + return {0} + end + + local bNeg = integer < 0 + local ci = math.abs(integer) + + local nData = {} + while ci > 0 do + table.insert(nData, 1, ci % num) + ci = math.floor(ci / num) + end + + if bNeg then + for i = #nData + 1, __bitNum do + table.insert(nData, 1, num - 1) + end + end + + return nData +end + +--N进制转换成10进制 +function __ntoi(nData, num) + assert(type(nData) == "table") + + local integer = 0 + for i, data in ipairs(nData) do + integer = integer + data * math.pow(num, #nData - i) + end + + return integer +end + diff --git a/luaScript/class.lua b/luaScript/class.lua new file mode 100644 index 0000000..0ecbe26 --- /dev/null +++ b/luaScript/class.lua @@ -0,0 +1,80 @@ + + +function GetClassName(name) + for k,v in pairs(_G) do + if name==v then + return k + end + end +end +function CreateClass(name,basename) + if _G[name] ~= nil then + unilight.error("CreateClass被意外全局初始化,这里强制重置成类:"..name) + return nil + end + _G[name] = {} + local class = _G[name] + if basename then + local baseclass = _G[basename] + if baseclass then + for k,v in pairs(baseclass) do + class[k] = v + end + else + unilight.error("CreateClass error:" .. tostring(name) .. ":" .. tostring(basename)) + end + end + class.__classname = name + function class:New(initclass) + local new = initclass or {} + setmetatable(new, { __index = self}) + return new + end + function class:SetClassName(cname) + self.__classname = cname or self.__classname + end + function class:GetLogPrefix() + local id = nil + local name = "" + if self.GetId then + id = self:GetId() + elseif self.id then + id = self.id + elseif self.Id then + id = self.Id + elseif self.tempid then + id = self.tempid + elseif self.Tempid then + id = self.Tempid + end + if self.GetName then + name = self:GetName() + elseif self.name then + name = self.name + elseif self.Name then + name = self.Name + end + local id = id or "" + local name = name or "" + return self.__classname .. "[" .. id .."," ..name.. "] " + end + function class:Debug(...) + unilight.debug(self:GetLogPrefix() .. unpack(arg)) + end + function class:Info(...) + unilight.info(self:GetLogPrefix() .. unpack(arg)) + end + function class:Warn(...) + unilight.warn(self:GetLogPrefix() .. unpack(arg)) + end + function class:Error(...) + unilight.error(self:GetLogPrefix() .. unpack(arg)) + end + function class:Stack(...) + unilight.stack(self:GetLogPrefix() .. unpack(arg)) + end + return class +end +--Class = CreateClass("Class") +--new = Class:New() +--new:Debug("whj") diff --git a/luaScript/extend.lua b/luaScript/extend.lua new file mode 100644 index 0000000..ce93354 --- /dev/null +++ b/luaScript/extend.lua @@ -0,0 +1,295 @@ +-- 通用lua扩充函数,与任何游戏逻辑无关 + +-- from http://snippets.luacode.org/?p=snippets/String_to_Hex_String_68 +string.tohex = function(str, spacer) + return string.gsub(str,"(.)", function (c) return string.format("%02X%s", string.byte(c), spacer or "") end) +end + +string.trim = function(str) + return string.gsub(str, "^%s*(.-)%s*$", "%1") +end +string.trimbegin = function(str) + return string.gsub(str, "^%s*(.-)$", "%1") +end +string.trimend = function(str) + return string.gsub(str, "^(.-)%s*$", "%1") +end + +string.padleft = function(str, totalWidth, paddingChar) + local len = #str + if len >= totalWidth then + return str + else + paddingChar = paddingChar or ' ' + assert(#paddingChar == 1) + return string.rep(paddingChar, totalWidth - len) .. str + end +end +string.padright = function(str, totalWidth, paddingChar) + local len = #str + if len >= totalWidth then + return str + else + paddingChar = paddingChar or ' ' + assert(#paddingChar == 1) + return str .. string.rep(paddingChar, totalWidth - len) + end +end + +string.split = function(szFullString, szSeparator) + local FindStartIndex = 1 + local SplitArray = {} + while true do + local FindLastIndex = string.find(szFullString, szSeparator, FindStartIndex, true) + if not FindLastIndex then + table.insert(SplitArray, string.sub(szFullString, FindStartIndex, string.len(szFullString))) + break + end + table.insert(SplitArray, string.sub(szFullString, FindStartIndex, FindLastIndex-1)) + FindStartIndex = FindLastIndex + string.len(szSeparator) + end + return SplitArray +end + +string.isNilOrEmpty = function(str) + if str == nil then + return true, nil + end + if type(str) ~= "string" then + return true, nil + end + local fstr = string.match(str,"%s*(.-)%s*$") + local ret = fstr == "" + if ret == true then + str = nil + end + return ret, fstr +end + +table.find = function(this, value) + for k,v in pairs(this) do + if v == value then return k end + end +end + +table.omit = function(tbl) + for k,v in pairs(tbl) do + local typ = type(v) + if typ == "table" then + v = table.omit(v) + if v == nil or next(v) == nil then + tbl[k] = nil + end + elseif (typ == "string" and v == "") or (typ == "number" and v == 0) then + tbl[k] = nil + end + end + return tbl +end +table.tostring = function(data, _indent) + local visited = {} + local function dump(data, prefix) + local str = tostring(data) + if table.find(visited, data) ~= nil then return str end + table.insert(visited, data) + + local prefix_next = prefix .. " " + str = str .. "\n" .. prefix .. "{" + for k,v in pairs(data) do + if type(k) == "number" then + str = str .. "\n" .. prefix_next .. "[" .. tostring(k) .. "] = " + else + str = str .. "\n" .. prefix_next .. tostring(k) .. " = " + end + if type(v) == "table" then + str = str .. dump(v, prefix_next) + elseif type(v) == "string" then + str = str .. '"' .. v .. '"' + else + str = str .. tostring(v) + end + end + str = str .. "\n" .. prefix .. "}" + return str + end + return dump(data, _indent or "") +end + +table.merge = function(base, delta) + if type(delta) ~= "table" then return end + for k,v in pairs(delta) do + base[k] = v + end +end + +table.extend = function(base, delta) + if type(delta) ~= "table" then return end + for i,v in ipairs(delta) do + table.insert(base, v) + end +end + +table.len = function(tbl) + if type(tbl) ~= "table" then return 0 end + local n = 0 + for k,v in pairs(tbl) do n = n + 1 end + return n +end + +table.empty = function(tbl) + if tbl == nil then return true end + assert(type(tbl) == "table") + return next(tbl) == nil + --if #tbl > 0 then return false end + --for k,v in pairs(tbl) do return false end + --return true +end + +-- http://snippets.luacode.org/?p=snippets/Deep_copy_of_a_Lua_Table_2 +table.clone = function(t,deepnum) + if type(t) ~= 'table' then return t end + local mt = getmetatable(t) + local res = {} + + if deepnum and deepnum > 0 then + deepnum = deepnum - 1 + end + for k,v in pairs(t) do + if type(v) == 'table' then + if not deepnum or deepnum > 0 then + v = table.clone(v, deepnum) + end + end + res[k] = v + end + setmetatable(res,mt) + return res +end + +-- http://snippets.luacode.org/?p=snippets/Table_Slice_116 +table.slice = function(values,i1,i2) + local res = {} + local n = #values + i1 = i1 or 1 + i2 = i2 or n + if i2 < 0 then + i2 = n + i2 + 1 + elseif i2 > n then + i2 = n + end + if i1 < 1 or i1 > n then + return {} + end + local k = 1 + for i = i1,i2 do + res[k] = values[i] + k = k + 1 + end + return res +end + +table.reverse = function(tab) + local size = #tab + local newTable = {} + for i,v in ipairs(tab) do + newTable[size+1-i] = v + end + return newTable +end + +table.reset = function(t) + for k,v in pairs(t) do + t[k] = nil + end + return t +end + +-- math.random({0.7, 0.1, 0.2}, {'A', 'B', 'C'}) +math.random = function(m, n) + if type(m) == "table" and #m == #n then + -- 标准化概率表 + local sum = 0 + for _,v in ipairs(m) do sum = sum + v end + local sm = {} + for k,v in ipairs(m) do sm[k] = v / sum end + -- 得到下标 + local r = go.rand.Random() + for k,v in ipairs(sm) do + if r <= v then return n[k] + else r = r - v end + end + assert(false) + end + + if m == nil then return go.rand.Random() end + local _random = function(m, n) + m, n = math.min(m, n), math.max(m, n) + local mi, mf = math.modf(m) + local ni, nf = math.modf(n) + if mf == 0 and nf == 0 then + return go.rand.RandBetween(m, n) + else + return m + go.rand.Random() * (n - m) + end + end + if n == nil then return _random(1, m) end + return _random(m, n) +end + +-- http://www.cplusplus.com/reference/algorithm/random_shuffle/ +-- http://stackoverflow.com/questions/17119804/lua-array-shuffle-not-working +math.shuffle = function(array) + local counter = #array + while counter > 1 do + local index = math.random(counter) + array[index], array[counter] = array[counter], array[index] + counter = counter - 1 + end + return array +end + +--按table的key排序遍历table e.g. for k, v in pairsByKeys(tab, function(v1,v2) return v1 > v2 end) do print(k, v) end +function pairsByKeys(t, sortfunc) + local kt = {} + local len = 0 + for k in pairs(t) do + len = len + 1 + kt[len] = k + end + + table.sort(kt, sortfunc) + + local i = 0 + return function() + i = i + 1 + return kt[i], t[kt[i]] + end +end + +--计算utf8字符串的长度 from quickcocos +function string.utf8len(input) + local len = string.len(input) + local left = len + local cnt = 0 + local arr = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc} + while left ~= 0 do + local tmp = string.byte(input, -left) + local i = #arr + while arr[i] do + if tmp >= arr[i] then + left = left - i + break + end + i = i - 1 + end + cnt = cnt + 1 + end + return cnt +end + +--检查一个文件是否存在 +function file_exists(path) + local file = io.open(path, "rb") + if file then file:close() end + return file ~= nil +end diff --git a/luaScript/random.lua b/luaScript/random.lua new file mode 100644 index 0000000..80525d0 --- /dev/null +++ b/luaScript/random.lua @@ -0,0 +1,37 @@ +module('random', package.seeall) + + +--添加的随机概率函数--------- +----小数点概率--- +function selectByPoint(value) + if value == nil or value <= 0 then + return false + end + local value = math.ceil(1 / value) + return selectByRegion(1, value) +end + + +----百分比概率--- +function selectByPercent(value) + if value < 1 then + return false + end + return selectByRegion(value, 100) +end + +----万分比概率--- +function selectByTenTh(value) + if value < 1 then + return false + end + return selectByRegion(value, 10000) +end + +function selectByRegion(down, up) + if down >= up then + return true + end + local random = math.random(1, up) + return random <= down +end diff --git a/luaScript/unilight.lua b/luaScript/unilight.lua new file mode 100644 index 0000000..83942d2 --- /dev/null +++ b/luaScript/unilight.lua @@ -0,0 +1,42 @@ +unilight = unilight or {} +os.time = go.time.luatime() +os.msectime = go.time.Msec +os.nsectime = go.time.Nsec + +-- log -- +unilight.debug = function(...) + local arg = {...} + go.logging.debug(arg[1], arg[2] or {}) +end + +unilight.info = function(...) + local arg = {...} + go.logging.info(arg[1], arg[2] or {}) +end + +unilight.warn = function(...) + print("unilight-warn:" .. tostring(...)) + local arg = {...} + go.logging.warning(arg[1], arg[2] or {}) +end + +unilight.error = function(...) + local arg = {...} + if next(arg) == nil then + unilight.error(debug.traceback()) + end + go.logging.error(arg[1], arg[2] or {}) +end + +unilight.stack = function(...) + local arg = {...} + print("unilight-stack:" .. tostring(...)) +end + +unilight.tablefiles = function() + return luar.slice2table(go.getLuaFiles(go.tablePath)) +end + +unilight.scriptfiles = function() + return luar.slice2table(go.getLuaFiles(go.scriptPath)) +end diff --git a/luaScript/uniregexp.lua b/luaScript/uniregexp.lua new file mode 100644 index 0000000..fc56c7b --- /dev/null +++ b/luaScript/uniregexp.lua @@ -0,0 +1,21 @@ +uniregexp= uniregexp or {} + +--[[ + exp: + uniregexp.match("foo.*","seafood") => true nil + uniregexp.match("bar.*","seafood") => false nil + uniregexp.match("a(b","seafood") => false error parsing regexp: missing closing ): `a(b` +--]] +uniregexp.match = function(pattern, s) + return go.uniregexp.Match(pattern, s) +end + +--[[ + exp: + quotemeta(`[foo]`) => `\[foo\]` +--]] +uniregexp.quotemeta = function(s) + return go.uniregexp.QuoteMeta(s) +end + +-- 其余api可以调用go.uniregexp.***** 参考go语言 regexp.Regexp类方法 diff --git a/luaScript/unitimer.lua b/luaScript/unitimer.lua new file mode 100644 index 0000000..42876d3 --- /dev/null +++ b/luaScript/unitimer.lua @@ -0,0 +1,137 @@ + +CreateClass("UniTimerClass") +CreateClass("UniEventClass") + + +function NewUniTimerClass(callback, msec, ...) + local timer = { + nextmsec=unitimer.now, + callback = callback, + tick = msec, + params = arg, + } + UniTimerClass:New(timer) + return timer +end +function NewUniTimerRandomClass(callback, msec, ...) + local timer = { + nextmsec=unitimer.now+math.random(msec/2,msec), + callback = callback, + tick = msec, + params = arg, + } + UniTimerClass:New(timer) + return timer +end +function NewUniEventClass(callback, msec,maxtimes, ...) + local event = { + nextmsec=unitimer.now+msec, + callback = callback, + tick = msec, + maxtimes = maxtimes, + params = arg, + } + UniEventClass:New(event) + return event +end +function UniTimerClass:GetId() + return self.tick +end +function UniTimerClass:GetName() + return self.tick +end +function UniTimerClass:Stop() + self.stop = true + unitimer.removetimer(self) +end +function UniTimerClass:Check(now,force) + if self.nextmsec <= now or force then + --unilight.error("UniEventClass:"..unpack(self.params)) + self.nextmsec = now + self.tick --如果callback脚本报错,会悲剧,WHJ,似乎没人用,先提前试试 + self.callback(unpack(self.params)) + return true + end + --duaration=0 + --first=true + --pause=false + --stop=false + return false +end +function UniEventClass:GetId() + return self.tick +end +function UniEventClass:GetName() + return self.maxtimes +end +function UniEventClass:Check(now,force) + --if (self.nextmsec <= now or force) and self.tick > 0 then + if (self.maxtimes > 0 and self.nextmsec <= now) or force then + self.nextmsec = now + self.tick --如果callback脚本报错,会悲剧,WHJ,似乎没人用,先提前试试 + self.maxtimes = self.maxtimes - 1 --计数可以提前,时间不能提前,有可能逻辑里要用时间,提前的目的是防止Check报错后就悲剧 + self.callback(unpack(self.params)) + return true + end + return false +end +function UniEventClass:Stop() + unitimer.removeevent(self) +end +unitimer={ + timermap={}, + eventmap={}, +} +function unitimer.init(msec) --最小精度的定时器 + unitimer.now = go.time.Msec() + if unitimer.ticktimer ~= nil then + unilight.error("unitimer.init已经初始化过了:"..unitimer.tickmsec) + return false + end + unitimer.tickmsec = msec --保存最小精度 + unitimer.ticktimer = unilight.addtimermsec("unitimer.loop", msec) + return true +end +function unitimer.loop() + local timer = unitimer + timer.now = go.time.Msec() + for k,v in pairs(timer.timermap) do + if v:Check(timer.now) == true then + if v.stop == true then + timer.removetimer(v) + end + end + end + for k,v in pairs(timer.eventmap) do + if v:Check(timer.now) == true then + if v.maxtimes <= 0 then + --v:Debug("事件结束") + v:Stop() + end + end + end +end +function unitimer.addtimermsec(callback, msec, ...) + local timer = NewUniTimerClass(callback, msec, ...) + --timer:Debug("unitimer.addtimermsec:") + unitimer.timermap[timer]=timer + return timer +end +function unitimer.addtimer(callback, msec, ...) + return unitimer.addtimermsec(callback, msec*1000, ...) +end +function unitimer.removetimer(timer) + --timer:Debug("unitimer.removetimer:") + unitimer.timermap[timer] = nil +end +function unitimer.addevent(callback, msec,maxtimes, ...) + return unitimer.addeventmsec(callback, msec*1000,maxtimes, ...) +end +function unitimer.addeventmsec(callback, msec,maxtimes, ...) + maxtime = maxtimes or 1 + local event = NewUniEventClass(callback, msec,maxtimes, ...) + --event:Debug("设置事件:"..msec) + unitimer.eventmap[event]=event + return event +end +function unitimer.removeevent(event) + unitimer.eventmap[event] = nil +end diff --git a/luaScript/utf8.lua b/luaScript/utf8.lua new file mode 100644 index 0000000..2c4f0ed --- /dev/null +++ b/luaScript/utf8.lua @@ -0,0 +1,118 @@ +local pattern = '[%z\1-\127\194-\244][\128-\191]*' + +-- helper function +local posrelat = + function (pos, len) + if pos < 0 then + pos = len + pos + 1 + end + + return pos + end + +utf8 = {} + +-- maps f over s's utf8 characters f can accept args: (visual_index, utf8_character, byte_index) +utf8.map = + function (s, f, no_subs) + local i = 0 + + if no_subs then + for b, e in s:gmatch('()' .. pattern .. '()') do + i = i + 1 + local c = e - b + f(i, c, b) + end + else + for b, c in s:gmatch('()(' .. pattern .. ')') do + i = i + 1 + f(i, c, b) + end + end + end + +-- generator for the above -- to iterate over all utf8 chars +utf8.chars = + function (s, no_subs) + return coroutine.wrap(function () return utf8.map(s, coroutine.yield, no_subs) end) + end + +-- returns the number of characters in a UTF-8 string +utf8.len = + function (s) + -- count the number of non-continuing bytes + return select(2, s:gsub('[^\128-\193]', '')) + end + +utf8.GetMaxLenString = + function (s, maxlen, symbol) + -- s:待裁剪字符串,maxlen:最大长度,symbol:裁剪后补全符号 + symbol = symbol or "" + local len = utf8.len(s) + local dstString = s + -- 超长,裁剪,加symbol + if len > maxlen then + dstString = utf8.sub(s, 1, maxlen) + dstString = dstString..symbol + end + return dstString + end + +-- replace all utf8 chars with mapping +utf8.replace = + function (s, map) + return s:gsub(pattern, map) + end + +-- reverse a utf8 string +utf8.reverse = + function (s) + -- reverse the individual greater-than-single-byte characters + s = s:gsub(pattern, function (c) return #c > 1 and c:reverse() end) + + return s:reverse() + end + +-- strip non-ascii characters from a utf8 string +utf8.strip = + function (s) + return s:gsub(pattern, function (c) return #c > 1 and '' end) + end + +-- like string.sub() but i, j are utf8 strings +-- a utf8-safe string.sub() +utf8.sub = + function (s, i, j) + local l = utf8.len(s) + + i = posrelat(i, l) + j = j and posrelat(j, l) or l + + if i < 1 then i = 1 end + if j > l then j = l end + + if i > j then return '' end + + local diff = j - i + local iter = utf8.chars(s, true) + + -- advance up to i + for _ = 1, i - 1 do iter() end + + local c, b = select(2, iter()) + + -- i and j are the same, single-charaacter sub + if diff == 0 then + return string.sub(s, b, b + c - 1) + end + + i = b + + -- advance up to j + for _ = 1, diff - 1 do iter() end + + c, b = select(2, iter()) + + return string.sub(s, i, b + c - 1) + end + diff --git a/luaStatePool.go b/luaStatePool.go new file mode 100644 index 0000000..b61b9d1 --- /dev/null +++ b/luaStatePool.go @@ -0,0 +1,76 @@ +package luaInGo + +import ( + lua "github.com/yuin/gopher-lua" + "strings" + "sync" +) + +type lStatePool struct { + m sync.Mutex + saved []*lua.LState +} + +// Get 从池中取出一个LState,若池中没有,则新增一个 +func (pl *lStatePool) Get() *lua.LState { + pl.m.Lock() + defer pl.m.Unlock() + n := len(pl.saved) + if n == 0 { + return pl.New() + } + x := pl.saved[n-1] + pl.saved = pl.saved[0 : n-1] + return x +} + +// Put 用完LState后放回池中 +func (pl *lStatePool) Put(L *lua.LState) { + pl.m.Lock() + defer pl.m.Unlock() + if len(pl.saved) > NaxPoolSize { + L.Close() + } else { + // 放回的时候 清理一下 堆栈 确认数据正常 + L.SetTop(0) + pl.saved = append(pl.saved, L) + } +} + +func (pl *lStatePool) ShutDown() { + for _, L := range pl.saved { + L.Close() + } +} + +func (pl *lStatePool) New() *lua.LState { + L := lua.NewState() + + //提供全局函数给lua + PreLoadGo(L) + + //加载go提供元表给lua + // golua.RegisterPersonType(L) + + // 添加lua脚本自动搜索路径 + // Tamper package.path according to configuration... + t := L.GetGlobal("package").(*lua.LTable) + // Get "path" from package table + lPath := lua.LString("path") + s := L.RawGet(t, lPath).(lua.LString).String() + + // Create list of elements to join for new package path + elems := []string{s} + elems = append(elems, "./luaScript/?.lua") + + // Set new package.path + L.RawSet(t, lPath, lua.LString(strings.Join(elems, ";"))) + + //加载lua脚本 仅仅加载入口函数模块的lua + if err := L.DoFile("./luaScript/main.lua"); err != nil { + println("load the main lua files error") + panic(err) + } + + return L +} diff --git a/preLoadGo.go b/preLoadGo.go new file mode 100644 index 0000000..abdf4cc --- /dev/null +++ b/preLoadGo.go @@ -0,0 +1,21 @@ +package luaInGo + +import ( + lua "github.com/yuin/gopher-lua" + "luaInGo/goApis" + "luaInGo/goApis/crypto" + "luaInGo/goApis/json" + "luaInGo/goApis/strings" + "luaInGo/goApis/time" +) + +// 这里封装一个函数 统一load go中提供给lua调用的函数 + +func PreLoadGo(L *lua.LState) { + // 这里再调用一些子模块的LoadGo()函数 + time.PreLoadGo(L) + strings.PreLoadGo(L) + crypto.PreLoadGo(L) + json.PreloadGo(L) + goApis.PreLoadLibs(L) +}