├── .gitattributes
├── .gitignore
├── LICENSE
├── README.adoc
├── bench
└── object_access.lua
├── bugs
├── coroutine_1.lua
├── coroutine_2.lua
├── error.lua
├── io_read.lua
├── multi-assignment.lua
├── self-assign.lua
├── string_format_1.lua
└── string_format_2.lua
├── cmd
├── dsl
│ └── main.go
├── ll
│ └── main.go
├── standalone
│ ├── main.go
│ └── src
│ │ └── main.lua
└── test
│ └── src
│ └── main.lua
├── docs
├── bitcask.adoc
├── crypto.adoc
├── csv.adoc
├── date.adoc
├── exec.adoc
├── extension_exec.adoc
├── extension_json.adoc
├── extension_string.adoc
├── extension_table.adoc
├── fmt.adoc
├── fs.adoc
├── fsnotify.adoc
├── go-helper.adoc
├── go-loader.adoc
├── guard.adoc
├── http.adoc
├── json.adoc
├── list.adoc
├── logger.adoc
├── lz4.adoc
├── map.adoc
├── mysql.adoc
├── os.adoc
├── pushover.adoc
├── queue.adoc
├── redis.adoc
├── refmt.adoc
├── slack.adoc
├── ssh_config.adoc
├── telegram.adoc
├── template.adoc
├── tuple.adoc
├── uid.adoc
├── ulid.adoc
└── uuid.adoc
├── dsl.go
├── external
├── gluacrypto
│ ├── LICENSE
│ └── crypto
│ │ ├── base64.go
│ │ ├── ch.go
│ │ ├── crc32.go
│ │ ├── crypto.go
│ │ ├── decrypt.go
│ │ ├── encrypt.go
│ │ ├── hmac.go
│ │ ├── md5.go
│ │ ├── random.go
│ │ ├── sha1.go
│ │ ├── sha256.go
│ │ └── sha512.go
├── gluahttp
│ ├── LICENSE
│ ├── gluahttp.go
│ └── httpresponsetype.go
├── gluasocket
│ ├── LICENSE
│ ├── gluasocket.go
│ ├── socket
│ │ └── socket.go
│ ├── socketcore
│ │ ├── client.go
│ │ ├── clientclose.go
│ │ ├── clientdirty.go
│ │ ├── clientgetfd.go
│ │ ├── clientgetpeername.go
│ │ ├── clientgetsockname.go
│ │ ├── clientgetstats.go
│ │ ├── clientreceive.go
│ │ ├── clientsend.go
│ │ ├── clientsetoption.go
│ │ ├── clientsetstats.go
│ │ ├── clientsettimeout.go
│ │ ├── clientshutdown.go
│ │ ├── connect.go
│ │ ├── dns.go
│ │ ├── dnsgetaddrinfo.go
│ │ ├── dnsgethostname.go
│ │ ├── dnstohostname.go
│ │ ├── dnstoip.go
│ │ ├── gettime.go
│ │ ├── master.go
│ │ ├── masteraccept.go
│ │ ├── masterbind.go
│ │ ├── masterclose.go
│ │ ├── masterconnect.go
│ │ ├── masterlisten.go
│ │ ├── mastersetoption.go
│ │ ├── mastersettimeout.go
│ │ ├── select.go
│ │ ├── skip.go
│ │ ├── sleep.go
│ │ ├── socketcore.go
│ │ ├── tcp.go
│ │ ├── tcp4.go
│ │ ├── tcp6.go
│ │ └── udp.go
│ └── socketexcept
│ │ └── socketexcept.go
├── gluasql
│ ├── LICENSE
│ ├── mysql
│ │ ├── client.go
│ │ ├── clientconnect.go
│ │ ├── clientquery.go
│ │ ├── clientsettimeout.go
│ │ └── mysql.go
│ └── util
│ │ └── util.go
├── gopher-json
│ ├── LICENSE
│ └── json.go
└── gopher-lfs
│ ├── LICENSE
│ ├── api.go
│ ├── api_darwin.go
│ ├── api_linux.go
│ ├── api_other.go
│ ├── api_windows.go
│ └── util.go
├── go.mod
├── go.sum
├── helper.go
├── internal
├── bitcask.go
├── dsl
│ ├── lbuildah.lua
│ └── lopper.lua
├── exec.go
├── fs.go
├── fsnotify.go
├── global.go
├── ksuid.go
├── logger.go
├── lua
│ ├── argparse.lua
│ ├── csv.lua
│ ├── date.lua
│ ├── extension_exec.lua
│ ├── extension_json.lua
│ ├── extension_string.lua
│ ├── extension_table.lua
│ ├── fmt.lua
│ ├── graph.lua
│ ├── guard.lua
│ ├── list.lua
│ ├── map.lua
│ ├── object.lua
│ ├── queue.lua
│ ├── state.lua
│ ├── template.lua
│ ├── test.lua
│ ├── tuple.lua
│ └── util.lua
├── lz4.go
├── os.go
├── pushover.go
├── redis.go
├── refmt.go
├── slack.go
├── ssh_config.go
├── telegram.go
├── ulid.go
└── uuid.go
├── ll.svg
├── ll.toml
├── loader.go
├── scripts
├── .lib
│ ├── 000-header.sh
│ └── 001-go.sh
├── build-dsl
│ └── script
├── build-pie
│ └── script
├── build-standalone
│ └── script
├── build-test
│ └── script
├── build
│ └── script
├── docs
│ └── script
├── godocs
│ └── script
├── install
│ └── script
├── lint
│ └── script
├── show-functions
│ └── script
├── template-test
│ ├── script
│ └── template.txt
└── test
│ └── script
├── selene.toml
├── stylua.toml
└── tests
├── argparse.lua
├── bitcask.lua
├── crypto.lua
├── csv.lua
├── date.lua
├── exec.lua
├── exec_cmd.lua
├── extension_exec.lua
├── extension_json.lua
├── extension_string.lua
├── extension_table.lua
├── fmt.lua
├── fs.lua
├── fsnotify.lua
├── graph.lua
├── guard.lua
├── http.lua
├── json.lua
├── ksuid.lua
├── list.lua
├── logger.lua
├── lua.lua
├── lz4.lua
├── map.lua
├── mysql.lua
├── object.lua
├── os.lua
├── pushover.lua
├── queue.lua
├── redis.lua
├── refmt.lua
├── slack.lua
├── ssh_config.lua
├── state.lua
├── state
├── composite.lua
├── debug_plain.lua
└── helloworld.lua
├── telegram.lua
├── template.lua
├── tuple.lua
├── ulid.lua
└── uuid.lua
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.lua linguist-detectable=false
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /ll
2 | /experiments
3 | /external/gopher-lua
4 | /cmd/lopper
5 | /cmd/lbuildah
6 | /cmd/test/main.go
7 | /*.lua
8 | /bin
9 | /rr.json
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Eduardo Tongson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/bench/object_access.lua:
--------------------------------------------------------------------------------
1 | -- http://lua-users.org/wiki/ObjectBenchmarkTests
2 | --[[ This is an evaluation of object access time for various approaches to object orientation in Lua. The primary concern was raw performance speed, not memory use or object creation time.
3 | ]]
4 |
5 | do
6 | local function runbenchmark(name, code, count, ob)
7 | local f = loadstring([[
8 | local count,ob = ...
9 | local clock = os.clock
10 | local start = clock()
11 | for i=1,count do ]] .. code .. [[ end
12 | return clock() - start
13 | ]])
14 | io.write(f(count, ob), "\t", name, "\n")
15 | end
16 |
17 | local nameof = {}
18 | local codeof = {}
19 | local tests = {}
20 | function addbenchmark(name, code, ob)
21 | nameof[ob] = name
22 | codeof[ob] = code
23 | tests[#tests+1] = ob
24 | end
25 | function runbenchmarks(count)
26 | for _,ob in ipairs(tests) do
27 | runbenchmark(nameof[ob], codeof[ob], count, ob)
28 | end
29 | end
30 | end
31 |
32 | function makeob1()
33 | local self = {data = 0}
34 | function self:test() self.data = self.data + 1 end
35 | return self
36 | end
37 | addbenchmark("Standard (solid)", "ob:test()", makeob1())
38 |
39 | local ob2mt = {}
40 | ob2mt.__index = ob2mt
41 | function ob2mt:test() self.data = self.data + 1 end
42 | function makeob2()
43 | return setmetatable({data = 0}, ob2mt)
44 | end
45 | addbenchmark("Standard (metatable)", "ob:test()", makeob2())
46 |
47 | function makeob3()
48 | local self = {data = 0};
49 | function self.test() self.data = self.data + 1 end
50 | return self
51 | end
52 | addbenchmark("Object using closures (PiL 16.4)", "ob.test()", makeob3())
53 |
54 | function makeob4()
55 | local public = {}
56 | local data = 0
57 | function public.test() data = data + 1 end
58 | function public.getdata() return data end
59 | function public.setdata(d) data = d end
60 | return public
61 | end
62 | addbenchmark("Object using closures (noself)", "ob.test()", makeob4())
63 |
64 | addbenchmark("Direct Access", "ob.data = ob.data + 1", makeob1())
65 |
66 | addbenchmark("Local Variable", "ob = ob + 1", 0)
67 |
68 |
69 | runbenchmarks(select(1,...) or 100000000)
70 |
--------------------------------------------------------------------------------
/bugs/coroutine_1.lua:
--------------------------------------------------------------------------------
1 | mt = {
2 | __le = function (a,b)
3 | coroutine.yield("yield")
4 | return a.x <= b.x
5 | end
6 | }
7 | t1 = setmetatable({x=1}, mt)
8 | t2 = {x=2}
9 | fn = function (a,b) return t2 <= t1 end
10 | co = coroutine.wrap(fn)
11 | co()
12 | print(co())
13 |
--------------------------------------------------------------------------------
/bugs/coroutine_2.lua:
--------------------------------------------------------------------------------
1 | local f = string.gmatch("1 2 3 4 5", "%d+")
2 | print(f()) --> 1
3 | co = coroutine.wrap(f)
4 | print(co()) --> ??? (should be 2)
5 |
--------------------------------------------------------------------------------
/bugs/error.lua:
--------------------------------------------------------------------------------
1 | error(coroutine.create(function() end))
2 |
--------------------------------------------------------------------------------
/bugs/io_read.lua:
--------------------------------------------------------------------------------
1 | print(io.read("*n", "*n"))
2 |
--------------------------------------------------------------------------------
/bugs/multi-assignment.lua:
--------------------------------------------------------------------------------
1 | --#315
2 | local a = {}
3 | local d = 'e'
4 | local f = 1
5 |
6 | f, a.d = f, d
7 |
8 | print(f..", "..a.d)
9 |
--------------------------------------------------------------------------------
/bugs/self-assign.lua:
--------------------------------------------------------------------------------
1 | --#280
2 | function conver(str)
3 | str = f() and str or str
4 | print(type(str))
5 | end
6 | function f()
7 | return false
8 | end
9 | conver("main")
10 |
--------------------------------------------------------------------------------
/bugs/string_format_1.lua:
--------------------------------------------------------------------------------
1 | print(string.format("%"))
2 |
--------------------------------------------------------------------------------
/bugs/string_format_2.lua:
--------------------------------------------------------------------------------
1 | x = string.rep("x", 10000) .. "%d"
2 | print(string.format(x))
3 |
--------------------------------------------------------------------------------
/cmd/standalone/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "embed"
5 | "github.com/tongson/LadyLua"
6 | "github.com/tongson/gl"
7 | "github.com/yuin/gopher-lua"
8 | "os"
9 | "runtime"
10 | )
11 |
12 | //go:embed src/*
13 | var mainSrc embed.FS
14 |
15 | func main() {
16 | runtime.MemProfileRate = 0
17 | defer gl.RecoverPanic()
18 | L := lua.NewState()
19 | defer L.Close()
20 | ll.GlobalGo(L, "fs")
21 | ll.GlobalGo(L, "os")
22 | ll.GlobalGo(L, "extend")
23 | ll.GlobalGo(L, "exec")
24 | ll.PreloadGo(L, "http")
25 | ll.PreloadGo(L, "json")
26 | ll.PreloadGo(L, "crypto")
27 | ll.PreloadGo(L, "ksuid")
28 | ll.PreloadGo(L, "mysql")
29 | ll.PreloadGo(L, "lz4")
30 | ll.PreloadGo(L, "telegram")
31 | ll.PreloadGo(L, "pushover")
32 | ll.PreloadGo(L, "slack")
33 | ll.PreloadGo(L, "logger")
34 | ll.PreloadGo(L, "fsnotify")
35 | ll.PreloadGo(L, "bitcask")
36 | ll.PreloadGo(L, "refmt")
37 | ll.PreloadGo(L, "uuid")
38 | ll.PreloadGo(L, "ulid")
39 | ll.PreloadGo(L, "redis")
40 | ll.PreloadGo(L, "ssh_config")
41 | ll.Preload(L)
42 | ll.FillArg(L, os.Args)
43 | ll.Main(L, ll.ReadFile(mainSrc, "src/main.lua"))
44 | os.Exit(0)
45 | }
46 |
--------------------------------------------------------------------------------
/cmd/standalone/src/main.lua:
--------------------------------------------------------------------------------
1 | local argparse = require("argparse")
2 | local parser = argparse()
3 | parser:argument("first")
4 | parser:argument("second")
5 | local a = parser:parse(arg)
6 | print(a.first)
7 | print(a.second)
8 | os.exit(1)
9 |
--------------------------------------------------------------------------------
/cmd/test/src/main.lua:
--------------------------------------------------------------------------------
1 | local all = false
2 | if arg[1] == "all" then
3 | all = true
4 | end
5 | os.setenv("MYSQL_PASSWORD", "irbj0O3Bn1j8Ezja21NdfcMzj7ZFd2lz")
6 | local T = require("test")
7 | local errstr = function(tested, str, ...)
8 | local n, s = tested(...)
9 | if n ~= nil then
10 | return false, "First return value is not nil."
11 | end
12 | if nil == (string.find(s, str, 1, true)) then
13 | return false, string.format('Not found in error string: "%s".', str)
14 | end
15 | return true
16 | end
17 | T.register_assert("error", errstr)
18 |
19 | T["built-in => os.hostname"] = dofile("tests/os.lua")
20 | T["built-in => fmt"] = dofile("tests/fmt.lua")
21 | T["built-in => exec"] = dofile("tests/exec.lua")
22 | T["internal => lua"] = dofile("tests/lua.lua")
23 | T["extension => table"] = dofile("tests/extension_table.lua")
24 | T["extension => string"] = dofile("tests/extension_string.lua")
25 | T["extension => exec"] = dofile("tests/extension_exec.lua")
26 | T["module => list"] = dofile("tests/list.lua")
27 | T["module => guard"] = dofile("tests/guard.lua")
28 | T["module => queue"] = dofile("tests/queue.lua")
29 | T["module => map"] = dofile("tests/map.lua")
30 | T["module => tuple"] = dofile("tests/tuple.lua")
31 | T["module => graph"] = dofile("tests/graph.lua")
32 | T["module => object"] = dofile("tests/object.lua")
33 | T["module => date"] = dofile("tests/date.lua")
34 | T["module => csv"] = dofile("tests/csv.lua")
35 | T["module => ssh_config"] = dofile("tests/ssh_config.lua")
36 | T["module => ulid"] = dofile("tests/ulid.lua")
37 | T["module => refmt"] = dofile("tests/refmt.lua")
38 | T["module => bitcask"] = dofile("tests/bitcask.lua")
39 | T["module => fsnotify"] = dofile("tests/fsnotify.lua")
40 | T["module => logger"] = dofile("tests/logger.lua")
41 | T["module => lz4"] = dofile("tests/lz4.lua")
42 | if all then
43 | T["module => slack"] = dofile("tests/slack.lua")
44 | T["module => pushover"] = dofile("tests/pushover.lua")
45 | T["module => telegram"] = dofile("tests/telegram.lua")
46 | T["module => mysql"] = dofile("tests/mysql.lua")
47 | T["module => redis"] = dofile("tests/redis.lua")
48 | end
49 | T["module => ksuid"] = dofile("tests/ksuid.lua")
50 | T["module => tengattack/gluacrypto"] = dofile("tests/crypto.lua")
51 | T["module => leafo/etlua"] = dofile("tests/template.lua")
52 | T["module => layeh/gopher-json"] = dofile("tests/json.lua")
53 | T["extension => json"] = dofile("tests/extension_json.lua")
54 | T["module => cjoudrey/gluahttp"] = dofile("tests/http.lua")
55 | T["module => luarocks/argparse"] = dofile("tests/argparse.lua")
56 | T["global => extend"] = function()
57 | T.is_function(extend)
58 | end
59 | T["module => UIdalov/u-test"] = function()
60 | T.is_function(T.is_function)
61 | end
62 | T["built-in => fs"] = dofile("tests/fs.lua")
63 | T.summary()
64 |
--------------------------------------------------------------------------------
/docs/bitcask.adoc:
--------------------------------------------------------------------------------
1 | = bitcask
2 | :toc:
3 | :toc-placement!:
4 |
5 | Wrapper to https://git.mills.io/prologic/bitcask[Bitcask].
6 |
7 | [NOTE]
8 | ====
9 | Maximum key size is *64* bytes +
10 | Default maximum value size is *64* KiB
11 | ====
12 |
13 | toc::[]
14 |
15 | == *bitcask.open*(_String_[, _Number_]) -> _Userdata_
16 | Open a database. Creates a new database if it does not exists.
17 |
18 | === Arguments
19 | [options="header",width="72%"]
20 | |===
21 | |Type |Description
22 | |string |Path for directory hierarchy
23 | |number |Maximum value size in bytes; default 64KiB
24 | |===
25 |
26 | === Returns
27 | [options="header",width="72%"]
28 | |===
29 | |Type |Description
30 | |userdata |Database lock
31 | |===
32 |
33 | == *:put*(_String_, _String_) -> _Boolean_
34 | Write key-value to database.
35 |
36 | === Arguments
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |string |Key
41 | |string |Value
42 | |===
43 |
44 | === Returns
45 | [options="header",width="72%"]
46 | |===
47 | |Type |Description
48 | |boolean |`true` if succesful
49 | |===
50 |
51 | == *:keys*() -> _Table_
52 | List of keys in database.
53 |
54 | === Returns
55 | [options="header",width="72%"]
56 | |===
57 | |Type |Description
58 | |table |List of keys
59 | |===
60 |
61 | == *:get*(_String_) -> _String_
62 | Fetch value with matching key.
63 |
64 | === Arguments
65 | [options="header",width="72%"]
66 | |===
67 | |Type |Description
68 | |string |Key
69 | |===
70 |
71 | === Returns
72 | [options="header",width="72%"]
73 | |===
74 | |Type |Description
75 | |string |Value
76 | |===
77 |
78 | == *:has*(_String_) -> _Boolean_
79 | Returns true if the key exists in the database, false otherwise.
80 |
81 | === Arguments
82 | [options="header",width="72%"]
83 | |===
84 | |Type |Description
85 | |string |Key
86 | |===
87 |
88 | === Returns
89 | [options="header",width="72%"]
90 | |===
91 | |Type |Description
92 | |boolean |`true` if found, `false` otherwise
93 | |===
94 |
95 | == *:delete*(_String_) -> _Boolean_
96 | Delete key and value from database.
97 |
98 | === Arguments
99 | [options="header",width="72%"]
100 | |===
101 | |Type |Description
102 | |string |Key
103 | |===
104 |
105 | === Returns
106 | [options="header",width="72%"]
107 | |===
108 | |Type |Description
109 | |boolean |`true` if successful
110 | |===
111 |
112 | == *:sync*() -> _Boolean_
113 | Flush buffers to disk ensuring all data is written
114 |
115 | === Returns
116 | [options="header",width="72%"]
117 | |===
118 | |Type |Description
119 | |boolean |`true` if successful
120 | |===
121 |
122 | == *:close*() -> _Boolean_
123 | Release database lock.
124 |
125 | === Returns
126 | [options="header",width="72%"]
127 | |===
128 | |Type |Description
129 | |boolean |`true` if successful
130 | |===
131 |
--------------------------------------------------------------------------------
/docs/crypto.adoc:
--------------------------------------------------------------------------------
1 | = crypto
2 | :toc:
3 | :toc-placement!:
4 |
5 | Cryptography operations and base64 encoding/decoding. +
6 |
7 | Not in the global namespace. Load with `require('crypto')`.
8 |
9 | toc::[]
10 |
11 | == *crypto.base64_encode*(_String_) -> _String_
12 | Encode data to base64.
13 |
14 | === Arguments
15 | [width="72%"]
16 | |===
17 | |string |Data to encode
18 | |===
19 |
20 | === Returns
21 | [width="72%"]
22 | |===
23 | |string |Encoded base64 string
24 | |===
25 |
26 | == *crypto.base64_decode*(_String_) -> _String_
27 | Decode base64 string.
28 |
29 | === Arguments
30 | [width="72%"]
31 | |===
32 | |string |String to decode
33 | |===
34 |
35 | === Returns
36 | [width="72%"]
37 | |===
38 | |string |Decoded data
39 | |===
40 |
41 | == *crypto.crc32*(_String_[, _Boolean_]) -> _String_
42 | Perform CRC32 on data.
43 |
44 | === Arguments
45 | [width="72%"]
46 | |===
47 | |string |String to check
48 | |boolean|If `true`, returns raw bytes instead of the default hex encoding string
49 | |===
50 |
51 | === Returns
52 | [width="72%"]
53 | |===
54 | |string |Checksum
55 | |===
56 |
57 | == *crypto.sha256*(_String_[, _Boolean_]) -> _String_
58 | Compute the SHA256 hash code from data.
59 |
60 | === Arguments
61 | [width="72%"]
62 | |===
63 | |string |Data
64 | |boolean|If `true`, returns raw bytes instead of the default hex encoding string
65 | |===
66 |
67 | === Returns
68 | [width="72%"]
69 | |===
70 | |string |Hash code
71 | |===
72 |
73 | == *crypto.sha512*(_String_[, _Boolean_]) -> _String_
74 | Compute the SHA512 hash code from data.
75 |
76 | === Arguments
77 | [width="72%"]
78 | |===
79 | |string |Data
80 | |boolean|If `true`, returns raw bytes instead of the default hex encoding string
81 | |===
82 |
83 | === Returns
84 | [width="72%"]
85 | |===
86 | |string |Hash code
87 | |===
88 |
89 | == *crypto.hmac*(_String_, _String_, _String_[, _Boolean_]) -> _String_
90 | Data integrity and authenticity code computation.
91 |
92 | === Arguments
93 | [width="72%"]
94 | |===
95 | |string |Hash function, example: `sha256`
96 | |string |Message
97 | |string |Secret key
98 | |boolean|If `true`, returns raw bytes instead of the default hex encoding string
99 | |===
100 |
101 | === Returns
102 | [width="72%"]
103 | |===
104 | |string |Code
105 | |===
106 |
107 | == *crypto.valid_hmac*(_String_, _String_, _String_, _String_) -> _Boolean_
108 | Compare MACs in a way that avoids side-channel attacks.
109 |
110 | === Arguments
111 | [width="72%"]
112 | |===
113 | |string |Hash function, example: `sha256`
114 | |string |Message
115 | |string |Secret key
116 | |string |Raw output from crypto.hmac()
117 | |===
118 |
119 | === Returns
120 | [width="72%"]
121 | |===
122 | |boolean |`true` if valid
123 | |===
124 |
125 | == *crypto.random*([_Number_]) -> _String_
126 | Generate random Hexadecimal string.
127 |
128 | === Arguments
129 | [width="72%"]
130 | |===
131 | |number |Optional hexadecimal length, default: 8 (16 characters)
132 | |===
133 |
134 | === Returns
135 | [width="72%"]
136 | |===
137 | |string |Hexadecimal string
138 | |===
139 |
140 | == *crypto.fast_random*() -> _String_
141 | Generate random Hexadecimal string(16-character string).
142 |
143 | === Returns
144 | [width="72%"]
145 | |===
146 | |string |Hexadecimal string
147 | |===
148 |
--------------------------------------------------------------------------------
/docs/csv.adoc:
--------------------------------------------------------------------------------
1 | = csv
2 | :toc:
3 | :toc-placement!:
4 |
5 | Parse and encode CSV.
6 |
7 | toc::[]
8 |
9 | == *csv.parse*(_String_) -> _Table_
10 | Decode a CSV into a table.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |CSV
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |table |Table
24 | |===
25 |
26 | == *csv.encode*(_Table_) -> _String_
27 | Encode table into CSV string.
28 |
29 | === Arguments
30 | [options="header",width="72%"]
31 | |===
32 | |Type |Description
33 | |table |Table
34 | |===
35 |
36 | === Returns
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |string |CSV
41 | |===
42 |
--------------------------------------------------------------------------------
/docs/exec.adoc:
--------------------------------------------------------------------------------
1 | = exec
2 | :toc:
3 | :toc-placement!:
4 |
5 | Execute external programs.
6 |
7 | toc::[]
8 |
9 | == *exec.command*(_String_[, _Table_][, _Table_][, _Table_][, _String_][, _String_]) -> _Boolean_, _String_, _String_, _String_
10 | Execute a program. Base function of the the other functions in this module.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |Executable
17 | |table |Arguments
18 | |table |Environment
19 | |string |Working directory
20 | |string |STDIN
21 | |number |Timeout in seconds
22 | |===
23 |
24 | === Returns
25 | [options="header",width="72%"]
26 | |===
27 | |Type |Description
28 | |boolean |`true` if no errors encountered, `false` otherwise
29 | |string |STDOUT output from program
30 | |string |STDERR output from program
31 | |string |Error from Go
32 | |===
33 |
34 | == *exec.ctx*(_String_) -> _Function_
35 | Execute program under a context. The returned function takes a table(list) for arguments.
36 |
37 | === Arguments
38 | [options="header",width="72%"]
39 | |===
40 | |Type |Description
41 | |string |Executable
42 | |===
43 |
44 | === Returns
45 | [options="header",width="72%"]
46 | |===
47 | |Type |Description
48 | |function| A function that can be called and set values; the function also returns the same values as `exec.command`
49 | |===
50 |
51 | === Map
52 | [options="header",width="72%"]
53 | |===
54 | |Value |Description
55 | |env |Environment
56 | |cwd |Working directory
57 | |stdin |STDIN
58 | |timeout |Timeout in seconds
59 | |===
60 |
61 | === Example
62 | ----
63 | local ls = exec.ctx'/bin/ls'
64 | ls.env = {'LC_ALL=C'}
65 | local r, o = ls{'/tmp', '/dev'}
66 | ----
67 |
--------------------------------------------------------------------------------
/docs/extension_exec.adoc:
--------------------------------------------------------------------------------
1 | = extension: exec
2 | :toc:
3 | :toc-placement!:
4 |
5 | Additional functions for the exec namespace.
6 |
7 | To load and patch global `exec` namespace:
8 | ----
9 | extend("exec")
10 | ----
11 |
12 | toc::[]
13 |
14 | == *exec.cmd*(_String_) -> _Function_
15 | Execute program under a context. Difference with `exec.ctx` is this takes two additional settings; `errexit` and `error`. When `errexit` is set to `true`, the programs exits immediately when an error is encountered. The `error` setting takes a string to show when `errexit` is triggered. +
16 | The returned function's also accepts a format string OR a table(list) for building the argument.
17 |
18 | === Arguments
19 | [options="header",width="72%"]
20 | |===
21 | |Type |Description
22 | |string |Executable
23 | |===
24 |
25 | === Returns
26 | [options="header",width="72%"]
27 | |===
28 | |Type |Description
29 | |function| A function that can be called and set values; the function also returns the same values as `exec.command`
30 | |===
31 |
32 | === Map
33 | [options="header",width="72%"]
34 | |===
35 | |Value |Description
36 | |env |Environment
37 | |cwd |Working directory
38 | |stdin |STDIN
39 | |timeout |Timeout in seconds
40 | |errexit |Exit immediately when an error is encountered
41 | |error |Custom error message when errexit is triggered
42 | |===
43 |
44 | === Example
45 | ----
46 | local ls = exec.cmd'/bin/ls'
47 | ls.env = {'LC_ALL=C'}
48 | local tmp = '/tmp'
49 | local dev = '/dev'
50 | local r, o = ls('%s %s', tmp, dev)
51 | ----
52 |
53 | == *exec.run*(_String_) -> _Function_
54 | A quick way run programs if you only need to set arguments.
55 |
56 | === Arguments
57 | [options="header",width="72%"]
58 | |===
59 | |Type |Description
60 | |string |Executable
61 | |===
62 |
63 | === Returns
64 | [options="header",width="72%"]
65 | |===
66 | |Type |Description
67 | |function| A function that can be called; the function also returns the same values as `exec.command`
68 | |===
69 |
70 | === Example
71 | ----
72 | local rm = exec.run 'rm'
73 | rm'/tmp/test'
74 | ----
75 |
--------------------------------------------------------------------------------
/docs/extension_json.adoc:
--------------------------------------------------------------------------------
1 | = extension: json
2 | :toc:
3 | :toc-placement!:
4 |
5 | Additional functions for the `json` module.
6 |
7 | To load and patch `json` namespace:
8 | ----
9 | extend("json")
10 | ----
11 |
12 | toc::[]
13 |
14 | == *json.array*(_String_)
15 | JSON array iterator
16 |
17 | === Arguments
18 | [options="header",width="72%"]
19 | |===
20 | |Type |Description
21 | |string |JSON
22 | |===
23 |
24 | == *json.object*(_String_)
25 | JSON object iterator.
26 |
27 | === Arguments
28 | [options="header",width="72%"]
29 | |===
30 | |Type |Description
31 | |string |JSON
32 | |===
33 |
--------------------------------------------------------------------------------
/docs/fmt.adoc:
--------------------------------------------------------------------------------
1 | = fmt
2 | :toc:
3 | :toc-placement!:
4 |
5 | Format string variants that wraps `string.format`. +
6 |
7 | toc::[]
8 |
9 | == *fmt.print*(_String_, _..._)
10 | Print formatted string to io.stdout.
11 |
12 | === Arguments
13 | [width="72%"]
14 | |===
15 | |string| Format string
16 | |...| Values for the format string
17 | |===
18 |
19 | == *fmt.warn*(_String_, _..._)
20 | Print formatted string to io.stderr.
21 |
22 | === Arguments
23 | [width="72%"]
24 | |===
25 | |string| Format string
26 | |...| Values for the format string
27 | |===
28 |
29 | == *fmt.error*(_String_, _..._) -> _Nil_, _String_
30 | Shortcut for following the Lua convention of returning `nil` and `string` during error conditions.
31 |
32 | === Arguments
33 | [width="72%"]
34 | |===
35 | |string| Format string
36 | |...| Values for the format string
37 | |===
38 |
39 | === Returns
40 | [width="72%"]
41 | |===
42 | |nil| nil
43 | |string| Error message
44 | |===
45 |
46 | == *fmt.panic*(_String_, _..._)
47 | Print formatted string to io.stderr and exit immediately with code 1.
48 |
49 | === Arguments
50 | [width="72%"]
51 | |===
52 | |string| Format string
53 | |...| Values for the format string
54 | |===
55 |
56 | == *fmt.assert*(_Value_, _String_, _..._)
57 | Print formatted string to io.stderr and exit immediately with code 1 if argument #1 is falsy(nil or false).
58 |
59 | === Arguments
60 | [width="72%"]
61 | |===
62 | |value| Any Lua type that can return nil or false
63 | |string| Format string
64 | |...| Values for the format string
65 | |===
66 |
--------------------------------------------------------------------------------
/docs/fsnotify.adoc:
--------------------------------------------------------------------------------
1 | = fsnotify
2 | :toc:
3 | :toc-placement!:
4 |
5 | Wait for filesystem create, delete, and write events. All functions block until the specified event is detected.
6 |
7 | toc::[]
8 |
9 | == *fsnotify.create*(_String_) -> _Boolean_
10 | Wait for a create event on path.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |Path to wait on
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |boolean |`true` if create event happened
24 | |===
25 |
26 | == *fsnotify.write*(_String_) -> _Boolean_
27 | Wait for a write event on path.
28 |
29 | === Arguments
30 | [options="header",width="72%"]
31 | |===
32 | |Type |Description
33 | |string |Path to wait on
34 | |===
35 |
36 | === Returns
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |boolean |`true` if write event happened
41 | |===
42 |
43 | == *fsnotify.remove*(_String_) -> _Boolean_
44 | Wait for a remove event on path.
45 |
46 | === Arguments
47 | [options="header",width="72%"]
48 | |===
49 | |Type |Description
50 | |string |Path to wait on
51 | |===
52 |
53 | === Returns
54 | [options="header",width="72%"]
55 | |===
56 | |Type |Description
57 | |boolean |`true` if remove event happened
58 | |===
59 |
--------------------------------------------------------------------------------
/docs/go-helper.adoc:
--------------------------------------------------------------------------------
1 |
2 | == *ll.FillArg*(*lua.LState, []string)
3 | Capture command line arguments as the `arg` table in the global `_G` environment.
4 |
5 | === Arguments
6 | [width="72%"]
7 | |===
8 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
9 | |[]string |Usually `os.Args`
10 | |===
11 |
12 | == *ll.ReadFile*(embed.FS, string) -> string
13 | Read file from an `embed.FS` location.
14 |
15 | === Arguments
16 | [width="72%"]
17 | |===
18 | |embed.FS |Variable of embedded filesystem
19 | |string |Filename
20 | |===
21 |
22 | === Returns
23 | [width="72%"]
24 | |===
25 | |string |Contents of file
26 | |===
27 |
--------------------------------------------------------------------------------
/docs/go-loader.adoc:
--------------------------------------------------------------------------------
1 | = loader.go
2 | :toc:
3 | :toc-placement!:
4 |
5 | Module loaders.
6 |
7 | toc::[]
8 |
9 | == *ll.Preload*(*lua.LState)
10 | Add `package.loaders` entry for loading plain Lua modules from `internal/lua`. +
11 | This allows Lua code to `require()` these modules.
12 |
13 | == *ll.LoadPatch*(*lua.LState, string)
14 | For monkey-patching Lua values.
15 |
16 | [NOTE]
17 | ====
18 | Severely degrades VM start up time.
19 | ====
20 |
21 | === Arguments
22 | [width="72%"]
23 | |===
24 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
25 | |string |Basename of Lua source in `internal/lua`
26 | |===
27 |
28 | == *ll.LoadGlobalLua*(*lua.LState, string)
29 | For adding Lua values into the global `_G` environment.
30 |
31 | === Arguments
32 | [width="72%"]
33 | |===
34 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
35 | |string |Basename of Lua source in `internal/lua`
36 | |===
37 |
38 | == *ll.Main*(*lua.LState, string)
39 | The entrypoint(main) Lua code for standalone projects.
40 |
41 | === Arguments
42 | [width="72%"]
43 | |===
44 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
45 | |string |Lua source code
46 | |===
47 |
48 | == *ll.PreloadModule*(*lua.LState, string, string)
49 | Load plain Lua modules into `package.preload`. Useful for your own Lua modules loaded from standalone projects.
50 |
51 | === Arguments
52 | [width="72%"]
53 | |===
54 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
55 | |string |Name of the module
56 | |string |Lua source code
57 | |===
58 |
59 | == *ll.LoadGlobalGo*(*lua.LState, string)
60 | Load gopher-lua (Go) module into the global `_G` environment. +
61 |
62 | === Arguments
63 | [width="72%"]
64 | |===
65 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
66 | |string |Name of the module
67 | |===
68 |
69 | == *ll.PreloadGo*(*lua.LState, string)
70 | Load gopher-lua (Go) module into `package.preload`. +
71 |
72 | === Arguments
73 | [width="72%"]
74 | |===
75 | |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
76 | |string |Name of the module
77 | |===
78 |
--------------------------------------------------------------------------------
/docs/guard.adoc:
--------------------------------------------------------------------------------
1 | = guard
2 | :toc:
3 | :toc-placement!:
4 |
5 | Elixir-style guards. One way to avoid nested conditionals.
6 |
7 | toc::[]
8 |
9 | == *guard*() -> _Table_
10 | Returns new guard factory.
11 |
12 | === Returns
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |table |Guardian table
17 | |===
18 |
19 | == *.any*(_function_)
20 | Fallthrough for a guard chain.
21 |
22 | === Arguments
23 | [options="header",width="72%"]
24 | |===
25 | |type |description
26 | |function |Default case function
27 | |===
28 |
29 | == *.when*(_function_, _function_)
30 | Expects two functions arguments: the first one being a filter function, and the second one being a function to be evaluated. the filter function should return a boolean. if it returns `true`, the second function argument is evaluated and the guard returns itself right after.
31 |
32 | === Arguments
33 | [options="header",width="72%"]
34 | |===
35 | |type |description
36 | |function |filter
37 | |function |main function
38 | |===
39 |
--------------------------------------------------------------------------------
/docs/http.adoc:
--------------------------------------------------------------------------------
1 | = http
2 | :toc:
3 | :toc-placement!:
4 |
5 | Perform HTTP requests from Lua. From https://github.com/cjoudrey/gluahttp[gluahttp].
6 |
7 | toc::[]
8 |
9 | === Common Options Map
10 | [options="header",width="88%"]
11 | |===
12 | |Name |Type | Description
13 | |query |String | URL encoded query params
14 | |cookies |Table | Additional cookies to send with the request
15 | |headers |Table | Additional headers to send with the request
16 | |timeout |Number/String |Request timeout. Number of seconds or String such as "1h"
17 | |auth |Table |Username and password for HTTP basic auth. Table keys are *user* for username, *pass* for passwod. `auth={user="user", pass="pass"}`
18 | |===
19 |
20 | === Additional Options for HTTP POST, PUT, PATCH
21 | [options="header",width="88%"]
22 | |===
23 | |Name |Type | Description
24 | |body |String |Request body
25 | |===
26 |
27 | === Common Response Map
28 | [options="header",width="88%"]
29 | |===
30 | |Name | Type | Description
31 | |body | String | The HTTP response body
32 | |body_size | Number | The size of the HTTP response body in bytes
33 | |headers | Table | The HTTP response headers
34 | |cookies | Table | The cookies sent by the server in the HTTP response
35 | |status_code | Number | The HTTP response status code
36 | |url | String | The final URL the request ended pointing to after redirects
37 | |===
38 |
39 | == *http.get*(_String_, _Table_) -> _Table_
40 | HTTP GET.
41 |
42 | === Arguments
43 | [options="header",width="72%"]
44 | |===
45 | |Type |Description
46 | |string |URL
47 | |table |Options, see map above
48 | |===
49 |
50 | === Returns
51 | [options="header",width="72%"]
52 | |===
53 | |Type |Description
54 | |table |Response, see map above
55 | |===
56 |
57 | == *http.head*(_String_, _Table_) -> _Table_
58 | HTTP HEAD.
59 |
60 | === Arguments
61 | [options="header",width="72%"]
62 | |===
63 | |Type |Description
64 | |string |URL
65 | |table |Options, see map above
66 | |===
67 |
68 | === Returns
69 | [options="header",width="72%"]
70 | |===
71 | |Type |Description
72 | |table |Response, see map above
73 | |===
74 |
75 | == *http.delete*(_String_, _Table_) -> _Table_
76 | HTTP DELETE.
77 |
78 | === Arguments
79 | [options="header",width="72%"]
80 | |===
81 | |Type |Description
82 | |string |URL
83 | |table |Options, see map above
84 | |===
85 |
86 | === Returns
87 | [options="header",width="72%"]
88 | |===
89 | |Type |Description
90 | |table |Response, see map above
91 | |===
92 |
93 | == *http.patch*(_String_, _Table_) -> _Table_
94 | HTTP PATCH.
95 |
96 | === Arguments
97 | [options="header",width="72%"]
98 | |===
99 | |Type |Description
100 | |string |URL
101 | |table |Options, see map above
102 | |===
103 |
104 | === Returns
105 | [options="header",width="72%"]
106 | |===
107 | |Type |Description
108 | |table |Response, see map above
109 | |===
110 |
111 | == *http.put*(_String_, _Table_) -> _Table_
112 | HTTP PUT.
113 |
114 | === Arguments
115 | [options="header",width="72%"]
116 | |===
117 | |Type |Description
118 | |string |URL
119 | |table |Options, see map above
120 | |===
121 |
122 | === Returns
123 | [options="header",width="72%"]
124 | |===
125 | |Type |Description
126 | |table |Response, see map above
127 | |===
128 |
129 | == *http.post*(_String_, _Table_) -> _Table_
130 | HTTP POST.
131 |
132 | === Arguments
133 | [options="header",width="72%"]
134 | |===
135 | |Type |Description
136 | |string |URL
137 | |table |Options, see map above
138 | |===
139 |
140 | === Returns
141 | [options="header",width="72%"]
142 | |===
143 | |Type |Description
144 | |table |Response, see map above
145 | |===
146 |
--------------------------------------------------------------------------------
/docs/json.adoc:
--------------------------------------------------------------------------------
1 | = json
2 | :toc:
3 | :toc-placement!:
4 |
5 | JSON encoding and decoding of Lua values.
6 |
7 | toc::[]
8 |
9 | == *json.encode*(_Any_) -> _String_
10 | Encode value to JSON.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |any |Any value
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |string |JSON representation
24 | |===
25 |
26 | == *json.decode*(_String_) -> _Any_
27 | Decode JSON to Lua value
28 |
29 | === Arguments
30 | [options="header",width="72%"]
31 | |===
32 | |Type |Description
33 | |string |JSON string
34 | |===
35 |
36 | === Returns
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |any |Lua value
41 | |===
42 |
--------------------------------------------------------------------------------
/docs/list.adoc:
--------------------------------------------------------------------------------
1 | = list
2 | :toc:
3 | :toc-placement!:
4 |
5 | Doubly linked list data structures. Stores one instance of a value. Push tables for more leeway.
6 |
7 | toc::[]
8 |
9 | == *list.new*() -> _Table_
10 | Create a new list.
11 |
12 | === Returns
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |table |List
17 | |===
18 |
19 |
20 | == *:push_front*(_Value_)
21 | Push to beginning of list.
22 |
23 | === Arguments
24 | [options="header",width="72%"]
25 | |===
26 | |Type |Description
27 | |value |String, Boolean, Number, or Table
28 | |===
29 |
30 | == *:push_back*(_Value_)
31 | Push to end of list.
32 |
33 | Alias: `:push`
34 |
35 | === Arguments
36 | [options="header",width="72%"]
37 | |===
38 | |Type |Description
39 | |value |String, Boolean, Number, or Table
40 | |===
41 |
42 | == *:pop_front*() -> _Value_
43 | Pop value from beginning of list.
44 |
45 | === Returns
46 | [options="header",width="72%"]
47 | |===
48 | |Type |Description
49 | |value |String, Boolean, Number, or Table
50 | |===
51 |
52 | == *:pop_back*() -> _Value_
53 | Pop value from end of list.
54 |
55 | Alias: `:pop`
56 |
57 | === Returns
58 | [options="header",width="72%"]
59 | |===
60 | |Type |Description
61 | |value |String, Boolean, Number, or Table
62 | |===
63 |
64 | == *:contains*() -> _Boolean_
65 | Check if list contains an instance of number, string, or boolean
66 |
67 | === Returns
68 | [options="header",width="72%"]
69 | |===
70 | |Type |Description
71 | |boolean |`true` if value is found, `false` otherwise
72 | |===
73 |
74 | == *:size*() -> _Number_
75 | Count items in list.
76 |
77 | === Returns
78 | [options="header",width="72%"]
79 | |===
80 | |Type |Description
81 | |number |Count
82 | |===
83 |
84 | == *:front*() -> _Value_
85 | Return first value in the list. Does not pop() the value.
86 |
87 | === Returns
88 | [options="header",width="72%"]
89 | |===
90 | |Type |Description
91 | |value |Value
92 | |===
93 |
94 | == *:back*() -> _Value_
95 | Return last value in the list. Does not pop() the value.
96 |
97 | === Returns
98 | [options="header",width="72%"]
99 | |===
100 | |Type |Description
101 | |value |Value
102 | |===
103 |
104 | == *:walk*([_Boolean_]) -> _Iterator_
105 | Iterate over list.
106 |
107 | === Arguments
108 | [options="header",width="72%"]
109 | |===
110 | |Type |Description
111 | |boolean |if `false`, does a reverse iteration
112 | |===
113 |
114 | == *:range*(_Number_, _Number_) -> _Table_
115 | Return a table for ranged iteration.
116 |
117 | === Arguments
118 | [options="header",width="72%"]
119 | |===
120 | |Type |Description
121 | |number |Index start
122 | |number |Index end
123 | |===
124 |
125 | === Returns
126 | [options="header",width="72%"]
127 | |===
128 | |Type |Description
129 | |table |Table with values
130 | |===
131 |
--------------------------------------------------------------------------------
/docs/logger.adoc:
--------------------------------------------------------------------------------
1 | = logger
2 | :toc:
3 | :toc-placement!:
4 |
5 | Structured logging to STDERR, STDOUT, or file.
6 | A https://github.com/rs/zerolog[zerolog] wrapper.
7 |
8 | toc::[]
9 |
10 | == *logger.new*() -> _Userdata_
11 |
12 | Initialize object to access methods below.
13 |
14 | === Arguments
15 | [options="header",width="72%"]
16 | |===
17 | |Type |Description
18 | |string |`stdout`, `stderr`, or path to a file, default is `stderr`
19 | |===
20 |
21 | === Returns
22 | [options="header",width="72%"]
23 | |===
24 | |Type |Description
25 | |userdata| Userdata with methods below
26 | |===
27 |
28 | == *logger.time*() -> _String_
29 |
30 | Get same timestamp format used in logs.
31 |
32 | === Returns
33 | [options="header",width="72%"]
34 | |===
35 | |Type |Description
36 | |string| Timestamp
37 | |===
38 |
39 | == *:{info, debug, warn, error}* (_String_, _Table_)
40 |
41 | Log to specified log level.
42 |
43 | === Arguments
44 | [options="header",width="72%"]
45 | |===
46 | |Type |Description
47 | |string| message
48 | |table | key-value map
49 | |===
50 |
--------------------------------------------------------------------------------
/docs/lz4.adoc:
--------------------------------------------------------------------------------
1 | = lz4
2 | :toc:
3 | :toc-placement!:
4 |
5 | LZ4 compression and decompression.
6 |
7 | toc::[]
8 |
9 | == *lz4.compress*(_String_) -> _String_
10 | Compress data.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |Data
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |string |Compressed binary data
24 | |===
25 |
26 | == *lz4.decompress*(_String_) -> _String_
27 | Decompress lz4 data.
28 |
29 | === Arguments
30 | [options="header",width="72%"]
31 | |===
32 | |Type |Description
33 | |string |Compressed
34 | |===
35 |
36 | === Returns
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |string |Decompressed data
41 | |===
42 |
--------------------------------------------------------------------------------
/docs/map.adoc:
--------------------------------------------------------------------------------
1 | = map
2 | :toc:
3 | :toc-placement!:
4 |
5 | Bidirectional map implementation.
6 |
7 | toc::[]
8 |
9 | == *map.new*() -> _Table_, _Table_
10 | Create a new map.
11 |
12 | === Returns
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |table |Array side
17 | |table |Map side
18 | |===
19 |
--------------------------------------------------------------------------------
/docs/mysql.adoc:
--------------------------------------------------------------------------------
1 | = mysql
2 | :toc:
3 | :toc-placement!:
4 |
5 | Access MySQL or MariaDB databases.
6 |
7 | toc::[]
8 |
9 | == *mysql.escape*(_String_) -> _String_
10 | Escape a query.
11 |
12 | == *mysql.new*
13 | Initialize mysql instance.
14 |
15 | === Returns
16 | [options="header",width="72%"]
17 | |===
18 | |Type |Description
19 | |object |Instance of mysql that you can index into
20 | |===
21 |
22 | == *close*
23 | Close mysql instance.
24 |
25 | == *set_timeout*(_Number_)
26 | Set timeout.
27 |
28 | === Arguments
29 | [options="header",width="72%"]
30 | |===
31 | |Type |Description
32 | |number |Timeout in ms
33 | |===
34 |
35 | == *set_keepalive*(_Number_, _Number_)
36 |
37 | === Arguments
38 | [options="header",width="72%"]
39 | |===
40 | |Type |Description
41 | |number |Timeout in ms
42 | |number |Max idle connections(poolSize)
43 | |===
44 |
45 | == *connect*(_Table_)
46 |
47 | === Arguments
48 | [options="header",width="72%"]
49 | |===
50 | |Type |Description
51 | |table |See map below
52 | |===
53 |
54 | === Map
55 | [options="header",width="72%"]
56 | |===
57 | |host |
58 | |port |
59 | |database |
60 | |user |
61 | |password |
62 | |===
63 |
64 | == *query*(_String_[, ...]) -> _Table_
65 |
66 | === Arguments
67 | [options="header",width="72%"]
68 | |===
69 | |Type |Description
70 | |string |SQL query
71 | |===
72 |
73 | === Returns
74 | [options="header",width="72%"]
75 | |===
76 | |Type |Description
77 | |table |Query results, empty table if no results
78 | |===
79 |
--------------------------------------------------------------------------------
/docs/os.adoc:
--------------------------------------------------------------------------------
1 | = os
2 | :toc:
3 | :toc-placement!:
4 |
5 | Extensions to the `os` namespace.
6 |
7 | toc::[]
8 |
9 | == *os.hostname*() -> _String_
10 | Get current hostname.
11 |
12 | === Returns
13 | [width="72%"]
14 | |===
15 | |string |Hostname
16 | |===
17 |
18 | == *os.outbound_ip*() -> _String_
19 | Get IP used for outbound connections.
20 |
21 | === Returns
22 | [width="72%"]
23 | |===
24 | |string |IP
25 | |===
26 |
27 | == *os.sleep(_Number_) -> _Boolean_
28 | Sleep for a number of milliseconds.
29 |
30 | === Arguments
31 | [width="72%"]
32 | |===
33 | |number |Milliseconds
34 | |===
35 |
36 | === Returns
37 | [width="72%"]
38 | |===
39 | |boolean |`true`
40 | |===
41 |
42 | == *os.setenv*(_String_, _String_) -> _Boolean_
43 | Set environment variable.
44 |
45 | === Arguments
46 | [width="72%"]
47 | |===
48 | |string |Variable
49 | |string |Value
50 | |===
51 |
52 | === Returns
53 | [width="72%"]
54 | |===
55 | |boolean |`true` if successful
56 | |===
57 |
--------------------------------------------------------------------------------
/docs/pushover.adoc:
--------------------------------------------------------------------------------
1 | = pushover
2 | :toc:
3 | :toc-placement!:
4 |
5 | Send Pushover messages via the API.
6 |
7 | toc::[]
8 |
9 | == *pushover.new*()
10 |
11 | Initialize object to access methods below. Requires a valid token in the environment variable `PUSHOVER_TOKEN`.
12 |
13 | === Returns
14 | [options="header",width="72%"]
15 | |===
16 | |Type |Description
17 | |userdata| Userdata with methods below
18 | |===
19 |
20 | == *:message*(_String_, _String_)
21 |
22 | Send a message to device.
23 |
24 | === Arguments
25 | [options="header",width="72%"]
26 | |===
27 | |Type |Description
28 | |string| Device ID
29 | |string| message
30 | |===
31 |
32 | === Returns
33 | [options="header",width="72%"]
34 | |===
35 | |Type |Description
36 | |string| Response from API
37 | |===
38 |
--------------------------------------------------------------------------------
/docs/refmt.adoc:
--------------------------------------------------------------------------------
1 | = refmt
2 | :toc:
3 | :toc-placement!:
4 |
5 | Convert between JSON and YAML.
6 |
7 | toc::[]
8 |
9 | == *refmt.json_to_yaml*(_String_) -> _String_
10 | Convert JSON to YAML.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |JSON
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |string |YAML
24 | |===
25 |
26 | == *refmt.yaml_to_json*(_String_) -> _String_
27 | Convert YAML to JSON.
28 |
29 | === Arguments
30 | [options="header",width="72%"]
31 | |===
32 | |Type |Description
33 | |string |YAML
34 | |===
35 |
36 | === Returns
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |string |JSON
41 | |===
42 |
43 | == *refmt.toml_to_json*(_String_) -> _String_
44 | Convert TOML to JSON.
45 |
46 | === Arguments
47 | [options="header",width="72%"]
48 | |===
49 | |Type |Description
50 | |string |TOML
51 | |===
52 |
53 | === Returns
54 | [options="header",width="72%"]
55 | |===
56 | |Type |Description
57 | |string |JSON
58 | |===
59 |
60 | == *refmt.json_to_toml*(_String_) -> _String_
61 | Convert JSON to TOML.
62 |
63 | === Arguments
64 | [options="header",width="72%"]
65 | |===
66 | |Type |Description
67 | |string |JSON
68 | |===
69 |
70 | === Returns
71 | [options="header",width="72%"]
72 | |===
73 | |Type |Description
74 | |string |TOML
75 | |===
76 |
--------------------------------------------------------------------------------
/docs/slack.adoc:
--------------------------------------------------------------------------------
1 | = slack
2 | :toc:
3 | :toc-placement!:
4 |
5 | Wrapper for the Slack API.
6 |
7 | toc::[]
8 |
9 | == *slack.message*(_String_) -> _Boolean_
10 | Send webhook text. Requires the string after the `https://hooks.slack.com/services/` URL in the `SLACK_WEBHOOK` environment variable.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |Message
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |boolean| `true` if successful
24 | |===
25 | == *slack.attachment*(_Table_) -> _Boolean_
26 | Send webhook attachment containing values from the argument. Requires the string after the `https://hooks.slack.com/services/` URL in the `SLACK_WEBHOOK` environment variable.
27 |
28 | === Arguments
29 | [options="header",width="72%"]
30 | |===
31 | |Type |Description
32 | |table |See valid values from https://github.com/slack-go/slack[repo]
33 | |===
34 |
35 | === Returns
36 | [options="header",width="72%"]
37 | |===
38 | |Type |Description
39 | |boolean| `true` if successful
40 | |===
41 |
--------------------------------------------------------------------------------
/docs/ssh_config.adoc:
--------------------------------------------------------------------------------
1 | = ssh_config
2 | :toc:
3 | :toc-placement!:
4 |
5 | Get values from ~/.ssh/config
6 |
7 | toc::[]
8 |
9 | == *ssh_config.port*(_String_) -> _String_
10 | Get configured Port for Host.
11 |
12 | === Arguments
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |Host
17 | |===
18 |
19 | === Returns
20 | [options="header",width="72%"]
21 | |===
22 | |Type |Description
23 | |string |Port
24 | |===
25 |
26 | == *ssh_config.hostname*(_String_) -> _String_
27 | Get configured Hostname for Host.
28 |
29 | === Arguments
30 | [options="header",width="72%"]
31 | |===
32 | |Type |Description
33 | |string |Host
34 | |===
35 |
36 | === Returns
37 | [options="header",width="72%"]
38 | |===
39 | |Type |Description
40 | |string |Hostname
41 | |===
42 |
43 | == *ssh_config.identity_file*(_String_) -> _String_
44 | Get configured IdentityFile for Host.
45 |
46 | === Arguments
47 | [options="header",width="72%"]
48 | |===
49 | |Type |Description
50 | |string |Host
51 | |===
52 |
53 | === Returns
54 | [options="header",width="72%"]
55 | |===
56 | |Type |Description
57 | |string |Path of key
58 | |===
59 |
60 | == *ssh_config.hosts*() -> _Table_
61 | Get all hosts configured in ~/.ssh/config
62 |
63 | === Returns
64 | [options="header",width="72%"]
65 | |===
66 | |Type |Description
67 | |table|List of hosts
68 | |===
69 |
--------------------------------------------------------------------------------
/docs/telegram.adoc:
--------------------------------------------------------------------------------
1 | = telegram
2 | :toc:
3 | :toc-placement!:
4 |
5 | Send Telegram messages via the Bot API.
6 |
7 | toc::[]
8 |
9 | == *telegram.new*()
10 |
11 | Initialize object to access methods below. Requires a valid BOT token in the environment variable `TELEGRAM_TOKEN`.
12 |
13 | === Returns
14 | [options="header",width="72%"]
15 | |===
16 | |Type |Description
17 | |userdata| Userdata containing methods below
18 | |===
19 |
20 | == *:channel*(_String_, _String_)
21 |
22 | Post a channel message.
23 |
24 | === Arguments
25 | [options="header",width="72%"]
26 | |===
27 | |Type |Description
28 | |string| channel id e.g. "-12312313"
29 | |string| message
30 | |===
31 |
32 | === Returns
33 | [options="header",width="72%"]
34 | |===
35 | |Type |Description
36 | |boolean| true
37 | |===
38 |
39 |
40 | == *:message*(_String_, _String_)
41 |
42 | Send a message to Telegram user.
43 |
44 | === Arguments
45 | [options="header",width="72%"]
46 | |===
47 | |Type |Description
48 | |number| user id e.g. 9348484
49 | |string| message
50 | |===
51 |
52 | === Returns
53 | [options="header",width="72%"]
54 | |===
55 | |Type |Description
56 | |boolean| true
57 | |===
58 |
--------------------------------------------------------------------------------
/docs/template.adoc:
--------------------------------------------------------------------------------
1 | = template
2 | :toc:
3 | :toc-placement!:
4 |
5 | Embedded Lua templating. This is etlua(github.com/leafo/etlua). +
6 |
7 | Not in the global namespace. Load with `require('template')`.
8 |
9 | toc::[]
10 |
11 | == *template.compile*(_String_) -> _Function_
12 | Compiles the template into a function, the returned function can be called to render the template. The function takes one argument: a table to use as the environment within the template. `_G` is used to look up a variable if it can't be found in the environment.
13 |
14 | === Arguments
15 | [width="72%"]
16 | |===
17 | |string| String to compile
18 | |===
19 |
20 | === Returns
21 | [width="72%"]
22 | |===
23 | |function| (_Table_) -> _String_
24 | |===
25 |
26 | == *template.render*(_String_, _Table_) -> _String_
27 | Compiles and renders the template in a single call. If you are concerned about high performance this should be avoided in favor of `compile` if it's possible to cache the compiled template.
28 |
29 | === Arguments
30 | [width="72%"]
31 | |===
32 | |string| String to compile
33 | |===
34 |
35 | === Returns
36 | [width="72%"]
37 | |===
38 | |function| (_Table_) -> _String_
39 | |===
40 |
41 | :note-caption: :information_source:
42 | [NOTE]
43 | ====
44 | Documentation and tests from etlua project page.
45 | Check github.com/leafo/etlua for information on the `Parser` raw API.
46 | ====
47 |
--------------------------------------------------------------------------------
/docs/tuple.adoc:
--------------------------------------------------------------------------------
1 | = tuple
2 | :toc:
3 | :toc-placement!:
4 |
5 | Implementation of ordered n-tuples.
6 |
7 | . Fixed sized
8 | . May contain `nil`
9 | . Values can be changed for existing keys
10 | . Tables passed are copied
11 | . Maximum of 199 values
12 |
13 | toc::[]
14 |
15 | == *tuple([...])* -> _Table_
16 | Create a new tuple.
17 |
18 | === Returns
19 | [options="header",width="72%"]
20 | |===
21 | |Type |Description
22 | |table |Tuple
23 | |===
24 |
25 | == *:iterator()*
26 | Iterator function to traverse a tuple. Returns a count and a value at each step of iteration, until the end of the tuple is reached.
27 |
28 | Use this instead of `ipairs` since the tuple may contain `nil`.
29 |
30 | == *:includes(_Table_)* -> _Boolean_
31 | Returns `true` if the tuple argument is included in the tuple, i.e when all elements found in tuple argument were found in the original tuple. Otherwise, returns `false`.
32 |
33 | === Arguments
34 | [options="header",width="72%"]
35 | |===
36 | |Type |Description
37 | |table |Tuple
38 | |===
39 |
40 | === Returns
41 | [options="header",width="72%"]
42 | |===
43 | |Type |Description
44 | |boolean |Result
45 | |===
46 |
47 | == *:has(_Table_)* -> _Boolean_
48 | Returns `true` when the given value was found in the tuple. Otherwhise, returns `false`.
49 |
50 | === Arguments
51 | [options="header",width="72%"]
52 | |===
53 | |Type |Description
54 | |value |Any valid value for comparison
55 | |===
56 |
57 | === Returns
58 | [options="header",width="72%"]
59 | |===
60 | |Type |Description
61 | |boolean |Result
62 | |===
63 |
64 | == *:size(_Table_)* -> _Number_
65 | Returns the size (the count of values) of the tuple.
66 |
67 | === Returns
68 | [options="header",width="72%"]
69 | |===
70 | |Type |Description
71 | |number |Size of tuple
72 | |===
73 |
74 | == *:contents(_Table_)* -> _Table_
75 | Converts the tuple contents to a read-only array.
76 |
77 | [NOTE]
78 | ====
79 | Lower level tables can be modified.
80 | ====
81 |
82 | === Arguments
83 | [options="header",width="72%"]
84 | |===
85 | |Type |Description
86 | |table |Tuple
87 | |===
88 |
89 | === Returns
90 | [options="header",width="72%"]
91 | |===
92 | |Type |Description
93 | |table |New table
94 | |===
95 |
--------------------------------------------------------------------------------
/docs/uid.adoc:
--------------------------------------------------------------------------------
1 | = uid
2 | :toc:
3 | :toc-placement!:
4 |
5 | Generate unique IDs. This is a https://github.com/segmentio/ksuid[ksuid] wrapper.
6 |
7 | toc::[]
8 |
9 | == *uid.new*() -> _String_
10 | Generate an ID.
11 |
12 | === Returns
13 | [options="header",width="72%"]
14 | |===
15 | |Type |Description
16 | |string |ksuid string
17 | |===
18 |
--------------------------------------------------------------------------------
/docs/ulid.adoc:
--------------------------------------------------------------------------------
1 | = ulid
2 | :toc:
3 | :toc-placement!:
4 |
5 | Generate random strings in ULID format.
6 | This is a https://github.com/oklog/ulid/[ulid] wrapper.
7 |
8 | toc::[]
9 |
10 | == *ulid.new*() -> _String_
11 | Generate an ID.
12 |
13 | === Returns
14 | [options="header",width="72%"]
15 | |===
16 | |Type |Description
17 | |string |ULID string
18 | |===
19 |
--------------------------------------------------------------------------------
/docs/uuid.adoc:
--------------------------------------------------------------------------------
1 | = uuid
2 | :toc:
3 | :toc-placement!:
4 |
5 | Generate random strings in UUID format.
6 | This is a https://github.com/hashicorp/go-uuid[go-uuid] wrapper.
7 |
8 | toc::[]
9 |
10 | == *uuid.new*() -> _String_
11 | Generate an ID.
12 |
13 | === Returns
14 | [options="header",width="72%"]
15 | |===
16 | |Type |Description
17 | |string |uuid string
18 | |===
19 |
--------------------------------------------------------------------------------
/dsl.go:
--------------------------------------------------------------------------------
1 | // +build dsl
2 | package ll
3 |
4 | import (
5 | "embed"
6 | "fmt"
7 |
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | //go:embed internal/dsl/*
12 | var dslSrc embed.FS
13 |
14 | func DslLoader(L *lua.LState, mod string) {
15 | src, _ := dslSrc.ReadFile(fmt.Sprintf("internal/dsl/%s.lua", mod))
16 | fn, _ := L.LoadString(string(src))
17 | L.Push(fn)
18 | L.Call(0, 0)
19 | }
20 |
--------------------------------------------------------------------------------
/external/gluacrypto/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/base64.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "encoding/base64"
5 |
6 | lua "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func base64EncodeFn(L *lua.LState) int {
10 | s := lua.LVAsString(L.Get(1))
11 | result := base64.StdEncoding.EncodeToString([]byte(s))
12 | L.Push(lua.LString(result))
13 | return 1
14 | }
15 |
16 | func base64DecodeFn(L *lua.LState) int {
17 | s := lua.LVAsString(L.Get(1))
18 | result, err := base64.StdEncoding.DecodeString(s)
19 | if err != nil {
20 | L.Push(lua.LNil)
21 | L.Push(lua.LString(err.Error()))
22 | return 2
23 | }
24 | L.Push(lua.LString(result))
25 | return 1
26 | }
27 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/ch.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "encoding/hex"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 | "unicode/utf8"
9 |
10 | "github.com/yuin/gopher-lua"
11 | )
12 |
13 | // xor
14 | // xor two numbers
15 | // (number, number) -> (number)
16 | func xorFn(L *lua.LState) int {
17 | i := L.CheckNumber(1)
18 | x := L.CheckNumber(2)
19 | L.Push(lua.LNumber(uint8(i) ^ uint8(x)))
20 | return 1
21 | }
22 |
23 | // htos
24 | // Hexadecimal string to string
25 | // (string) -> string
26 | func hextostrFn(L *lua.LState) int {
27 | h := L.CheckString(1)
28 | decodedByteArray, err := hex.DecodeString(h)
29 | if err != nil {
30 | L.Push(lua.LNil)
31 | L.Push(lua.LString(err.Error()))
32 | return 2
33 | }
34 | L.Push(lua.LString(string(decodedByteArray)))
35 | return 1
36 | }
37 |
38 | // stoh
39 | // String to Hexadecimal string
40 | // (string) -> string
41 | func strtohexFn(L *lua.LState) int {
42 | h := L.CheckString(1)
43 | encodedString := hex.EncodeToString([]byte(h))
44 | L.Push(lua.LString(encodedString))
45 | return 1
46 | }
47 |
48 | // htoi
49 | // Hexadecimal string to int
50 | // (string) -> number
51 | func hextointFn(L *lua.LState) int {
52 | h := L.CheckString(1)
53 | value, err := strconv.ParseInt(h, 16, 64)
54 | if err != nil {
55 | L.Push(lua.LNil)
56 | L.Push(lua.LString(err.Error()))
57 | return 2
58 | }
59 | L.Push(lua.LNumber(value))
60 | return 1
61 | }
62 |
63 | // htot
64 | // Hexadecimal string to int array
65 | // (string) -> table[number]
66 | func hextotblFn(L *lua.LState) int {
67 | h := L.CheckString(1)
68 | decodedByteArray, err := hex.DecodeString(h)
69 | if err != nil {
70 | L.Push(lua.LNil)
71 | L.Push(lua.LString(err.Error()))
72 | return 2
73 | }
74 | t := L.NewTable()
75 | for _, element := range decodedByteArray {
76 | t.Append(lua.LNumber(element))
77 | }
78 | L.Push(t)
79 | return 1
80 | }
81 |
82 | // hexor
83 | // XOR two hex strings
84 | // (string, string) -> string, table[number]
85 | func hexorFn(L *lua.LState) int {
86 | a := L.CheckString(1)
87 | b := L.CheckString(2)
88 | aa, err := hex.DecodeString(a)
89 | if err != nil {
90 | L.Push(lua.LNil)
91 | L.Push(lua.LString(err.Error()))
92 | return 2
93 | }
94 | ba, err := hex.DecodeString(b)
95 | if err != nil {
96 | L.Push(lua.LNil)
97 | L.Push(lua.LString(err.Error()))
98 | return 2
99 | }
100 | hexa := strings.Builder{}
101 | var ax *[]byte
102 | var bx *[]byte
103 | var sz int
104 | la := len(aa)
105 | lb := len(ba)
106 | switch la > lb {
107 | case true:
108 | ax = &aa
109 | bx = &ba
110 | sz = lb - 1
111 | case false:
112 | ax = &ba
113 | bx = &aa
114 | sz = la - 1
115 | }
116 | t := L.NewTable()
117 | var r int = 0
118 | var v uint8
119 | for _, element := range *ax {
120 | v = element ^ (*bx)[r]
121 | hexa.WriteString(fmt.Sprintf("%02x", v))
122 | t.Append(lua.LNumber(v))
123 | if r < sz {
124 | r++
125 | } else {
126 | r = 0
127 | }
128 | }
129 | L.Push(lua.LString(hexa.String()))
130 | L.Push(t)
131 | return 2
132 | }
133 |
134 | // ord
135 | func ordFn(L *lua.LState) int {
136 | s := L.CheckString(1)
137 | r, _ := utf8.DecodeRuneInString(s)
138 | L.Push(lua.LNumber(r))
139 | return 1
140 | }
141 |
142 | // char
143 | func charFn(L *lua.LState) int {
144 | L.Push(lua.LString(string(int32(L.CheckNumber(1)))))
145 | return 1
146 | }
147 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/crc32.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "encoding/hex"
5 | "hash/crc32"
6 |
7 | lua "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func crc32Fn(L *lua.LState) int {
11 | h := crc32.NewIEEE()
12 | s := lua.LVAsString(L.Get(1))
13 | raw := lua.LVAsBool(L.Get(2))
14 | _, err := h.Write([]byte(s))
15 | if err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString(err.Error()))
18 | return 2
19 | }
20 |
21 | var result string
22 | if !raw {
23 | result = hex.EncodeToString(h.Sum(nil))
24 | } else {
25 | result = string(h.Sum(nil))
26 | }
27 | L.Push(lua.LString(result))
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/crypto.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | lua "github.com/yuin/gopher-lua"
5 | )
6 |
7 | var exports = map[string]lua.LGFunction{
8 | "base64_encode": base64EncodeFn,
9 | "base64_decode": base64DecodeFn,
10 | "crc32": crc32Fn,
11 | "md5": md5Fn,
12 | "sha1": sha1Fn,
13 | "sha256": sha256Fn,
14 | "sha512": sha512Fn,
15 | "hmac": hmacFn,
16 | "valid_hmac": validHmacFn,
17 | "encrypt": encryptFn,
18 | "decrypt": decryptFn,
19 | "random": randomFn,
20 | "fast_random": fastRandomFn,
21 | "xor": xorFn,
22 | "stoh": strtohexFn,
23 | "htos": hextostrFn,
24 | "htoi": hextointFn,
25 | "htot": hextotblFn,
26 | "hexor": hexorFn,
27 | "ord": ordFn,
28 | "char": charFn,
29 | }
30 |
31 | func Loader(L *lua.LState) int {
32 | mod := L.SetFuncs(L.NewTable(), exports)
33 | L.Push(mod)
34 |
35 | L.SetField(mod, "_DEBUG", lua.LBool(false))
36 | L.SetField(mod, "_VERSION", lua.LString("0.0.0"))
37 |
38 | // consts
39 | L.SetField(mod, "RAW_DATA", lua.LNumber(1))
40 | L.SetField(mod, "ZERO_PADDING", lua.LNumber(2))
41 |
42 | return 1
43 | }
44 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/decrypt.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/aes"
5 | "crypto/cipher"
6 | "crypto/des"
7 | "encoding/hex"
8 | "errors"
9 |
10 | lua "github.com/yuin/gopher-lua"
11 | )
12 |
13 | // PKCS5Unpadding unpad data
14 | func PKCS5Unpadding(origData []byte) []byte {
15 | length := len(origData)
16 | unpadding := int(origData[length-1])
17 | return origData[:(length - unpadding)]
18 | }
19 |
20 | // Decrypt data by specified method: `des-ecb`, `des-cbc`, `aes-cbc`
21 | func Decrypt(data []byte, method string, key, iv []byte) ([]byte, error) {
22 | var out []byte
23 | switch method {
24 | case "des-ecb":
25 | block, err := des.NewCipher([]byte(key))
26 | if err != nil {
27 | return nil, err
28 | }
29 |
30 | bs := block.BlockSize()
31 | if len(data)%bs != 0 {
32 | return nil, errors.New("crypto/cipher: input not full blocks")
33 | }
34 |
35 | out = make([]byte, len(data))
36 | dst := out
37 | for len(data) > 0 {
38 | block.Decrypt(dst, data[:bs])
39 | data = data[bs:]
40 | dst = dst[bs:]
41 | }
42 | out = PKCS5Unpadding(out)
43 | case "des-cbc":
44 | block, err := des.NewCipher([]byte(key))
45 | if err != nil {
46 | return nil, err
47 | }
48 |
49 | // CBC mode always works in whole blocks.
50 | if len(data)%block.BlockSize() != 0 {
51 | return nil, ErrCiphertextNotMultipleBlockSize
52 | }
53 |
54 | mode := cipher.NewCBCDecrypter(block, []byte(iv))
55 | plaintext := make([]byte, len(data))
56 | mode.CryptBlocks(plaintext, data)
57 | out = PKCS5Unpadding(plaintext)
58 | case "aes-cbc":
59 | block, err := aes.NewCipher([]byte(key))
60 | if err != nil {
61 | return nil, err
62 | }
63 |
64 | // CBC mode always works in whole blocks.
65 | if len(data)%block.BlockSize() != 0 {
66 | return nil, ErrCiphertextNotMultipleBlockSize
67 | }
68 |
69 | mode := cipher.NewCBCDecrypter(block, []byte(iv))
70 | plaintext := make([]byte, len(data))
71 | mode.CryptBlocks(plaintext, data)
72 | out = PKCS5Unpadding(plaintext)
73 | default:
74 | return nil, ErrNotSupport
75 | }
76 | return out, nil
77 | }
78 |
79 | func decryptFn(L *lua.LState) int {
80 | s := lua.LVAsString(L.Get(1))
81 | method := lua.LVAsString(L.Get(2))
82 | key := lua.LVAsString(L.Get(3))
83 | options := L.ToInt(4)
84 | iv := lua.LVAsString(L.Get(5))
85 |
86 | var data []byte
87 | var err error
88 | if options&RawData == 0 {
89 | data, err = hex.DecodeString(s)
90 | } else {
91 | data = []byte(s)
92 | }
93 | if err != nil {
94 | L.Push(lua.LNil)
95 | L.Push(lua.LString(err.Error()))
96 | return 2
97 | }
98 |
99 | out, err := Decrypt(data, method, []byte(key), []byte(iv))
100 | if err != nil {
101 | L.Push(lua.LNil)
102 | L.Push(lua.LString(err.Error()))
103 | return 2
104 | }
105 |
106 | L.Push(lua.LString(out))
107 | return 1
108 | }
109 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/encrypt.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "bytes"
5 | "crypto/aes"
6 | "crypto/cipher"
7 | "crypto/des"
8 | "encoding/hex"
9 | "errors"
10 |
11 | lua "github.com/yuin/gopher-lua"
12 | )
13 |
14 | // options const
15 | const (
16 | RawData = 1 << iota
17 | // not implement
18 | // ZeroPadding = 1 << iota
19 | )
20 |
21 | // errors
22 | var (
23 | ErrNotSupport = errors.New("unsupported encrypt method")
24 | ErrCiphertextNotMultipleBlockSize = errors.New("ciphertext is not a multiple of the block size")
25 | )
26 |
27 | // PKCS5Padding pad data
28 | func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
29 | padding := blockSize - len(ciphertext)%blockSize
30 | padtext := bytes.Repeat([]byte{byte(padding)}, padding)
31 | return append(ciphertext, padtext...)
32 | }
33 |
34 | // Encrypt data by specified method: `des-ecb`, `des-cbc`, `aes-cbc`
35 | func Encrypt(data []byte, method string, key, iv []byte) ([]byte, error) {
36 | var out []byte
37 | switch method {
38 | case "des-ecb":
39 | block, err := des.NewCipher(key)
40 | if err != nil {
41 | return nil, err
42 | }
43 |
44 | bs := block.BlockSize()
45 | data := PKCS5Padding(data, bs)
46 | out = make([]byte, len(data))
47 |
48 | dst := out
49 | for len(data) > 0 {
50 | // The message is divided into blocks,
51 | // and each block is encrypted separately.
52 | block.Encrypt(dst, data[:bs])
53 | data = data[bs:]
54 | dst = dst[bs:]
55 | }
56 | case "des-cbc":
57 | block, err := des.NewCipher(key)
58 | if err != nil {
59 | return nil, err
60 | }
61 |
62 | data := PKCS5Padding(data, block.BlockSize())
63 | mode := cipher.NewCBCEncrypter(block, iv)
64 | out = make([]byte, len(data))
65 | mode.CryptBlocks(out, data)
66 | case "aes-cbc":
67 | block, err := aes.NewCipher(key)
68 | if err != nil {
69 | return nil, err
70 | }
71 |
72 | data := PKCS5Padding(data, block.BlockSize())
73 | mode := cipher.NewCBCEncrypter(block, iv)
74 | out = make([]byte, len(data))
75 | mode.CryptBlocks(out, data)
76 | default:
77 | return nil, ErrNotSupport
78 | }
79 | return out, nil
80 | }
81 |
82 | func encryptFn(L *lua.LState) int {
83 | s := lua.LVAsString(L.Get(1))
84 | method := lua.LVAsString(L.Get(2))
85 | key := lua.LVAsString(L.Get(3))
86 | options := L.ToInt(4)
87 | iv := lua.LVAsString(L.Get(5))
88 |
89 | out, err := Encrypt([]byte(s), method, []byte(key), []byte(iv))
90 | if err != nil {
91 | L.Push(lua.LNil)
92 | L.Push(lua.LString(err.Error()))
93 | return 2
94 | }
95 |
96 | var result string
97 | if options&RawData == 0 {
98 | result = hex.EncodeToString(out)
99 | } else {
100 | result = string(out)
101 | }
102 | L.Push(lua.LString(result))
103 | return 1
104 | }
105 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/hmac.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/hmac"
5 | "crypto/md5"
6 | "crypto/sha1"
7 | "crypto/sha256"
8 | "crypto/sha512"
9 | "encoding/hex"
10 | "hash"
11 |
12 | lua "github.com/yuin/gopher-lua"
13 | )
14 |
15 | func hmacFn(L *lua.LState) int {
16 | algorithm := lua.LVAsString(L.Get(1))
17 | s := lua.LVAsString(L.Get(2))
18 | key := lua.LVAsString(L.Get(3))
19 | raw := lua.LVAsBool(L.Get(4))
20 |
21 | var h hash.Hash
22 | switch algorithm {
23 | case "md5":
24 | h = hmac.New(md5.New, []byte(key))
25 | case "sha1":
26 | h = hmac.New(sha1.New, []byte(key))
27 | case "sha256":
28 | h = hmac.New(sha256.New, []byte(key))
29 | case "sha512":
30 | h = hmac.New(sha512.New, []byte(key))
31 | default:
32 | L.Push(lua.LNil)
33 | L.Push(lua.LString("unsupported algorithm"))
34 | return 2
35 | }
36 |
37 | _, err := h.Write([]byte(s))
38 | if err != nil {
39 | L.Push(lua.LNil)
40 | L.Push(lua.LString(err.Error()))
41 | return 2
42 | }
43 |
44 | var result string
45 | if !raw {
46 | result = hex.EncodeToString(h.Sum(nil))
47 | } else {
48 | result = string(h.Sum(nil))
49 | }
50 | L.Push(lua.LString(result))
51 | return 1
52 | }
53 |
54 | func validHmacFn(L *lua.LState) int {
55 | algorithm := L.CheckString(1)
56 | message := L.CheckString(2)
57 | key := L.CheckString(3)
58 | mmac := L.CheckString(4)
59 | var mac hash.Hash
60 | switch algorithm {
61 | case "md5":
62 | mac = hmac.New(md5.New, []byte(key))
63 | case "sha1":
64 | mac = hmac.New(sha1.New, []byte(key))
65 | case "sha256":
66 | mac = hmac.New(sha256.New, []byte(key))
67 | case "sha512":
68 | mac = hmac.New(sha512.New, []byte(key))
69 | default:
70 | L.Push(lua.LNil)
71 | L.Push(lua.LString("unsupported algorithm"))
72 | return 2
73 | }
74 | mac.Write([]byte(message))
75 | expectedMAC := mac.Sum(nil)
76 | if hmac.Equal([]byte(mmac), expectedMAC) {
77 | L.Push(lua.LTrue)
78 | } else {
79 | L.Push(lua.LFalse)
80 | }
81 | return 1
82 | }
83 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/md5.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 |
7 | lua "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func md5Fn(L *lua.LState) int {
11 | h := md5.New()
12 | s := lua.LVAsString(L.Get(1))
13 | raw := lua.LVAsBool(L.Get(2))
14 | _, err := h.Write([]byte(s))
15 | if err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString(err.Error()))
18 | return 2
19 | }
20 |
21 | var result string
22 | if !raw {
23 | result = hex.EncodeToString(h.Sum(nil))
24 | } else {
25 | result = string(h.Sum(nil))
26 | }
27 | L.Push(lua.LString(result))
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/random.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/rand"
5 | "fmt"
6 | "hash/maphash"
7 | "io"
8 |
9 | lua "github.com/yuin/gopher-lua"
10 | )
11 |
12 | func randomFn(L *lua.LState) int {
13 | size := int(L.OptNumber(1, 8))
14 | buf := make([]byte, size)
15 | if _, err := io.ReadFull(rand.Reader, buf); err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString("Failed to read bytes."))
18 | return 2
19 | }
20 | L.Push(lua.LString(fmt.Sprintf("%016x", buf[0:size])))
21 | return 1
22 | }
23 |
24 | func fastRandomFn(L *lua.LState) int {
25 | h := new(maphash.Hash)
26 | L.Push(lua.LString(fmt.Sprintf("%016X", h.Sum64())))
27 | return 1
28 | }
29 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/sha1.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 |
7 | lua "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func sha1Fn(L *lua.LState) int {
11 | h := sha1.New()
12 | s := lua.LVAsString(L.Get(1))
13 | raw := lua.LVAsBool(L.Get(2))
14 | _, err := h.Write([]byte(s))
15 | if err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString(err.Error()))
18 | return 2
19 | }
20 |
21 | var result string
22 | if !raw {
23 | result = hex.EncodeToString(h.Sum(nil))
24 | } else {
25 | result = string(h.Sum(nil))
26 | }
27 | L.Push(lua.LString(result))
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/sha256.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/sha256"
5 | "encoding/hex"
6 |
7 | lua "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func sha256Fn(L *lua.LState) int {
11 | h := sha256.New()
12 | s := lua.LVAsString(L.Get(1))
13 | raw := lua.LVAsBool(L.Get(2))
14 | _, err := h.Write([]byte(s))
15 | if err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString(err.Error()))
18 | return 2
19 | }
20 |
21 | var result string
22 | if !raw {
23 | result = hex.EncodeToString(h.Sum(nil))
24 | } else {
25 | result = string(h.Sum(nil))
26 | }
27 | L.Push(lua.LString(result))
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluacrypto/crypto/sha512.go:
--------------------------------------------------------------------------------
1 | package gluacrypto_crypto
2 |
3 | import (
4 | "crypto/sha512"
5 | "encoding/hex"
6 |
7 | lua "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func sha512Fn(L *lua.LState) int {
11 | h := sha512.New()
12 | s := lua.LVAsString(L.Get(1))
13 | raw := lua.LVAsBool(L.Get(2))
14 | _, err := h.Write([]byte(s))
15 | if err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString(err.Error()))
18 | return 2
19 | }
20 |
21 | var result string
22 | if !raw {
23 | result = hex.EncodeToString(h.Sum(nil))
24 | } else {
25 | result = string(h.Sum(nil))
26 | }
27 | L.Push(lua.LString(result))
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluahttp/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Christian Joudrey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/external/gluahttp/httpresponsetype.go:
--------------------------------------------------------------------------------
1 | package gluahttp
2 |
3 | import "github.com/yuin/gopher-lua"
4 | import "net/http"
5 |
6 | const luaHttpResponseTypeName = "http.response"
7 |
8 | type luaHttpResponse struct {
9 | res *http.Response
10 | body lua.LString
11 | bodySize int
12 | }
13 |
14 | func registerHttpResponseType(module *lua.LTable, L *lua.LState) {
15 | mt := L.NewTypeMetatable(luaHttpResponseTypeName)
16 | L.SetField(mt, "__index", L.NewFunction(httpResponseIndex))
17 |
18 | L.SetField(module, "response", mt)
19 | }
20 |
21 | func newHttpResponse(res *http.Response, body *[]byte, bodySize int, L *lua.LState) *lua.LUserData {
22 | ud := L.NewUserData()
23 | ud.Value = &luaHttpResponse{
24 | res: res,
25 | body: lua.LString(*body),
26 | bodySize: bodySize,
27 | }
28 | L.SetMetatable(ud, L.GetTypeMetatable(luaHttpResponseTypeName))
29 | return ud
30 | }
31 |
32 | func checkHttpResponse(L *lua.LState) *luaHttpResponse {
33 | ud := L.CheckUserData(1)
34 | if v, ok := ud.Value.(*luaHttpResponse); ok {
35 | return v
36 | }
37 | L.ArgError(1, "http.response expected")
38 | return nil
39 | }
40 |
41 | func httpResponseIndex(L *lua.LState) int {
42 | res := checkHttpResponse(L)
43 |
44 | switch L.CheckString(2) {
45 | case "headers":
46 | return httpResponseHeaders(res, L)
47 | case "cookies":
48 | return httpResponseCookies(res, L)
49 | case "status_code":
50 | return httpResponseStatusCode(res, L)
51 | case "url":
52 | return httpResponseUrl(res, L)
53 | case "body":
54 | return httpResponseBody(res, L)
55 | case "body_size":
56 | return httpResponseBodySize(res, L)
57 | }
58 |
59 | return 0
60 | }
61 |
62 | func httpResponseHeaders(res *luaHttpResponse, L *lua.LState) int {
63 | headers := L.NewTable()
64 | for key, _ := range res.res.Header {
65 | headers.RawSetString(key, lua.LString(res.res.Header.Get(key)))
66 | }
67 | L.Push(headers)
68 | return 1
69 | }
70 |
71 | func httpResponseCookies(res *luaHttpResponse, L *lua.LState) int {
72 | cookies := L.NewTable()
73 | for _, cookie := range res.res.Cookies() {
74 | cookies.RawSetString(cookie.Name, lua.LString(cookie.Value))
75 | }
76 | L.Push(cookies)
77 | return 1
78 | }
79 |
80 | func httpResponseStatusCode(res *luaHttpResponse, L *lua.LState) int {
81 | L.Push(lua.LNumber(res.res.StatusCode))
82 | return 1
83 | }
84 |
85 | func httpResponseUrl(res *luaHttpResponse, L *lua.LState) int {
86 | L.Push(lua.LString(res.res.Request.URL.String()))
87 | return 1
88 | }
89 |
90 | func httpResponseBody(res *luaHttpResponse, L *lua.LState) int {
91 | L.Push(res.body)
92 | return 1
93 | }
94 |
95 | func httpResponseBodySize(res *luaHttpResponse, L *lua.LState) int {
96 | L.Push(lua.LNumber(res.bodySize))
97 | return 1
98 | }
99 |
--------------------------------------------------------------------------------
/external/gluasocket/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2019 Nubix https://nubix.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/external/gluasocket/gluasocket.go:
--------------------------------------------------------------------------------
1 | package gluasocket
2 |
3 | import (
4 | "github.com/tongson/LadyLua/external/gluasocket/socket"
5 | "github.com/tongson/LadyLua/external/gluasocket/socketcore"
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func Preload(L *lua.LState) {
10 | L.PreloadModule("socket", gluasocket_socket.Loader)
11 | L.PreloadModule("socket.core", gluasocket_socketcore.Loader)
12 | }
13 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/client.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "bufio"
5 | "net"
6 | "time"
7 |
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | const (
12 | CLIENT_TYPENAME = "tcp{client}"
13 | )
14 |
15 | type Client struct {
16 | Conn net.Conn
17 | Timeout time.Duration
18 | Reader *bufio.Reader
19 | }
20 |
21 | var clientMethods = map[string]lua.LGFunction{
22 | "close": clientCloseMethod,
23 | "dirty": clientDirtyMethod,
24 | "getfd": clientGetFdMethod,
25 | "getpeername": clientGetPeerNameMethod,
26 | "getsockname": clientGetSockNameMethod,
27 | "getstats": clientGetStatsMethod,
28 | "receive": clientReceiveMethod,
29 | "settimeout": clientSetTimeoutMethod,
30 | "send": clientSendMethod,
31 | "setoption": clientSetOptionMethod,
32 | "setstats": clientSetStatsMethod,
33 | "shutdown": clientShutdownMethod,
34 | }
35 |
36 | // ----------------------------------------------------------------------------
37 |
38 | func checkClient(L *lua.LState) *Client {
39 | ud := L.CheckUserData(1)
40 | if v, ok := ud.Value.(*Client); ok {
41 | return v
42 | }
43 | L.ArgError(1, "client expected")
44 | return nil
45 | }
46 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientclose.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientCloseMethod(L *lua.LState) int {
8 | client := checkClient(L)
9 | if err := client.Conn.Close(); err != nil {
10 | L.RaiseError(err.Error())
11 | }
12 | return 0
13 | }
14 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientdirty.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientDirtyMethod(L *lua.LState) int {
8 | L.Push(lua.LBool(false))
9 | return 1
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientgetfd.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "net"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func clientGetFdMethod(L *lua.LState) int {
10 | client := checkClient(L)
11 | if file, err := client.Conn.(*net.TCPConn).File(); err != nil {
12 | L.RaiseError(err.Error())
13 | return 0
14 | } else {
15 | L.Push(lua.LNumber(file.Fd()))
16 | return 1
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientgetpeername.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientGetPeerNameMethod(L *lua.LState) int {
8 | L.RaiseError("client:getpeername() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientgetsockname.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientGetSockNameMethod(L *lua.LState) int {
8 | L.RaiseError("client:getsockname() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientgetstats.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientGetStatsMethod(L *lua.LState) int {
8 | L.RaiseError("client:getstats() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientreceive.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "net"
7 | "time"
8 |
9 | "github.com/yuin/gopher-lua"
10 | )
11 |
12 | func clientReceiveMethod(L *lua.LState) int {
13 | client := checkClient(L)
14 | pattern := L.Get(2)
15 | //prefix := "" // TODO L.CheckString(3)
16 |
17 | // Read a number of bytes from the socket
18 | if pattern.Type() == lua.LTNumber {
19 | if client.Timeout <= 0 {
20 | client.Conn.SetDeadline(time.Time{})
21 | } else {
22 | client.Conn.SetDeadline(time.Now().Add(client.Timeout))
23 | }
24 | var buf bytes.Buffer
25 | bytesToRead := L.ToInt(2)
26 | for i := 0; i < bytesToRead; i++ {
27 | byte, err := client.Reader.ReadByte()
28 | if err == io.EOF {
29 | break
30 | }
31 | if err != nil {
32 | errstr := err.Error()
33 | if err, ok := err.(net.Error); ok && err.Timeout() {
34 | errstr = "timeout"
35 | }
36 | L.Push(lua.LNil)
37 | L.Push(lua.LString(errstr))
38 | return 2
39 | }
40 | buf.WriteByte(byte)
41 | }
42 | L.Push(lua.LString(string(buf.Bytes())))
43 | return 1
44 | }
45 |
46 | // Read a line of text from the socket. Line separators are not returned.
47 | // This is the default pattern so nil is the same as "*l".
48 | if pattern.Type() == lua.LTNil || (pattern.Type() == lua.LTString && pattern.String() == "*l") {
49 | var buf bytes.Buffer
50 | for {
51 | if client.Timeout <= 0 {
52 | client.Conn.SetDeadline(time.Time{})
53 | } else {
54 | client.Conn.SetDeadline(time.Now().Add(client.Timeout))
55 | }
56 | line, isPrefix, err := client.Reader.ReadLine()
57 | if err != nil {
58 | errstr := err.Error()
59 | if err, ok := err.(net.Error); ok && err.Timeout() {
60 | errstr = "timeout"
61 | }
62 | L.Push(lua.LNil)
63 | L.Push(lua.LString(errstr))
64 | return 2
65 | }
66 | buf.Write(line)
67 | if !isPrefix {
68 | break
69 | }
70 | }
71 | L.Push(lua.LString(string(buf.Bytes())))
72 | return 1
73 | }
74 |
75 | // Read until the connection is closed
76 | if pattern.Type() == lua.LTString && pattern.String() == "*a" {
77 | if client.Timeout <= 0 {
78 | client.Conn.SetDeadline(time.Time{})
79 | } else {
80 | client.Conn.SetDeadline(time.Now().Add(client.Timeout))
81 | }
82 | var buf bytes.Buffer
83 | for {
84 | byte, err := client.Reader.ReadByte()
85 | if err == io.EOF {
86 | break
87 | }
88 | if err != nil {
89 | errstr := err.Error()
90 | if err, ok := err.(net.Error); ok && err.Timeout() {
91 | errstr = "timeout"
92 | }
93 | L.Push(lua.LNil)
94 | L.Push(lua.LString(errstr))
95 | return 2
96 | }
97 | buf.WriteByte(byte)
98 | }
99 | L.Push(lua.LString(string(buf.Bytes())))
100 | return 1
101 | }
102 |
103 | L.RaiseError("client:receive() not implemented yet")
104 | return 0
105 | }
106 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientsend.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientSendMethod(L *lua.LState) int {
8 | client := checkClient(L)
9 | data := L.ToString(2)
10 | i := L.OptInt(3, 1)
11 | j := L.OptInt(4, len(data)+1)
12 |
13 | dataBytes := []byte(data)
14 | if bytesSent, err := client.Conn.Write(dataBytes[i-1 : j-1]); err != nil {
15 | L.Push(lua.LNil)
16 | L.Push(lua.LString(err.Error()))
17 | return 2
18 | } else {
19 | L.Push(lua.LNumber(bytesSent))
20 | return 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientsetoption.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientSetOptionMethod(L *lua.LState) int {
8 | L.RaiseError("client:setoption() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientsetstats.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientSetStatsMethod(L *lua.LState) int {
8 | L.RaiseError("client:setstats() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientsettimeout.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func clientSetTimeoutMethod(L *lua.LState) int {
10 | client := checkClient(L)
11 | timeout := L.CheckNumber(2)
12 | client.Timeout = time.Duration(timeout * 1.0e9)
13 | L.Push(lua.LNumber(1))
14 | return 1
15 | }
16 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/clientshutdown.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func clientShutdownMethod(L *lua.LState) int {
8 | L.RaiseError("client:shutdown() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/connect.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "net"
7 |
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | func connectFn(L *lua.LState) int {
12 | hostname := L.ToString(1)
13 | port := L.ToInt(2)
14 |
15 | conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", hostname, port))
16 | if err != nil {
17 | L.Push(lua.LNil)
18 | L.Push(lua.LString(err.Error()))
19 | return 2
20 | }
21 |
22 | reader := bufio.NewReader(conn)
23 | client := &Client{Conn: conn, Reader: reader}
24 | ud := L.NewUserData()
25 | ud.Value = client
26 | L.SetMetatable(ud, L.GetTypeMetatable(CLIENT_TYPENAME))
27 | L.Push(ud)
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/dns.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | type DNS struct {
8 | }
9 |
10 | var dnsMethods = map[string]lua.LGFunction{
11 | "getaddrinfo": dnsGetAddrInfo,
12 | "gethostname": dnsGetHostName,
13 | "tohostname": dnsToHostName,
14 | "toip": dnsToIp,
15 | }
16 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/dnsgetaddrinfo.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "net"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func dnsGetAddrInfo(L *lua.LState) int {
10 |
11 | // Read arguments
12 | host := L.CheckString(1)
13 |
14 | // Handle
15 | if host == "" {
16 | return 0
17 | }
18 | addrs, err := net.LookupHost(host)
19 | if err != nil {
20 | L.RaiseError(err.Error())
21 | return 0
22 | }
23 | result := &lua.LTable{}
24 | for _, addr := range addrs {
25 | if addr == "::1" {
26 | // best guess, according to https://stackoverflow.com/questions/5956516/getaddrinfo-and-ipv6
27 | continue
28 | }
29 | t := &lua.LTable{}
30 | t.RawSetString("family", lua.LString("inet"))
31 | t.RawSetString("addr", lua.LString(addr))
32 | result.Append(t)
33 | }
34 |
35 | L.Push(result)
36 | return 1
37 | }
38 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/dnsgethostname.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func dnsGetHostName(L *lua.LState) int {
11 | hostname, err := os.Hostname()
12 | if err != nil {
13 | L.RaiseError(fmt.Sprintf("Failure detecting hostname: %v", err))
14 | return 0
15 | }
16 |
17 | L.Push(lua.LString(hostname))
18 | return 1
19 | }
20 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/dnstohostname.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "net"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func dnsToHostName(L *lua.LState) int {
10 | ip := L.ToString(1)
11 | host, err := net.LookupAddr(ip)
12 | if err != nil {
13 | L.Push(lua.LNil)
14 | L.Push(lua.LString(err.Error()))
15 | return 2
16 | }
17 | // Generally only one result is returned by LookupAddr, so we just assume this is the case
18 | // TODO: Return a table containing all hostnames mapping to the address
19 | if len(host) > 0 {
20 | L.Push(lua.LString(host[0]))
21 | } else {
22 | L.Push(lua.LNil)
23 | }
24 | L.Push(lua.LNil)
25 | return 2
26 | }
27 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/dnstoip.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "net"
5 | "strings"
6 |
7 | "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func dnsToIp(L *lua.LState) int {
11 | host := L.ToString(1)
12 | if addrs, err := net.LookupHost(host); err != nil {
13 | L.RaiseError(err.Error())
14 | return 0
15 | } else {
16 | if len(addrs) < 1 {
17 | L.Push(lua.LNil)
18 | return 1
19 | }
20 | for _, addr := range addrs {
21 | if !strings.Contains(addr, ":") {
22 | L.Push(lua.LString(addr))
23 | return 1
24 | }
25 | }
26 | L.Push(lua.LString(addrs[0]))
27 | return 1
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/gettime.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func gettimeFn(l *lua.LState) int {
10 | now := time.Now()
11 | l.Push(lua.LNumber(float64(now.UnixNano()) / 1.0e9))
12 | return 1
13 | }
14 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/master.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "net"
5 | "time"
6 |
7 | "github.com/yuin/gopher-lua"
8 | )
9 |
10 | const (
11 | MASTER_TYPENAME = "tcp{master}"
12 | )
13 |
14 | type Master struct {
15 | Listener net.Listener
16 | BindAddr string
17 | BindPort lua.LValue
18 | Timeout time.Duration
19 | Family int
20 | Options map[string]lua.LValue
21 | }
22 |
23 | var masterMethods = map[string]lua.LGFunction{
24 | "accept": masterAcceptMethod,
25 | "bind": masterBindMethod,
26 | "close": masterCloseMethod,
27 | "connect": masterConnectMethod,
28 | "listen": masterListenMethod,
29 | "setoption": masterSetOptionMethod,
30 | "settimeout": masterSetTimeoutMethod,
31 | }
32 |
33 | // ----------------------------------------------------------------------------
34 |
35 | func checkMaster(L *lua.LState) (*Master, *lua.LUserData) {
36 | ud := L.CheckUserData(1)
37 | if v, ok := ud.Value.(*Master); ok {
38 | return v, ud
39 | }
40 | L.ArgError(1, "master expected")
41 | return nil, nil
42 | }
43 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/masteraccept.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "bufio"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func masterAcceptMethod(L *lua.LState) int {
10 | master, ud := checkMaster(L)
11 | conn, err := master.Listener.Accept()
12 | if err != nil {
13 | L.Push(lua.LNil)
14 | L.Push(lua.LString(err.Error()))
15 | return 2
16 | }
17 | reader := bufio.NewReader(conn)
18 | client := &Client{Conn: conn, Reader: reader, Timeout: master.Timeout}
19 | ud.Value = client
20 | L.SetMetatable(ud, L.GetTypeMetatable(CLIENT_TYPENAME))
21 | L.Push(ud)
22 | return 1
23 | }
24 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/masterbind.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func masterBindMethod(L *lua.LState) int {
8 | master, _ := checkMaster(L)
9 | master.BindAddr = L.CheckString(2)
10 | master.BindPort = L.Get(3)
11 | L.Push(lua.LNumber(1))
12 | return 1
13 | }
14 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/masterclose.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func masterCloseMethod(L *lua.LState) int {
8 | master, _ := checkMaster(L)
9 | master.Listener.Close()
10 | return 0
11 | }
12 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/masterconnect.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "net"
7 |
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | func masterConnectMethod(L *lua.LState) int {
12 | master, ud := checkMaster(L)
13 | hostname := L.ToString(2)
14 | port := L.ToInt(3)
15 |
16 | conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", hostname, port), master.Timeout)
17 | if err != nil {
18 | L.Push(lua.LNil)
19 | L.Push(lua.LString(err.Error()))
20 | return 2
21 | }
22 |
23 | reader := bufio.NewReader(conn)
24 | client := &Client{Conn: conn, Reader: reader, Timeout: master.Timeout}
25 | ud.Value = client
26 | L.SetMetatable(ud, L.GetTypeMetatable(CLIENT_TYPENAME))
27 | L.Push(ud)
28 | return 1
29 | }
30 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/masterlisten.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "fmt"
5 | "net"
6 |
7 | "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func masterListenMethod(L *lua.LState) int {
11 | master, _ := checkMaster(L)
12 | //backlog := L.CheckNumber(1)
13 |
14 | listener, err := net.Listen("tcp", fmt.Sprintf("%s:%s", master.BindAddr, master.BindPort))
15 | if err != nil {
16 | L.Push(lua.LNil)
17 | L.Push(lua.LString(err.Error()))
18 | return 2
19 | }
20 |
21 | master.Listener = listener
22 | L.Push(lua.LNumber(1))
23 | return 1
24 | }
25 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/mastersetoption.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func masterSetOptionMethod(L *lua.LState) int {
8 | master, _ := checkMaster(L)
9 | optionName := L.CheckString(2) /* obj, name, ... */
10 | if master.Options == nil {
11 | master.Options = map[string]lua.LValue{}
12 | }
13 | master.Options[optionName] = L.Get(3)
14 | return 0
15 | }
16 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/mastersettimeout.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func masterSetTimeoutMethod(L *lua.LState) int {
10 | master, _ := checkMaster(L)
11 | timeout := L.CheckNumber(2)
12 | master.Timeout = time.Duration(timeout * 1.0e9)
13 | L.Push(lua.LNumber(1))
14 | return 1
15 | }
16 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/select.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func selectFn(L *lua.LState) int {
10 |
11 | // Read arguments
12 | recvt := L.Get(1)
13 | sendt := L.Get(2)
14 | timeout := L.Get(3)
15 |
16 | // Handle select(nil, nil, timeout)
17 | if recvt.Type() == lua.LTNil && sendt.Type() == lua.LTNil {
18 | timeoutVal, ok := timeout.(lua.LNumber)
19 | if !ok {
20 | L.RaiseError("Malformed timeout in call to socket.select(?,?,timeout)")
21 | return 0
22 | }
23 | timeoutDuration := time.Duration(timeoutVal * 1.0e9)
24 | time.Sleep(timeoutDuration)
25 | L.Push(lua.LString("timeout"))
26 | return 1
27 | }
28 |
29 | // TODO Handle socket select
30 | L.RaiseError("socket.select(recvt,sendt,timeout) not implemented yet")
31 | return 0
32 | }
33 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/skip.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func skipFn(L *lua.LState) int {
8 | d := L.ToInt(1)
9 | for i := 0; i <= d; i++ {
10 | L.Remove(1)
11 | }
12 | return L.GetTop()
13 | }
14 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/sleep.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func sleepFn(L *lua.LState) int {
10 |
11 | // Read arguments
12 | timeout := L.Get(1)
13 |
14 | // Handle
15 | timeoutVal, ok := timeout.(lua.LNumber)
16 | if !ok {
17 | L.RaiseError("Malformed timeout in call to socket.sleep(time)")
18 | return 0
19 | }
20 | timeoutDuration := time.Duration(timeoutVal * 1.0e9)
21 | time.Sleep(timeoutDuration)
22 |
23 | return 0
24 | }
25 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/socketcore.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | const (
8 | AF_UNSPEC = 0
9 | AF_INET = 2
10 | AF_INET6 = 23
11 | )
12 |
13 | // ----------------------------------------------------------------------------
14 |
15 | var exports = map[string]lua.LGFunction{
16 | "connect": connectFn,
17 | "gettime": gettimeFn,
18 | "select": selectFn,
19 | "skip": skipFn,
20 | "sleep": sleepFn,
21 | "tcp": tcpFn,
22 | "tcp4": tcp4Fn,
23 | "tcp6": tcp6Fn,
24 | "udp": udpFn,
25 | }
26 |
27 | // ----------------------------------------------------------------------------
28 |
29 | func Loader(L *lua.LState) int {
30 | mod := L.SetFuncs(L.NewTable(), exports)
31 | L.Push(mod)
32 |
33 | L.SetField(mod, "_DEBUG", lua.LBool(false))
34 | L.SetField(mod, "_VERSION", lua.LString("0.0.0")) // TODO
35 |
36 | registerClientType(L)
37 | registerMasterType(L)
38 |
39 | registerDNSTable(L, mod)
40 |
41 | return 1
42 | }
43 |
44 | // ----------------------------------------------------------------------------
45 |
46 | func registerClientType(L *lua.LState) {
47 | mt := L.NewTypeMetatable(CLIENT_TYPENAME)
48 | L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), clientMethods))
49 | }
50 |
51 | // ----------------------------------------------------------------------------
52 |
53 | func registerDNSTable(L *lua.LState, mod *lua.LTable) {
54 | table := L.NewTable()
55 | L.SetFuncs(table, dnsMethods)
56 | L.SetField(mod, "dns", table)
57 | }
58 |
59 | // ----------------------------------------------------------------------------
60 |
61 | func registerMasterType(L *lua.LState) {
62 | mt := L.NewTypeMetatable(MASTER_TYPENAME)
63 | L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), masterMethods))
64 | }
65 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/tcp.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func tcpFn(L *lua.LState) int {
8 | master := &Master{Family: AF_UNSPEC}
9 | ud := L.NewUserData()
10 | ud.Value = master
11 | L.SetMetatable(ud, L.GetTypeMetatable(MASTER_TYPENAME))
12 | L.Push(ud)
13 | return 1
14 | }
15 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/tcp4.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func tcp4Fn(L *lua.LState) int {
8 | master := &Master{Family: AF_INET}
9 | ud := L.NewUserData()
10 | ud.Value = master
11 | L.SetMetatable(ud, L.GetTypeMetatable(MASTER_TYPENAME))
12 | L.Push(ud)
13 | return 1
14 | }
15 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/tcp6.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func tcp6Fn(L *lua.LState) int {
8 | master := &Master{Family: AF_INET6}
9 | ud := L.NewUserData()
10 | ud.Value = master
11 | L.SetMetatable(ud, L.GetTypeMetatable(MASTER_TYPENAME))
12 | L.Push(ud)
13 | return 1
14 | }
15 |
--------------------------------------------------------------------------------
/external/gluasocket/socketcore/udp.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketcore
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | func udpFn(L *lua.LState) int {
8 | L.RaiseError("socket.udp() not implemented yet")
9 | return 0
10 | }
11 |
--------------------------------------------------------------------------------
/external/gluasocket/socketexcept/socketexcept.go:
--------------------------------------------------------------------------------
1 | package gluasocket_socketexcept
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | // ----------------------------------------------------------------------------
8 |
9 | func Loader(l *lua.LState) int {
10 | if err := l.DoString(exceptDotLua); err != nil {
11 | l.RaiseError("Error loading except.lua: %v", err)
12 | return 0
13 | }
14 | return 1
15 | }
16 |
17 | const exceptDotLua = `-----------------------------------------------------------------------------
18 | -- Exception control
19 | -- LuaSocket toolkit (but completely independent from other modules)
20 | -- Author: Diego Nehab
21 |
22 | -- This provides support for simple exceptions in Lua. During the
23 | -- development of the HTTP/FTP/SMTP support, it became aparent that
24 | -- error checking was taking a substantial amount of the coding. These
25 | -- function greatly simplify the task of checking errors.
26 |
27 | -- The main idea is that functions should return nil as its first return
28 | -- value when it finds an error, and return an error message (or value)
29 | -- following nil. In case of success, as long as the first value is not nil,
30 | -- the other values don't matter.
31 |
32 | -- The idea is to nest function calls with the "try" function. This function
33 | -- checks the first value, and, if it's falsy, wraps the second value
34 | -- in a table with metatable and calls "error" on it. Otherwise,
35 | -- it returns all values it received.
36 |
37 | -- The "newtry" function is a factory for "try" functions that call a finalizer
38 | -- in protected mode before calling "error".
39 |
40 | -- The "protect" function returns a new function that behaves exactly like the
41 | -- function it receives, but the new function catches exceptions
42 | -- thrown by "try" functions and returns nil followed by the error message
43 | -- instead.
44 |
45 | -- With these three function, it's easy to write functions that throw
46 | -- exceptions on error, but that don't interrupt the user script.
47 | -----------------------------------------------------------------------------
48 |
49 | local base = _G
50 | local _M = {}
51 |
52 | local exception_metat = {}
53 |
54 | function exception_metat:__tostring()
55 | return base.tostring(self[1])
56 | end
57 |
58 | local function do_nothing() end
59 |
60 | function _M.newtry(finalizer)
61 | if finalizer == nil then finalizer = do_nothing end
62 | return function(...)
63 | local ok, err = ...
64 | if ok then
65 | return ...
66 | else
67 | base.pcall(finalizer)
68 | base.error(base.setmetatable({err}, exception_metat))
69 | end
70 | end
71 | end
72 |
73 | local function handle_pcall_returns(ok, ...)
74 | if ok then
75 | return ...
76 | else
77 | local err = ...
78 | if base.getmetatable(err) == exception_metat then
79 | return nil, err[1]
80 | else
81 | base.error(err, 0)
82 | end
83 | end
84 | end
85 |
86 | function _M.protect(func)
87 | return function(...)
88 | return handle_pcall_returns(base.pcall(func, ...))
89 | end
90 | end
91 |
92 | return _M
93 | `
94 |
--------------------------------------------------------------------------------
/external/gluasql/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/external/gluasql/mysql/client.go:
--------------------------------------------------------------------------------
1 | package gluasql_mysql
2 |
3 | import (
4 | "database/sql"
5 | "time"
6 |
7 | _ "github.com/go-sql-driver/mysql"
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | const (
12 | CLIENT_TYPENAME = "mysql{client}"
13 | )
14 |
15 | // Client mysql
16 | type Client struct {
17 | DB *sql.DB
18 | Timeout time.Duration
19 | }
20 |
21 | var clientMethods = map[string]lua.LGFunction{
22 | "connect": clientConnectMethod,
23 | "set_timeout": clientSetTimeoutMethod,
24 | "set_keepalive": clientSetKeepaliveMethod,
25 | "close": clientCloseMethod,
26 | "query": clientQueryMethod,
27 | }
28 |
29 | func checkClient(L *lua.LState) *Client {
30 | ud := L.CheckUserData(1)
31 | if v, ok := ud.Value.(*Client); ok {
32 | return v
33 | }
34 | L.ArgError(1, "client expected")
35 | return nil
36 | }
37 |
38 | func clientCloseMethod(L *lua.LState) int {
39 | client := checkClient(L)
40 |
41 | if client.DB == nil {
42 | L.Push(lua.LBool(true))
43 | return 1
44 | }
45 |
46 | err := client.DB.Close()
47 | // always clean
48 | client.DB = nil
49 | if err != nil {
50 | L.Push(lua.LBool(false))
51 | L.Push(lua.LString(err.Error()))
52 | return 2
53 | }
54 |
55 | L.Push(lua.LBool(true))
56 | return 1
57 | }
58 |
59 | func clientSetKeepaliveMethod(L *lua.LState) int {
60 | client := checkClient(L)
61 | idleTimeout := L.ToInt64(2) // timeout (in ms)
62 | poolSize := L.ToInt(3)
63 |
64 | if client.DB == nil {
65 | L.Push(lua.LBool(true))
66 | L.Push(lua.LString("connect required"))
67 | return 2
68 | }
69 |
70 | client.DB.SetConnMaxLifetime(time.Millisecond * time.Duration(idleTimeout))
71 | client.DB.SetMaxIdleConns(poolSize)
72 |
73 | L.Push(lua.LBool(true))
74 | return 1
75 | }
76 |
--------------------------------------------------------------------------------
/external/gluasql/mysql/clientconnect.go:
--------------------------------------------------------------------------------
1 | package gluasql_mysql
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "net/url"
7 |
8 | util "github.com/tongson/LadyLua/external/gluasql/util"
9 | "github.com/yuin/gopher-lua"
10 | )
11 |
12 | func clientConnectMethod(L *lua.LState) int {
13 | client := checkClient(L)
14 | tb := util.GetValue(L, 2)
15 | options, ok := tb.(map[string]interface{})
16 |
17 | if tb == nil || !ok {
18 | L.ArgError(2, "options excepted")
19 | return 0
20 | }
21 |
22 | host, _ := options["host"].(string)
23 | if host == "" {
24 | host = "127.0.0.1"
25 | }
26 | port, _ := options["port"].(int)
27 | if port == 0 {
28 | port = 3306
29 | }
30 | database, _ := options["database"].(string)
31 | user, _ := options["user"].(string)
32 | password, _ := options["password"].(string)
33 | charset, _ := options["charset"].(string)
34 |
35 | // current support tcp connection only
36 | dsn := fmt.Sprintf("tcp(%s:%d)/%s", host, port, database)
37 | if user != "" {
38 | if password != "" {
39 | dsn = fmt.Sprintf("%s:%s@", user, password) + dsn
40 | } else {
41 | dsn = fmt.Sprintf("%s@", user) + dsn
42 | }
43 | }
44 |
45 | query := url.Values{}
46 | if charset != "" {
47 | query.Set("charset", charset)
48 | }
49 | if client.Timeout > 0 {
50 | stimeout := client.Timeout.String()
51 | query.Set("readTimeout", stimeout)
52 | query.Set("writeTimeout", stimeout)
53 | }
54 |
55 | s := query.Encode()
56 | if s != "" {
57 | dsn += "?" + s
58 | }
59 |
60 | var err error
61 | client.DB, err = sql.Open("mysql", dsn)
62 | if err != nil {
63 | L.Push(lua.LBool(false))
64 | L.Push(lua.LString(err.Error()))
65 | return 2
66 | }
67 |
68 | L.Push(lua.LBool(true))
69 | return 1
70 | }
71 |
--------------------------------------------------------------------------------
/external/gluasql/mysql/clientquery.go:
--------------------------------------------------------------------------------
1 | package gluasql_mysql
2 |
3 | import (
4 | "reflect"
5 |
6 | "github.com/junhsieh/goexamples/fieldbinding/fieldbinding"
7 | util "github.com/tongson/LadyLua/external/gluasql/util"
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | func clientQueryMethod(L *lua.LState) int {
12 | client := checkClient(L)
13 | query := L.ToString(2)
14 |
15 | if client.DB == nil {
16 | return 0
17 | }
18 |
19 | if query == "" {
20 | L.ArgError(2, "query string required")
21 | return 0
22 | }
23 |
24 | top := L.GetTop()
25 | args := make([]interface{}, 0, top-2)
26 | for i := 3; i <= top; i++ {
27 | args = append(args, util.GetValue(L, i))
28 | }
29 |
30 | rows, err := client.DB.Query(query, args...)
31 | if err != nil {
32 | L.Push(lua.LNil)
33 | L.Push(lua.LString(err.Error()))
34 | return 2
35 | }
36 | defer rows.Close()
37 |
38 | fb := fieldbinding.NewFieldBinding()
39 | cols, err := rows.Columns()
40 | if err != nil {
41 | L.Push(lua.LNil)
42 | L.Push(lua.LString(err.Error()))
43 | return 2
44 | }
45 |
46 | fb.PutFields(cols)
47 |
48 | tb := L.NewTable()
49 | for rows.Next() {
50 | if err := rows.Scan(fb.GetFieldPtrArr()...); err != nil {
51 | L.Push(lua.LNil)
52 | L.Push(lua.LString(err.Error()))
53 | return 2
54 | }
55 |
56 | tbRow := util.ToTableFromMap(L, reflect.ValueOf(fb.GetFieldArr()))
57 | tb.Append(tbRow)
58 | }
59 |
60 | L.Push(tb)
61 | return 1
62 | }
63 |
--------------------------------------------------------------------------------
/external/gluasql/mysql/clientsettimeout.go:
--------------------------------------------------------------------------------
1 | package gluasql_mysql
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | func clientSetTimeoutMethod(L *lua.LState) int {
10 | client := checkClient(L)
11 | timeout := L.ToInt64(2) // timeout (in ms)
12 |
13 | client.Timeout = time.Millisecond * time.Duration(timeout)
14 | return 0
15 | }
16 |
--------------------------------------------------------------------------------
/external/gluasql/mysql/mysql.go:
--------------------------------------------------------------------------------
1 | package gluasql_mysql
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | )
6 |
7 | var exports = map[string]lua.LGFunction{
8 | "new": newFn,
9 | "escape": escapeFn,
10 | }
11 |
12 | func Loader(L *lua.LState) int {
13 | mod := L.SetFuncs(L.NewTable(), exports)
14 | L.Push(mod)
15 |
16 | L.SetField(mod, "_DEBUG", lua.LBool(false))
17 | L.SetField(mod, "_VERSION", lua.LString("0.0.0"))
18 |
19 | registerClientType(L)
20 |
21 | return 1
22 | }
23 |
24 | func registerClientType(L *lua.LState) {
25 | mt := L.NewTypeMetatable(CLIENT_TYPENAME)
26 | L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), clientMethods))
27 | }
28 |
29 | func newFn(L *lua.LState) int {
30 | client := &Client{}
31 | ud := L.NewUserData()
32 | ud.Value = client
33 | L.SetMetatable(ud, L.GetTypeMetatable(CLIENT_TYPENAME))
34 | L.Push(ud)
35 | return 1
36 | }
37 |
38 | func escape(source string) string {
39 | var j int = 0
40 | if len(source) == 0 {
41 | return ""
42 | }
43 | tempStr := source[:]
44 | desc := make([]byte, len(tempStr)*2)
45 | for i := 0; i < len(tempStr); i++ {
46 | flag := false
47 | var escape byte
48 | switch tempStr[i] {
49 | case '\r':
50 | flag = true
51 | escape = 'r'
52 | break
53 | case '\n':
54 | flag = true
55 | escape = 'n'
56 | break
57 | case '\\':
58 | flag = true
59 | escape = '\\'
60 | break
61 | case '\'':
62 | flag = true
63 | escape = '\''
64 | break
65 | case '"':
66 | flag = true
67 | escape = '"'
68 | break
69 | case '\032':
70 | flag = true
71 | escape = 'Z'
72 | break
73 | default:
74 | }
75 | if flag {
76 | desc[j] = '\\'
77 | desc[j+1] = escape
78 | j = j + 2
79 | } else {
80 | desc[j] = tempStr[i]
81 | j = j + 1
82 | }
83 | }
84 | return string(desc[0:j])
85 | }
86 |
87 | func escapeFn(L *lua.LState) int {
88 | s := L.ToString(1)
89 | L.Push(lua.LString(escape(s)))
90 | return 1
91 | }
92 |
--------------------------------------------------------------------------------
/external/gopher-json/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/external/gopher-lfs/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/external/gopher-lfs/api_darwin.go:
--------------------------------------------------------------------------------
1 | // +build darwin
2 |
3 | package lfs
4 |
5 | import (
6 | "os"
7 | "syscall"
8 |
9 | "github.com/yuin/gopher-lua"
10 | )
11 |
12 | func attributesFill(tbl *lua.LTable, stat os.FileInfo) error {
13 | sys := stat.Sys().(*syscall.Stat_t)
14 | tbl.RawSetString("dev", lua.LNumber(sys.Dev))
15 | tbl.RawSetString("ino", lua.LNumber(sys.Ino))
16 | {
17 | var mode string
18 | switch sys.Mode & syscall.S_IFMT {
19 | case syscall.S_IFREG:
20 | mode = "file"
21 | case syscall.S_IFDIR:
22 | mode = "directory"
23 | case syscall.S_IFLNK:
24 | mode = "link"
25 | case syscall.S_IFSOCK:
26 | mode = "socket"
27 | case syscall.S_IFIFO:
28 | mode = "named pipe"
29 | case syscall.S_IFCHR:
30 | mode = "char device"
31 | case syscall.S_IFBLK:
32 | mode = "block device"
33 | default:
34 | mode = "other"
35 | }
36 | tbl.RawSetString("mode", lua.LString(mode))
37 | }
38 | tbl.RawSetString("nlink", lua.LNumber(sys.Nlink))
39 | tbl.RawSetString("uid", lua.LNumber(sys.Uid))
40 | tbl.RawSetString("gid", lua.LNumber(sys.Gid))
41 | tbl.RawSetString("rdev", lua.LNumber(sys.Rdev))
42 | tbl.RawSetString("access", lua.LNumber(sys.Atimespec.Sec))
43 | tbl.RawSetString("modification", lua.LNumber(sys.Mtimespec.Sec))
44 | tbl.RawSetString("change", lua.LNumber(sys.Ctimespec.Sec))
45 | tbl.RawSetString("size", lua.LNumber(sys.Size))
46 | tbl.RawSetString("blocks", lua.LNumber(sys.Blocks))
47 | tbl.RawSetString("blksize", lua.LNumber(sys.Blksize))
48 | return nil
49 | }
50 |
--------------------------------------------------------------------------------
/external/gopher-lfs/api_linux.go:
--------------------------------------------------------------------------------
1 | // +build linux
2 |
3 | package lfs
4 |
5 | import (
6 | "os"
7 | "syscall"
8 |
9 | "github.com/yuin/gopher-lua"
10 | )
11 |
12 | func attributesFill(tbl *lua.LTable, stat os.FileInfo) error {
13 | sys := stat.Sys().(*syscall.Stat_t)
14 | tbl.RawSetString("dev", lua.LNumber(sys.Dev))
15 | tbl.RawSetString("ino", lua.LNumber(sys.Ino))
16 | {
17 | var mode string
18 | switch sys.Mode & syscall.S_IFMT {
19 | case syscall.S_IFREG:
20 | mode = "file"
21 | case syscall.S_IFDIR:
22 | mode = "directory"
23 | case syscall.S_IFLNK:
24 | mode = "link"
25 | case syscall.S_IFSOCK:
26 | mode = "socket"
27 | case syscall.S_IFIFO:
28 | mode = "named pipe"
29 | case syscall.S_IFCHR:
30 | mode = "char device"
31 | case syscall.S_IFBLK:
32 | mode = "block device"
33 | default:
34 | mode = "other"
35 | }
36 | tbl.RawSetString("mode", lua.LString(mode))
37 | }
38 | tbl.RawSetString("nlink", lua.LNumber(sys.Nlink))
39 | tbl.RawSetString("uid", lua.LNumber(sys.Uid))
40 | tbl.RawSetString("gid", lua.LNumber(sys.Gid))
41 | tbl.RawSetString("rdev", lua.LNumber(sys.Rdev))
42 | tbl.RawSetString("access", lua.LNumber(sys.Atim.Sec))
43 | tbl.RawSetString("modification", lua.LNumber(sys.Mtim.Sec))
44 | tbl.RawSetString("change", lua.LNumber(sys.Ctim.Sec))
45 | tbl.RawSetString("size", lua.LNumber(sys.Size))
46 | tbl.RawSetString("blocks", lua.LNumber(sys.Blocks))
47 | tbl.RawSetString("blksize", lua.LNumber(sys.Blksize))
48 | return nil
49 | }
50 |
--------------------------------------------------------------------------------
/external/gopher-lfs/api_other.go:
--------------------------------------------------------------------------------
1 | // +build !darwin,!linux,!windows
2 |
3 | package lfs
4 |
5 | import (
6 | "errors"
7 | "os"
8 | "runtime"
9 |
10 | "github.com/yuin/gopher-lua"
11 | )
12 |
13 | func attributesFill(tbl *lua.LTable, stat os.FileInfo) error {
14 | return errors.New("unsupported operating system " + runtime.GOOS)
15 | }
16 |
--------------------------------------------------------------------------------
/external/gopher-lfs/api_windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package lfs
4 |
5 | import (
6 | "os"
7 | "syscall"
8 | "time"
9 |
10 | "github.com/yuin/gopher-lua"
11 | )
12 |
13 | func attributesFill(tbl *lua.LTable, stat os.FileInfo) error {
14 | sys := stat.Sys().(*syscall.Win32FileAttributeData)
15 | tbl.RawSetString("dev", lua.LNumber(0))
16 | tbl.RawSetString("ino", lua.LNumber(0))
17 |
18 | if stat.IsDir() {
19 | tbl.RawSetString("mode", lua.LString("directory"))
20 | } else {
21 | tbl.RawSetString("mode", lua.LString("file"))
22 | }
23 |
24 | tbl.RawSetString("nlink", lua.LNumber(0))
25 | tbl.RawSetString("uid", lua.LNumber(0))
26 | tbl.RawSetString("gid", lua.LNumber(0))
27 | tbl.RawSetString("rdev", lua.LNumber(0))
28 |
29 | tbl.RawSetString("access", lua.LNumber(time.Unix(0, sys.LastAccessTime.Nanoseconds()/1e9).Second()))
30 | tbl.RawSetString("modification", lua.LNumber(time.Unix(0, sys.CreationTime.Nanoseconds()/1e9).Second()))
31 | tbl.RawSetString("change", lua.LNumber(time.Unix(0, sys.LastWriteTime.Nanoseconds()/1e9).Second()))
32 | tbl.RawSetString("size", lua.LNumber(stat.Size()))
33 |
34 | tbl.RawSetString("blocks", lua.LNumber(0))
35 | tbl.RawSetString("blksize", lua.LNumber(0))
36 | return nil
37 | }
38 |
--------------------------------------------------------------------------------
/external/gopher-lfs/util.go:
--------------------------------------------------------------------------------
1 | package lfs
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | "github.com/yuin/gopher-lua"
8 | )
9 |
10 | func attributes(L *lua.LState, statFunc func(string) (os.FileInfo, error)) int {
11 | fp := L.CheckString(1)
12 |
13 | stat, err := statFunc(fp)
14 | if err != nil {
15 | L.Push(lua.LNil)
16 | L.Push(lua.LString(err.Error()))
17 | return 2
18 | }
19 | table := L.NewTable()
20 | if err := attributesFill(table, stat); err != nil {
21 | L.Push(lua.LNil)
22 | L.Push(lua.LString(err.Error()))
23 | return 2
24 | }
25 | if table.RawGetString("mode").String() == "link" {
26 | if path, err := filepath.EvalSymlinks(fp); err == nil {
27 | table.RawSetString("target", lua.LString(path))
28 | }
29 | }
30 | if L.GetTop() > 1 {
31 | requestName := L.CheckString(2)
32 | L.Push(table.RawGetString(requestName))
33 | return 1
34 | }
35 | L.Push(table)
36 | return 1
37 | }
38 |
39 | func dirItr(L *lua.LState) int {
40 | ud := L.CheckUserData(1)
41 |
42 | f, ok := ud.Value.(*os.File)
43 | if !ok {
44 | return 0
45 | }
46 | names, err := f.Readdirnames(1)
47 | if err != nil {
48 | return 0
49 | }
50 | L.Push(lua.LString(names[0]))
51 | return 1
52 | }
53 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/tongson/LadyLua
2 |
3 | go 1.16
4 |
5 | require (
6 | git.mills.io/prologic/bitcask v0.3.14
7 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
8 | github.com/frankban/quicktest v1.13.0 // indirect
9 | github.com/fsnotify/fsnotify v1.4.9
10 | github.com/ghodss/yaml v1.0.0
11 | github.com/go-redis/redis/v8 v8.11.0
12 | github.com/go-sql-driver/mysql v1.6.0
13 | github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
14 | github.com/gregdel/pushover v1.1.0
15 | github.com/hashicorp/go-uuid v1.0.2
16 | github.com/junhsieh/goexamples v0.0.0-20210713004924-3d9f14ba676d
17 | github.com/kevinburke/ssh_config v1.1.0
18 | github.com/oklog/ulid/v2 v2.0.2
19 | github.com/pelletier/go-toml v1.9.3
20 | github.com/pierrec/lz4 v2.6.1+incompatible
21 | github.com/rs/zerolog v1.23.0
22 | github.com/segmentio/ksuid v1.0.4
23 | github.com/slack-go/slack v0.9.3
24 | github.com/technoweenie/multipartstreamer v1.0.1 // indirect
25 | github.com/tongson/gl v0.0.0-20210722053448-dfbc7abd31bf
26 | github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7
27 | github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9
28 | )
29 |
30 | replace github.com/yuin/gopher-lua => github.com/tongson/gopher-lua v0.0.0-20210610051759-53ab9600e09f
31 |
--------------------------------------------------------------------------------
/helper.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "embed"
5 | "fmt"
6 | "os"
7 |
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | //#
12 | //# == *ll.FillArg*(*lua.LState, []string)
13 | //# Capture command line arguments as the `arg` table in the global `_G` environment.
14 | //#
15 | //# === Arguments
16 | //# [width="72%"]
17 | //# |===
18 | //# |*lua.LState|The current `LState`; usually the result of `lua.NewState()`
19 | //# |[]string |Usually `os.Args`
20 | //# |===
21 | func FillArg(L *lua.LState, args []string) {
22 | argtb := L.NewTable()
23 | for i := 0; i < len(args); i++ {
24 | L.RawSet(argtb, lua.LNumber(i), lua.LString(args[i]))
25 | }
26 | L.SetGlobal("arg", argtb)
27 | }
28 |
29 | //#
30 | //# == *ll.ReadFile*(embed.FS, string) -> string
31 | //# Read file from an `embed.FS` location.
32 | //#
33 | //# === Arguments
34 | //# [width="72%"]
35 | //# |===
36 | //# |embed.FS |Variable of embedded filesystem
37 | //# |string |Filename
38 | //# |===
39 | //#
40 | //# === Returns
41 | //# [width="72%"]
42 | //# |===
43 | //# |string |Contents of file
44 | //# |===
45 | func ReadFile(f embed.FS, p string) string {
46 | c, err := f.ReadFile(p)
47 | if err != nil {
48 | fmt.Println(err.Error())
49 | os.Exit(1)
50 | }
51 | return string(c)
52 | }
53 |
--------------------------------------------------------------------------------
/internal/exec.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/tongson/gl"
5 | "github.com/yuin/gopher-lua"
6 | )
7 |
8 | func ExecCommand(L *lua.LState) int {
9 | targ := []string{}
10 | tenv := []string{}
11 | tbl := L.NewTable()
12 | exe := L.CheckString(1)
13 | arg := L.OptTable(2, tbl)
14 | env := L.OptTable(3, tbl)
15 | cwd := L.OptString(4, "")
16 | sin := L.OptString(5, "")
17 | tme := L.OptNumber(6, 0)
18 |
19 | if arg.Len() > 0 {
20 | arg.ForEach(func(_, value lua.LValue) {
21 | targ = append(targ, lua.LVAsString(value))
22 | })
23 | }
24 | if env.Len() > 0 {
25 | env.ForEach(func(_, value lua.LValue) {
26 | tenv = append(tenv, lua.LVAsString(value))
27 | })
28 | }
29 | cmd := gl.RunArgs{Exe: exe, Args: targ, Env: tenv, Dir: cwd, Stdin: []byte(sin), Timeout: int(tme)}
30 | ret, stdout, stderr, err := cmd.Run()
31 |
32 | if ret {
33 | L.Push(lua.LTrue)
34 | } else {
35 | L.Push(lua.LNil)
36 | }
37 | L.Push(lua.LString(stdout))
38 | L.Push(lua.LString(stderr))
39 | L.Push(lua.LString(err))
40 | return 4
41 | }
42 |
43 | func ExecCtx(L *lua.LState) int {
44 | exe := L.CheckString(1)
45 | set := L.NewTable()
46 | mt := L.NewTable()
47 | L.SetField(mt, "__call", L.NewFunction(func(L *lua.LState) int {
48 | deftbl := L.NewTable()
49 | args := L.OptTable(2, deftbl)
50 | L.Push(L.NewFunction(ExecCommand))
51 | L.Push(lua.LString(exe))
52 | L.Push(args)
53 | L.Push(L.GetField(set, "env"))
54 | L.Push(L.GetField(set, "cwd"))
55 | L.Push(L.GetField(set, "stdin"))
56 | L.Push(L.GetField(set, "timeout"))
57 | L.Call(6, 4)
58 | return 4
59 | }))
60 | L.SetMetatable(set, mt)
61 | L.Push(set)
62 | return 1
63 | }
64 |
--------------------------------------------------------------------------------
/internal/fs.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/tongson/gl"
5 | "github.com/yuin/gopher-lua"
6 | "io"
7 | "os"
8 | )
9 |
10 | func FsIsdir(L *lua.LState) int {
11 | dir := L.CheckString(1)
12 | is := gl.StatPath("directory")
13 | if is(dir) {
14 | L.Push(lua.LTrue)
15 | return 1
16 | } else {
17 | L.Push(lua.LNil)
18 | L.Push(lua.LString("Not a directory."))
19 | return 2
20 | }
21 | }
22 |
23 | func FsIsfile(L *lua.LState) int {
24 | f := L.CheckString(1)
25 | is := gl.StatPath("")
26 | if is(f) {
27 | L.Push(lua.LTrue)
28 | return 1
29 | } else {
30 | L.Push(lua.LNil)
31 | L.Push(lua.LString("Not a file."))
32 | return 2
33 | }
34 | }
35 |
36 | func FsRead(L *lua.LState) int {
37 | path := L.CheckString(1)
38 | isFile := gl.StatPath("file")
39 | /* #nosec G304 */
40 | if isFile(path) {
41 | file, err := os.Open(path)
42 | defer func() {
43 | _ = file.Close()
44 | }()
45 | if err != nil {
46 | L.Push(lua.LNil)
47 | L.Push(lua.LString(err.Error()))
48 | return 2
49 | }
50 | if str, err := io.ReadAll(file); err != nil {
51 | L.Push(lua.LNil)
52 | L.Push(lua.LString(err.Error()))
53 | return 2
54 | } else {
55 | L.Push(lua.LString(string(str)))
56 | return 1
57 | }
58 | } else {
59 | L.Push(lua.LNil)
60 | L.Push(lua.LString("Not a file or file does not exist."))
61 | return 2
62 | }
63 | }
64 |
65 | func FsWrite(L *lua.LState) int {
66 | f := L.CheckString(1)
67 | s := L.CheckString(2)
68 | err := gl.StringToFile(f, s)
69 | if err != nil {
70 | L.Push(lua.LNil)
71 | L.Push(lua.LString(err.Error()))
72 | return 2
73 | } else {
74 | L.Push(lua.LTrue)
75 | return 1
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/internal/fsnotify.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/fsnotify/fsnotify"
5 | "github.com/yuin/gopher-lua"
6 | )
7 |
8 | func fsnCreate(L *lua.LState) int {
9 | var got bool
10 | var ero string
11 | watcher, err := fsnotify.NewWatcher()
12 | if err != nil {
13 | L.Push(lua.LNil)
14 | L.Push(lua.LString(err.Error()))
15 | return 2
16 | }
17 | defer watcher.Close()
18 | f := L.CheckString(1)
19 | done := make(chan bool)
20 | go func() {
21 | for {
22 | select {
23 | case event, ok := <-watcher.Events:
24 | if !ok {
25 | return
26 | }
27 | if event.Op&fsnotify.Create == fsnotify.Create {
28 | got = true
29 | close(done)
30 | return
31 | }
32 | case err, ok := <-watcher.Errors:
33 | if !ok {
34 | return
35 | }
36 | ero = err.Error()
37 | return
38 | }
39 | }
40 | }()
41 | err = watcher.Add(f)
42 | <-done
43 | if err != nil {
44 | L.Push(lua.LNil)
45 | L.Push(lua.LString(err.Error()))
46 | return 2
47 | }
48 | if got == true {
49 | L.Push(lua.LTrue)
50 | return 1
51 | } else {
52 | L.Push(lua.LNil)
53 | L.Push(lua.LString(ero))
54 | return 2
55 | }
56 | }
57 |
58 | func fsnWrite(L *lua.LState) int {
59 | var got bool
60 | var ero string
61 | watcher, err := fsnotify.NewWatcher()
62 | if err != nil {
63 | L.Push(lua.LNil)
64 | L.Push(lua.LString(err.Error()))
65 | return 2
66 | }
67 | defer watcher.Close()
68 | f := L.CheckString(1)
69 | done := make(chan bool)
70 | go func() {
71 | for {
72 | select {
73 | case event, ok := <-watcher.Events:
74 | if !ok {
75 | return
76 | }
77 | if event.Op&fsnotify.Write == fsnotify.Write {
78 | got = true
79 | close(done)
80 | return
81 | }
82 | case err, ok := <-watcher.Errors:
83 | if !ok {
84 | return
85 | }
86 | ero = err.Error()
87 | return
88 | }
89 | }
90 | }()
91 | err = watcher.Add(f)
92 | <-done
93 | if err != nil {
94 | L.Push(lua.LNil)
95 | L.Push(lua.LString(err.Error()))
96 | return 2
97 | }
98 | if got == true {
99 | L.Push(lua.LTrue)
100 | return 1
101 | } else {
102 | L.Push(lua.LNil)
103 | L.Push(lua.LString(ero))
104 | return 2
105 | }
106 | }
107 |
108 | func fsnRemove(L *lua.LState) int {
109 | var got bool
110 | var ero string
111 | watcher, err := fsnotify.NewWatcher()
112 | if err != nil {
113 | L.Push(lua.LNil)
114 | L.Push(lua.LString(err.Error()))
115 | return 2
116 | }
117 | defer watcher.Close()
118 | f := L.CheckString(1)
119 | done := make(chan bool)
120 | go func() {
121 | for {
122 | select {
123 | case event, ok := <-watcher.Events:
124 | if !ok {
125 | return
126 | }
127 | if event.Op&fsnotify.Remove == fsnotify.Remove {
128 | got = true
129 | close(done)
130 | return
131 | }
132 | case err, ok := <-watcher.Errors:
133 | if !ok {
134 | return
135 | }
136 | ero = err.Error()
137 | return
138 | }
139 | }
140 | }()
141 | err = watcher.Add(f)
142 | <-done
143 | if err != nil {
144 | L.Push(lua.LNil)
145 | L.Push(lua.LString(err.Error()))
146 | return 2
147 | }
148 | if got == true {
149 | L.Push(lua.LTrue)
150 | return 1
151 | } else {
152 | L.Push(lua.LNil)
153 | L.Push(lua.LString(ero))
154 | return 2
155 | }
156 | }
157 |
158 | func FsnLoader(L *lua.LState) int {
159 | t := L.NewTable()
160 | L.SetFuncs(t, fsnApi)
161 | L.Push(t)
162 | return 1
163 | }
164 |
165 | var fsnApi = map[string]lua.LGFunction{
166 | "create": fsnCreate,
167 | "write": fsnWrite,
168 | "remove": fsnRemove,
169 | }
170 |
--------------------------------------------------------------------------------
/internal/global.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/yuin/gopher-lua"
7 | )
8 |
9 | // Prettier equivalent of `require("xstring")()` --> `extend("string")`
10 | func Extend(L *lua.LState) int {
11 | mod := L.CheckString(1)
12 | req := L.GetField(L.Get(lua.GlobalsIndex), "require").(*lua.LFunction)
13 | L.Push(req)
14 | L.Push(lua.LString(fmt.Sprintf("extension_%s", mod)))
15 | L.Call(1, 1)
16 | L.Call(0, 0)
17 | return 0
18 | }
19 |
--------------------------------------------------------------------------------
/internal/ksuid.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/segmentio/ksuid"
5 | "github.com/yuin/gopher-lua"
6 | )
7 |
8 | func ksuidNew(L *lua.LState) int {
9 | L.Push(lua.LString(ksuid.New().String()))
10 | return 1
11 | }
12 |
13 | func KsuidLoader(L *lua.LState) int {
14 | t := L.NewTable()
15 | L.SetFuncs(t, ksuidApi)
16 | L.Push(t)
17 | return 1
18 | }
19 |
20 | var ksuidApi = map[string]lua.LGFunction{
21 | "new": ksuidNew,
22 | }
23 |
--------------------------------------------------------------------------------
/internal/logger.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/rs/zerolog"
5 | "github.com/yuin/gluamapper"
6 | "github.com/yuin/gopher-lua"
7 | "os"
8 | "strings"
9 | "time"
10 | "fmt"
11 | )
12 |
13 | var loggerFile *os.File
14 |
15 | const (
16 | LOGGER_TYPE = "logger{api}"
17 | )
18 |
19 | type loggerT struct {
20 | logger *zerolog.Logger
21 | }
22 |
23 | func loggerInit(logger zerolog.Logger) *loggerT {
24 | return &loggerT{
25 | &logger,
26 | }
27 | }
28 |
29 | var loggerExports = map[string]lua.LGFunction{
30 | "new": loggerNew,
31 | "time": loggerTime,
32 | }
33 |
34 | func loggerTime(L *lua.LState) int {
35 | p := fmt.Sprintf
36 | t := time.Now()
37 | L.Push(lua.LString(p(t.Format(time.RFC3339))))
38 | return 1
39 | }
40 |
41 | func loggerCheck(L *lua.LState) *loggerT {
42 | ud := L.CheckUserData(1)
43 | if v, ok := ud.Value.(*loggerT); ok {
44 | return v
45 | } else {
46 | return nil
47 | }
48 | }
49 |
50 | func LoggerLoader(L *lua.LState) int {
51 | mod := L.SetFuncs(L.NewTable(), loggerExports)
52 | L.Push(mod)
53 | loggerRegister(L)
54 | return 1
55 | }
56 |
57 | func loggerRegister(L *lua.LState) {
58 | mt := L.NewTypeMetatable(LOGGER_TYPE)
59 | L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), loggerMethods))
60 | }
61 |
62 | func loggerNew(L *lua.LState) int {
63 | zerolog.TimeFieldFormat = time.RFC3339
64 | ud := L.NewUserData()
65 | a := L.OptString(1, "stderr")
66 | switch a {
67 | case "stdout":
68 | ud.Value = loggerInit(zerolog.New(os.Stdout).With().Timestamp().Logger())
69 | case "stderr":
70 | ud.Value = loggerInit(zerolog.New(os.Stderr).With().Timestamp().Logger())
71 | default:
72 | loggerFile, err := os.OpenFile(a, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
73 | if err != nil {
74 | ud.Value = nil
75 | } else {
76 | ud.Value = loggerInit(zerolog.New(loggerFile).With().Timestamp().Logger())
77 | }
78 | }
79 | L.SetMetatable(ud, L.GetTypeMetatable(LOGGER_TYPE))
80 | L.Push(ud)
81 | return 1
82 | }
83 |
84 | func loggerPush(L *lua.LState, event *zerolog.Event) int {
85 | msg := L.CheckString(2)
86 | stubs := L.CheckTable(3)
87 |
88 | gostubs := make(map[string]interface{})
89 | err := gluamapper.Map(stubs, &gostubs)
90 |
91 | if err != nil {
92 | L.Push(lua.LNil)
93 | L.Push(lua.LString(err.Error()))
94 | return 2
95 | }
96 |
97 | for str, val := range gostubs {
98 | event.Interface(strings.ToLower(str), val)
99 | }
100 | event.Msg(msg)
101 | loggerFile.Close()
102 | return 0
103 | }
104 |
105 | var loggerMethods = map[string]lua.LGFunction{
106 | "info": func(L *lua.LState) int {
107 | logger := loggerCheck(L)
108 | if logger == nil {
109 | L.Push(lua.LNil)
110 | L.Push(lua.LString("info: Invalid logger."))
111 | return 2
112 | }
113 | event := logger.logger.Info()
114 | return loggerPush(L, event)
115 | },
116 | "debug": func(L *lua.LState) int {
117 | logger := loggerCheck(L)
118 | if logger == nil {
119 | L.Push(lua.LNil)
120 | L.Push(lua.LString("info: Invalid logger."))
121 | return 2
122 | }
123 |
124 | event := logger.logger.Debug()
125 | return loggerPush(L, event)
126 | },
127 | "warn": func(L *lua.LState) int {
128 | logger := loggerCheck(L)
129 | if logger == nil {
130 | L.Push(lua.LNil)
131 | L.Push(lua.LString("info: Invalid logger."))
132 | return 2
133 | }
134 | event := logger.logger.Warn()
135 | return loggerPush(L, event)
136 | },
137 | "error": func(L *lua.LState) int {
138 | logger := loggerCheck(L)
139 | if logger == nil {
140 | L.Push(lua.LNil)
141 | L.Push(lua.LString("info: Invalid logger."))
142 | return 2
143 | }
144 | event := logger.logger.Error()
145 | return loggerPush(L, event)
146 | },
147 | }
148 |
--------------------------------------------------------------------------------
/internal/lua/extension_exec.lua:
--------------------------------------------------------------------------------
1 | return setmetatable({}, {
2 | __call = function()
3 | exec.cmd = function(exe)
4 | local format, len, gsub, gmatch = string.format, string.len, string.gsub, string.gmatch
5 | local set = {}
6 | return setmetatable(set, {
7 | __call = function(_, a, ...)
8 | local args
9 | if a and type(a) == "string" then
10 | local ergs = format(a, ...)
11 | args = {}
12 | for k in gmatch(ergs, "%S+") do
13 | args[#args + 1] = k
14 | end
15 | end
16 | if a and type(a) == "table" then
17 | args = a
18 | end
19 | local r, so, se, cerr = exec.command(
20 | exe,
21 | args,
22 | set.env,
23 | set.cwd,
24 | set.stdin,
25 | set.timeout
26 | )
27 | local pretty_prefix = function(header, prefix, str)
28 | local n
29 | if len(str) > 0 then
30 | local replacement = format("\n %s > ", prefix)
31 | str, n = gsub(str, "\n", replacement)
32 | if n == 0 then
33 | str = str .. ("\n %s > "):format(prefix)
34 | end
35 | return format(
36 | "%s\n %s >\n %s > %s\n",
37 | header,
38 | prefix,
39 | prefix,
40 | str
41 | )
42 | else
43 | return ""
44 | end
45 | end
46 | if set.errexit == true and r == nil then
47 | local err = cerr or set.error or "execution failed"
48 | local header = format('exec.cmd: `%s` => "%s"', exe, err)
49 | if len(so) < 1 and len(se) < 1 then
50 | return fmt.panic("%s\n", header)
51 | else
52 | fmt.print("%s", pretty_prefix(header, "stdout", so))
53 | return fmt.panic("%s", pretty_prefix(header, "stderr", se))
54 | end
55 | else
56 | return r, so, se
57 | end
58 | end,
59 | })
60 | end
61 |
62 | exec.run = setmetatable({}, {
63 | __index = function(_, exe)
64 | return function(...)
65 | local args
66 | if not (...) then
67 | args = {}
68 | elseif type(...) == "table" then
69 | args = ...
70 | else
71 | args = { ... }
72 | end
73 | return exec.command(exe, args)
74 | end
75 | end,
76 | })
77 | end,
78 | })
79 |
--------------------------------------------------------------------------------
/internal/lua/extension_json.lua:
--------------------------------------------------------------------------------
1 | return setmetatable({}, {
2 | __call = function()
3 | local json = require("json")
4 | local decode = json.decode
5 | json.array = function(j)
6 | local t = decode(j)
7 | local jagen = function(x, i)
8 | i = i + 1
9 | local v = x[i]
10 | if v ~= nil then
11 | return i, v
12 | else
13 | return nil
14 | end
15 | end
16 | return jagen, t, 0
17 | end
18 | json.object = function(j)
19 | local next = next
20 | local t = decode(j)
21 | return next, t, nil
22 | end
23 | end,
24 | })
25 |
--------------------------------------------------------------------------------
/internal/lua/extension_string.lua:
--------------------------------------------------------------------------------
1 | return setmetatable({}, {
2 | __call = function()
3 | local F = string.format
4 | local gmatch = string.gmatch
5 | local find = string.find
6 | local sub = string.sub
7 | local reverse = string.reverse
8 | local gsub = string.gsub
9 | local append = table.insert
10 | local unpack = unpack
11 | local escape = function(s)
12 | return (gsub(s, "[%-%.%+%[%]%(%)%$%^%%%?%*]", "%%%1"))
13 | end
14 | local _strip = function(s, left, right, chrs)
15 | if not chrs then
16 | chrs = "%s"
17 | else
18 | chrs = "[" .. escape(chrs) .. "]"
19 | end
20 | local f = 1
21 | local t
22 | if left then
23 | local i1, i2 = find(s, "^" .. chrs .. "*")
24 | if i2 >= i1 then
25 | f = i2 + 1
26 | end
27 | end
28 | if right then
29 | if #s < 200 then
30 | local i1, i2 = find(s, chrs .. "*$", f)
31 | if i2 >= i1 then
32 | t = i1 - 1
33 | end
34 | else
35 | local rs = reverse(s)
36 | local i1, i2 = find(rs, "^" .. chrs .. "*")
37 | if i2 >= i1 then
38 | t = -i2 - 1
39 | end
40 | end
41 | end
42 | return sub(s, f, t)
43 | end
44 |
45 | string.trim_start = function(s, chrs)
46 | return _strip(s, true, false, chrs)
47 | end
48 |
49 | string.trim_end = function(s, chrs)
50 | return _strip(s, false, true, chrs)
51 | end
52 |
53 | string.split = function(s, re, plain, n)
54 | local i1, ls = 1, {}
55 | if not re then
56 | re = "%s+"
57 | end
58 | if re == "" then
59 | return { s }
60 | end
61 | while true do
62 | local i2, i3 = find(s, re, i1, plain)
63 | if not i2 then
64 | local last = sub(s, i1)
65 | if last ~= "" then
66 | append(ls, last)
67 | end
68 | if #ls == 1 and ls[1] == "" then
69 | return {}
70 | else
71 | return ls
72 | end
73 | end
74 | append(ls, sub(s, i1, i2 - 1))
75 | if n and #ls == n then
76 | ls[#ls] = sub(s, i1)
77 | return ls
78 | end
79 | i1 = i3 + 1
80 | end
81 | end
82 |
83 | string.splitv = function(s, re, plain, n)
84 | return unpack(string.split(s, re, plain, n))
85 | end
86 |
87 | string.contains = function(str, a)
88 | return find(str, a, 1, true)
89 | end
90 |
91 | string.append = function(str, a)
92 | return F("%s\n%s", str, a)
93 | end
94 |
95 | string.word_to_list = function(str)
96 | local t = {}
97 | for s in gmatch(str, "%w+") do
98 | t[#t + 1] = s
99 | end
100 | return t
101 | end
102 |
103 | string.to_list = function(str)
104 | local t = {}
105 | for s in gmatch(str, "%S+") do
106 | t[#t + 1] = s
107 | end
108 | return t
109 | end
110 |
111 | string.to_map = function(str, def)
112 | def = def or true
113 | local t = {}
114 | for s in gmatch(str, "%S+") do
115 | t[s] = def
116 | end
117 | return t
118 | end
119 | end,
120 | })
121 |
--------------------------------------------------------------------------------
/internal/lua/fmt.lua:
--------------------------------------------------------------------------------
1 | local fmt = {}
2 | local F = string.format
3 |
4 | fmt.print = function(str, ...)
5 | local stdout = io.stdout
6 | stdout:write(F(str, ...))
7 | return stdout:flush()
8 | end
9 |
10 | fmt.fprint = function(file, str, ...)
11 | local o = io.output()
12 | io.output(file)
13 | local ret, err = io.write(F(str, ...))
14 | io.output(o)
15 | return ret, err
16 | end
17 |
18 | local warnf = function(str, ...)
19 | local stderr = io.stderr
20 | stderr:write(F(str, ...))
21 | stderr:flush()
22 | end
23 | fmt.warn = warnf
24 |
25 | local panicf = function(str, ...)
26 | warnf(str, ...)
27 | os.exit(1)
28 | end
29 | fmt.panic = panicf
30 |
31 | fmt.error = function(str, ...)
32 | return nil, F(str, ...)
33 | end
34 |
35 | fmt.assert = function(v, str, ...)
36 | if v then
37 | return true
38 | else
39 | panicf(str, ...)
40 | end
41 | end
42 | return fmt
43 |
--------------------------------------------------------------------------------
/internal/lua/graph.lua:
--------------------------------------------------------------------------------
1 | local setmetatable = setmetatable
2 | local pairs = pairs
3 | local type = type
4 | local function visit(k, n, m, s)
5 | if m[k] == 0 then return 1 end
6 | if m[k] == 1 then return end
7 | m[k] = 0
8 | local f = n[k]
9 | for i=1, #f do
10 | if visit(f[i], n, m, s) then return 1 end
11 | end
12 | m[k] = 1
13 | s[#s+1] = k
14 | end
15 | local tsort = {}
16 | tsort.__index = tsort
17 | function tsort.new()
18 | return setmetatable({ n = {} }, tsort)
19 | end
20 | function tsort:add(...)
21 | local p = { ... }
22 | local c = #p
23 | if c == 0 then return self end
24 | if c == 1 then
25 | p = p[1]
26 | if type(p) == "table" then
27 | c = #p
28 | else
29 | p = { p }
30 | end
31 | end
32 | local n = self.n
33 | for i=1, c do
34 | local f = p[i]
35 | if n[f] == nil then n[f] = {} end
36 | end
37 | for i=2, c, 1 do
38 | local f = p[i]
39 | local t = p[i-1]
40 | local o = n[f]
41 | o[#o+1] = t
42 | end
43 | return self
44 | end
45 | function tsort:sort()
46 | local n = self.n
47 | local s = {}
48 | local m = {}
49 | for k in pairs(n) do
50 | if m[k] == nil then
51 | if visit(k, n, m, s) then
52 | return nil, "There is a circular dependency in the graph. It is not possible to derive a topological sort."
53 | end
54 | end
55 | end
56 | return s
57 | end
58 | return tsort
--------------------------------------------------------------------------------
/internal/lua/guard.lua:
--------------------------------------------------------------------------------
1 | local setmetatable = setmetatable
2 | local ipairs = ipairs
3 | local error = error
4 |
5 | local _guardian = function()
6 | local guard = { __when = {} }
7 |
8 | guard.when = function(filter, f)
9 | guard.__when[#guard.__when + 1] = { filter = filter, f = f }
10 | return guard
11 | end
12 |
13 | guard.any = function(f)
14 | guard.__any = f
15 | return guard
16 | end
17 |
18 | return setmetatable(guard, {
19 | __call = function(gg, ...)
20 | for _, g in ipairs(gg.__when) do
21 | if g.filter(...) then
22 | return g.f(...)
23 | end
24 | end
25 | if gg.__any then
26 | return gg.__any(...)
27 | end
28 | return error("guard: No guard defined for given arguments.", 0)
29 | end,
30 | })
31 | end
32 |
33 | return setmetatable({
34 | _DESCRIPTION = "Elixir-style guards for Lua",
35 | _VERSION = "guard v0.0.1",
36 | _URL = "http://github.com/Yonaba/guard.lua",
37 | _LICENSE = "MIT LICENSE ",
38 | }, { __call = function()
39 | return _guardian()
40 | end })
41 |
--------------------------------------------------------------------------------
/internal/lua/map.lua:
--------------------------------------------------------------------------------
1 | --- Bimap implementation by Pierre 'catwell' Chapuis
2 | --- MIT licensed (see LICENSE.txt)
3 |
4 | local _newindex = function(l, r)
5 | return function(_, k, v)
6 | if v ~= nil then
7 | if r[v] then
8 | error(
9 | string.format(
10 | "cannot assign value %q to key %q: already assigned to key %q",
11 | tostring(v), tostring(k), tostring(r[v])
12 | ),
13 | 2
14 | )
15 | end
16 | r[v] = k
17 | end
18 | if l[k] ~= nil then
19 | r[l[k]] = nil
20 | end
21 | l[k] = v
22 | end
23 | end
24 |
25 | local _call = function(l)
26 | return function(_, x)
27 | if x == "len" then
28 | return #l
29 | elseif x == "raw" then
30 | return l
31 | end
32 | end
33 | end
34 |
35 | local new = function(l_val)
36 | if l_val == nil then
37 | l_val = {}
38 | end
39 | assert(type(l_val) == "table")
40 | local r_val = {}
41 | for k,v in pairs(l_val) do
42 | r_val[v] = k
43 | end
44 | local l_proxy = setmetatable({}, {
45 | __index = l_val,
46 | __len = function(_)
47 | return #l_val
48 | end,
49 | __newindex = _newindex(l_val, r_val),
50 | __call = _call(l_val, r_val),
51 | })
52 | local r_proxy = setmetatable({}, {
53 | __index = r_val,
54 | __len = function(_)
55 | return #r_val
56 | end,
57 | __newindex = _newindex(r_val, l_val),
58 | __call = _call(r_val, l_val),
59 | })
60 | return l_proxy, r_proxy
61 | end
62 |
63 | return {
64 | new = new,
65 | }
66 |
--------------------------------------------------------------------------------
/internal/lua/queue.lua:
--------------------------------------------------------------------------------
1 | --- Deque implementation by Pierre 'catwell' Chapuis
2 | --- MIT licensed (see LICENSE.txt)
3 |
4 | local push_back = function(self, x)
5 | assert(x ~= nil, "deque.push_back: Value cannot be nil.")
6 | self.tail = self.tail + 1
7 | self[self.tail] = x
8 | end
9 |
10 | local push_front = function(self, x)
11 | assert(x ~= nil, "deque.push_front: Value cannot be nil.")
12 | self[self.head] = x
13 | self.head = self.head - 1
14 | end
15 |
16 | local peek_back = function(self)
17 | return self[self.tail]
18 | end
19 |
20 | local peek_front = function(self)
21 | return self[self.head+1]
22 | end
23 |
24 | local pop_back = function(self)
25 | if self:is_empty() then return nil end
26 | local r = self[self.tail]
27 | self[self.tail] = nil
28 | self.tail = self.tail - 1
29 | return r
30 | end
31 |
32 | local pop_front = function(self)
33 | if self:is_empty() then return nil end
34 | local r = self[self.head+1]
35 | self.head = self.head + 1
36 | r = self[self.head]
37 | self[self.head] = nil
38 | return r
39 | end
40 |
41 | local rotate_back = function(self, n)
42 | n = n or 1
43 | if self:is_empty() then return nil end
44 | for _=1,n do
45 | self:push_front(self:pop_back())
46 | end
47 | end
48 |
49 | local rotate_front = function(self, n)
50 | n = n or 1
51 | if self:is_empty() then return nil end
52 | for _=1,n do
53 | self:push_back(self:pop_front())
54 | end
55 | end
56 |
57 | local _remove_at_internal = function(self, idx)
58 | for i=idx, self.tail do
59 | self[i] = self[i+1]
60 | end
61 | self.tail = self.tail - 1
62 | end
63 |
64 | local remove_back = function(self, x)
65 | for i=self.tail,self.head+1,-1 do
66 | if self[i] == x then
67 | _remove_at_internal(self, i)
68 | return true
69 | end
70 | end
71 | return false
72 | end
73 |
74 | local remove_front = function(self, x)
75 | for i=self.head+1,self.tail do
76 | if self[i] == x then
77 | _remove_at_internal(self, i)
78 | return true
79 | end
80 | end
81 | return false
82 | end
83 |
84 | local size = function(self)
85 | return self.tail - self.head
86 | end
87 |
88 | local is_empty = function(self)
89 | return self:size() == 0
90 | end
91 |
92 | local contents = function(self)
93 | local r = {}
94 | for i=self.head+1,self.tail do
95 | r[i-self.head] = self[i]
96 | end
97 | return r
98 | end
99 |
100 | local iter_back = function(self)
101 | local i = self.tail+1
102 | return function()
103 | if i > self.head+1 then
104 | i = i-1
105 | return self[i]
106 | end
107 | end
108 | end
109 |
110 | local iter_front = function(self)
111 | local i = self.head
112 | return function()
113 | if i < self.tail then
114 | i = i+1
115 | return self[i]
116 | end
117 | end
118 | end
119 |
120 | local methods = {
121 | push_back = push_back,
122 | push = push_back,
123 | push_front = push_front,
124 | peek_back = peek_back,
125 | peek_front = peek_front,
126 | pop_back = pop_back,
127 | pop = pop_back,
128 | pop_front = pop_front,
129 | rotate_back = rotate_back,
130 | rotate_front = rotate_front,
131 | remove_back = remove_back,
132 | remove_front = remove_front,
133 | iter_back = iter_back,
134 | iter_front = iter_front,
135 | iterator = iter_front,
136 | size = size,
137 | is_empty = is_empty,
138 | contents = contents,
139 | }
140 |
141 | local new = function()
142 | local r = {head = 0, tail = 0}
143 | return setmetatable(r, {__index = methods})
144 | end
145 |
146 | return {
147 | new = new,
148 | }
149 |
--------------------------------------------------------------------------------
/internal/lz4.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "bytes"
5 | "github.com/pierrec/lz4"
6 | "github.com/yuin/gopher-lua"
7 | "io"
8 | "strings"
9 | )
10 |
11 | func lz4Compress(L *lua.LState) int {
12 | s := L.CheckString(1)
13 | r := strings.NewReader(s)
14 | pr, pw := io.Pipe()
15 | zw := lz4.NewWriter(pw)
16 | go func() {
17 | _, _ = io.Copy(zw, r)
18 | _ = zw.Close()
19 | _ = pw.Close()
20 | }()
21 | if b, err := io.ReadAll(pr); err == nil {
22 | L.Push(lua.LString(b))
23 | return 1
24 | } else {
25 | L.Push(lua.LNil)
26 | L.Push(lua.LString("Unable to compress."))
27 | return 2
28 | }
29 | }
30 |
31 | func lz4Decompress(L *lua.LState) int {
32 | s := L.CheckString(1)
33 | r := strings.NewReader(s)
34 | var out bytes.Buffer
35 | zr := lz4.NewReader(r)
36 | _, err := io.Copy(&out, zr)
37 | if err == nil {
38 | L.Push(lua.LString(out.String()))
39 | return 1
40 | } else {
41 | L.Push(lua.LNil)
42 | L.Push(lua.LString("Unable to decompress."))
43 | return 2
44 | }
45 | }
46 |
47 | func Lz4Loader(L *lua.LState) int {
48 | t := L.NewTable()
49 | L.SetFuncs(t, lz4Api)
50 | L.Push(t)
51 | return 1
52 | }
53 |
54 | var lz4Api = map[string]lua.LGFunction{
55 | "compress": lz4Compress,
56 | "decompress": lz4Decompress,
57 | }
58 |
--------------------------------------------------------------------------------
/internal/os.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/yuin/gopher-lua"
5 | "net"
6 | "os"
7 | "time"
8 | )
9 |
10 | func OsHostname(L *lua.LState) int {
11 | name, err := os.Hostname()
12 | if err != nil {
13 | L.Push(lua.LNil)
14 | L.Push(lua.LString(err.Error()))
15 | return 2
16 | }
17 | L.Push(lua.LString(name))
18 | return 1
19 | }
20 |
21 | func OsSleep(L *lua.LState) int {
22 | n := L.CheckNumber(1)
23 | time.Sleep(time.Duration(n) * time.Millisecond)
24 | L.Push(lua.LTrue)
25 | return 1
26 | }
27 |
28 | func OsOutboundIP(L *lua.LState) int {
29 | conn, err := net.Dial("udp", "1.1.1.1:53")
30 | if err != nil {
31 | L.Push(lua.LNil)
32 | L.Push(lua.LString(err.Error()))
33 | return 2
34 | }
35 | defer conn.Close()
36 | localAddr := conn.LocalAddr().(*net.UDPAddr)
37 | L.Push(lua.LString(localAddr.IP.String()))
38 | return 1
39 | }
40 |
--------------------------------------------------------------------------------
/internal/pushover.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/gregdel/pushover"
5 | "github.com/yuin/gopher-lua"
6 | "os"
7 | )
8 |
9 | const (
10 | PUSHOVER_TYPE = "pushover{api}"
11 | )
12 |
13 | func pushoverCheck(L *lua.LState) *pushover.Pushover {
14 | ud := L.CheckUserData(1)
15 | if v, ok := ud.Value.(*pushover.Pushover); ok {
16 | return v
17 | } else {
18 | return nil
19 | }
20 | }
21 |
22 | func pushoverMessage(L *lua.LState) int {
23 | p := pushoverCheck(L)
24 | if p == nil {
25 | L.Push(lua.LNil)
26 | L.Push(lua.LString("pushover.message: Initializing with Pushover token failed."))
27 | return 2
28 | }
29 | r := L.CheckString(2)
30 | m := L.CheckString(3)
31 | recipient := pushover.NewRecipient(r)
32 | message := pushover.NewMessage(m)
33 | response, err := p.SendMessage(message, recipient)
34 | if err != nil {
35 | L.Push(lua.LNil)
36 | L.Push(lua.LString(err.Error()))
37 | return 2
38 | }
39 | L.Push(lua.LString(response.String()))
40 | return 1
41 | }
42 |
43 | var pushoverMethods = map[string]lua.LGFunction{
44 | "message": pushoverMessage,
45 | }
46 |
47 | var pushoverExports = map[string]lua.LGFunction{
48 | "new": pushoverNew,
49 | }
50 |
51 | func PushoverLoader(L *lua.LState) int {
52 | mod := L.SetFuncs(L.NewTable(), pushoverExports)
53 | L.Push(mod)
54 | pushoverRegister(L)
55 | return 1
56 | }
57 |
58 | func pushoverRegister(L *lua.LState) {
59 | mt := L.NewTypeMetatable(PUSHOVER_TYPE)
60 | L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), pushoverMethods))
61 | }
62 |
63 | func pushoverNew(L *lua.LState) int {
64 | token := os.Getenv("PUSHOVER_TOKEN")
65 | ud := L.NewUserData()
66 | p := pushover.New(token)
67 | ud.Value = p
68 | L.SetMetatable(ud, L.GetTypeMetatable(PUSHOVER_TYPE))
69 | L.Push(ud)
70 | return 1
71 | }
72 |
--------------------------------------------------------------------------------
/internal/refmt.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "encoding/json"
5 |
6 | gyaml "github.com/ghodss/yaml"
7 | toml "github.com/pelletier/go-toml"
8 | lua "github.com/yuin/gopher-lua"
9 | )
10 |
11 | func refmtToYAML(L *lua.LState) int {
12 | j := L.CheckString(1)
13 | y, err := gyaml.JSONToYAML([]byte(j))
14 | if err != nil {
15 | L.Push(lua.LNil)
16 | L.Push(lua.LString(err.Error()))
17 | return 2
18 | } else {
19 | L.Push(lua.LString(y))
20 | return 1
21 | }
22 | }
23 |
24 | func refmtToJSON(L *lua.LState) int {
25 | y := L.CheckString(1)
26 | j, err := gyaml.YAMLToJSON([]byte(y))
27 | if err != nil {
28 | L.Push(lua.LNil)
29 | L.Push(lua.LString(err.Error()))
30 | return 2
31 | } else {
32 | L.Push(lua.LString(j))
33 | return 1
34 | }
35 | }
36 |
37 | func refmtTOMLToJSON(L *lua.LState) int {
38 | s := L.CheckString(1)
39 | var tree *toml.Tree
40 | var err error
41 | if tree, err = toml.LoadBytes([]byte(s)); err != nil {
42 | L.Push(lua.LNil)
43 | L.Push(lua.LString(err.Error()))
44 | return 2
45 | }
46 | var bytes []byte
47 | treeMap := tree.ToMap()
48 | if bytes, err = json.MarshalIndent(treeMap, "", " "); err != nil {
49 | L.Push(lua.LNil)
50 | L.Push(lua.LString(err.Error()))
51 | return 2
52 | }
53 | L.Push(lua.LString(string(bytes[:])))
54 | return 1
55 | }
56 |
57 | func refmtJSONToTOML(L *lua.LState) int {
58 | s := L.CheckString(1)
59 | jsonMap := make(map[string]interface{})
60 | var err error
61 | jsonBytes := []byte(s)
62 | if err != nil {
63 | L.Push(lua.LNil)
64 | L.Push(lua.LString(err.Error()))
65 | return 2
66 | }
67 | err = json.Unmarshal(jsonBytes, &jsonMap)
68 | if err != nil {
69 | L.Push(lua.LNil)
70 | L.Push(lua.LString(err.Error()))
71 | return 2
72 | }
73 | tree, err := toml.TreeFromMap(jsonMap)
74 | if err != nil {
75 | L.Push(lua.LNil)
76 | L.Push(lua.LString(err.Error()))
77 | return 2
78 | }
79 | tomlBytes, err := tree.ToTomlString()
80 | if err != nil {
81 | L.Push(lua.LNil)
82 | L.Push(lua.LString(err.Error()))
83 | return 2
84 | }
85 | L.Push(lua.LString(string(tomlBytes[:])))
86 | return 1
87 | }
88 |
89 | func RefmtLoader(L *lua.LState) int {
90 | t := L.NewTable()
91 | L.SetFuncs(t, refmtApi)
92 | L.Push(t)
93 | return 1
94 | }
95 |
96 | var refmtApi = map[string]lua.LGFunction{
97 | "json": refmtToJSON,
98 | "yaml": refmtToYAML,
99 | "yaml_to_json": refmtToJSON,
100 | "json_to_yaml": refmtToYAML,
101 | "toml_to_json": refmtTOMLToJSON,
102 | "json_to_toml": refmtJSONToTOML,
103 | }
104 |
--------------------------------------------------------------------------------
/internal/slack.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/slack-go/slack"
5 | "github.com/yuin/gluamapper"
6 | "github.com/yuin/gopher-lua"
7 | "os"
8 | )
9 |
10 | func slackWebhookMessage(L *lua.LState) int {
11 | a := L.CheckString(1)
12 | msg := slack.WebhookMessage{
13 | Text: a,
14 | }
15 | token := "https://hooks.slack.com/services/" + os.Getenv("SLACK_WEBHOOK")
16 | err := slack.PostWebhook(token, &msg)
17 | if err != nil {
18 | L.Push(lua.LNil)
19 | L.Push(lua.LString(err.Error()))
20 | return 2
21 | }
22 | L.Push(lua.LTrue)
23 | return 1
24 | }
25 |
26 | func slackWebhookAttachment(L *lua.LState) int {
27 | a := L.CheckTable(1)
28 | var gostubs slack.Attachment
29 | {
30 | err := gluamapper.Map(a, &gostubs)
31 |
32 | if err != nil {
33 | L.Push(lua.LNil)
34 | L.Push(lua.LString(err.Error()))
35 | return 2
36 | }
37 | }
38 | msg := slack.WebhookMessage{
39 | Attachments: []slack.Attachment{gostubs},
40 | }
41 | token := "https://hooks.slack.com/services/" + os.Getenv("SLACK_WEBHOOK")
42 | err := slack.PostWebhook(token, &msg)
43 | if err != nil {
44 | L.Push(lua.LNil)
45 | L.Push(lua.LString(err.Error()))
46 | return 2
47 | }
48 | L.Push(lua.LTrue)
49 | return 1
50 | }
51 |
52 | func SlackLoader(L *lua.LState) int {
53 | t := L.NewTable()
54 | L.SetFuncs(t, slackApi)
55 | L.Push(t)
56 | return 1
57 | }
58 |
59 | var slackApi = map[string]lua.LGFunction{
60 | "attachment": slackWebhookAttachment,
61 | "message": slackWebhookMessage,
62 | }
63 |
--------------------------------------------------------------------------------
/internal/ssh_config.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | "github.com/kevinburke/ssh_config"
8 | "github.com/yuin/gopher-lua"
9 | )
10 |
11 | func sshconfigPort(L *lua.LState) int {
12 | host := L.CheckString(1)
13 | port := ssh_config.Get(host, "Port")
14 | if port != "" {
15 | L.Push(lua.LString(port))
16 | return 1
17 | } else {
18 | L.Push(lua.LNil)
19 | L.Push(lua.LString("ssh_config: No such host."))
20 | return 2
21 | }
22 |
23 | }
24 |
25 | func sshconfigIdentityFile(L *lua.LState) int {
26 | host := L.CheckString(1)
27 | key := ssh_config.Get(host, "IdentityFile")
28 | if key != "" {
29 | L.Push(lua.LString(key))
30 | return 1
31 | } else {
32 | L.Push(lua.LNil)
33 | L.Push(lua.LString("ssh_config: No such host."))
34 | return 2
35 | }
36 | }
37 |
38 | func sshconfigHostname(L *lua.LState) int {
39 | host := L.CheckString(1)
40 | hn := ssh_config.Get(host, "Hostname")
41 | if hn != "" {
42 | L.Push(lua.LString(hn))
43 | return 1
44 | } else {
45 | L.Push(lua.LNil)
46 | L.Push(lua.LString("ssh_config: No such host."))
47 | return 2
48 | }
49 | }
50 |
51 | func sshconfigHosts(L *lua.LState) int {
52 | f, ferr := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config"))
53 | if ferr != nil {
54 | L.Push(lua.LNil)
55 | L.Push(lua.LString(ferr.Error()))
56 | return 2
57 | }
58 | // TODO: cerr does not do anything?
59 | c, cerr := ssh_config.Decode(f)
60 | if cerr != nil {
61 | L.Push(lua.LNil)
62 | L.Push(lua.LString(cerr.Error()))
63 | return 2
64 | }
65 | t := L.NewTable()
66 | for _, host := range c.Hosts {
67 | for _, pat := range host.Patterns {
68 | s := pat.String()
69 | if s != "*" {
70 | t.Append(lua.LString(s))
71 | }
72 | }
73 | }
74 | L.Push(t)
75 | return 1
76 | }
77 |
78 | func SSHconfigLoader(L *lua.LState) int {
79 | t := L.NewTable()
80 | L.SetFuncs(t, sshconfigApi)
81 | L.Push(t)
82 | return 1
83 | }
84 |
85 | var sshconfigApi = map[string]lua.LGFunction{
86 | "port": sshconfigPort,
87 | "identity_file": sshconfigIdentityFile,
88 | "hostname": sshconfigHostname,
89 | "hosts": sshconfigHosts,
90 | }
91 |
--------------------------------------------------------------------------------
/internal/telegram.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/go-telegram-bot-api/telegram-bot-api"
5 | "github.com/yuin/gopher-lua"
6 | "os"
7 | )
8 |
9 | const (
10 | TELEGRAM_TYPE = "telegram{bot}"
11 | )
12 |
13 | func telegramCheck(L *lua.LState) *tgbotapi.BotAPI {
14 | ud := L.CheckUserData(1)
15 | if v, ok := ud.Value.(*tgbotapi.BotAPI); ok {
16 | return v
17 | } else {
18 | return nil
19 | }
20 | }
21 |
22 | func telegramMessage(L *lua.LState) int {
23 | bot := telegramCheck(L)
24 | if bot == nil {
25 | L.Push(lua.LNil)
26 | L.Push(lua.LString("telegram.message: Initializing with Telegram token failed."))
27 | return 2
28 | }
29 | i := L.CheckInt64(2)
30 | m := L.CheckString(3)
31 | msg := tgbotapi.NewMessage(i, m)
32 | if _, err := bot.Send(msg); err != nil {
33 | L.Push(lua.LNil)
34 | L.Push(lua.LString(err.Error()))
35 | return 2
36 | }
37 | L.Push(lua.LTrue)
38 | return 1
39 | }
40 |
41 | func telegramChannelMessage(L *lua.LState) int {
42 | bot := telegramCheck(L)
43 | if bot == nil {
44 | L.Push(lua.LNil)
45 | L.Push(lua.LString("telegram.channel: Initializing with Telegram token failed."))
46 | return 1
47 | }
48 | c := L.CheckString(2)
49 | m := L.CheckString(3)
50 | msg := tgbotapi.NewMessageToChannel(c, m)
51 | if _, err := bot.Send(msg); err != nil {
52 | L.Push(lua.LNil)
53 | L.Push(lua.LString(err.Error()))
54 | return 2
55 | }
56 | L.Push(lua.LTrue)
57 | return 1
58 | }
59 |
60 | var telegramMethods = map[string]lua.LGFunction{
61 | "message": telegramMessage,
62 | "channel": telegramChannelMessage,
63 | }
64 |
65 | var telegramExports = map[string]lua.LGFunction{
66 | "new": telegramNew,
67 | }
68 |
69 | func TelegramLoader(L *lua.LState) int {
70 | mod := L.SetFuncs(L.NewTable(), telegramExports)
71 | L.Push(mod)
72 | telegramRegister(L)
73 | return 1
74 | }
75 |
76 | func telegramRegister(L *lua.LState) {
77 | mt := L.NewTypeMetatable(TELEGRAM_TYPE)
78 | L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), telegramMethods))
79 | }
80 |
81 | func telegramNew(L *lua.LState) int {
82 | token := os.Getenv("TELEGRAM_TOKEN")
83 | ud := L.NewUserData()
84 | bot, err := tgbotapi.NewBotAPI(token)
85 | if err == nil {
86 | ud.Value = bot
87 | } else {
88 | ud.Value = nil
89 | }
90 | L.SetMetatable(ud, L.GetTypeMetatable(TELEGRAM_TYPE))
91 | L.Push(ud)
92 | return 1
93 | }
94 |
--------------------------------------------------------------------------------
/internal/ulid.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "bytes"
5 | "github.com/oklog/ulid/v2"
6 | "github.com/yuin/gopher-lua"
7 | "hash/maphash"
8 | "strconv"
9 | "time"
10 | )
11 |
12 | func ulidNew(L *lua.LState) int {
13 | b := []byte(strconv.FormatUint(new(maphash.Hash).Sum64(), 10))
14 | e := bytes.NewReader(b)
15 | id, err := ulid.New(ulid.Timestamp(time.Now()), e)
16 | if err != nil {
17 | L.Push(lua.LNil)
18 | L.Push(lua.LString(err.Error()))
19 | return 2
20 | }
21 | L.Push(lua.LString(id.String()))
22 | return 1
23 | }
24 |
25 | func UlidLoader(L *lua.LState) int {
26 | t := L.NewTable()
27 | L.SetFuncs(t, ulidApi)
28 | L.Push(t)
29 | return 1
30 | }
31 |
32 | var ulidApi = map[string]lua.LGFunction{
33 | "new": ulidNew,
34 | }
35 |
--------------------------------------------------------------------------------
/internal/uuid.go:
--------------------------------------------------------------------------------
1 | package ll
2 |
3 | import (
4 | "github.com/hashicorp/go-uuid"
5 | "github.com/yuin/gopher-lua"
6 | )
7 |
8 | func uuidNew(L *lua.LState) int {
9 | id, err := uuid.GenerateUUID()
10 | if err != nil {
11 | L.Push(lua.LNil)
12 | L.Push(lua.LString(err.Error()))
13 | return 2
14 | }
15 | L.Push(lua.LString(id))
16 | return 1
17 | }
18 |
19 | func UuidLoader(L *lua.LState) int {
20 | t := L.NewTable()
21 | L.SetFuncs(t, uuidApi)
22 | L.Push(t)
23 | return 1
24 | }
25 |
26 | var uuidApi = map[string]lua.LGFunction{
27 | "new": uuidNew,
28 | }
29 |
--------------------------------------------------------------------------------
/scripts/.lib/000-header.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | unset IFS
3 | set -o errexit -o nounset -o noglob
4 | export PATH=/bin:/sbin:/usr/bin:/usr/sbin
5 | export LC_ALL=C
6 |
7 | __mark()
8 | {
9 | printf >&2 "► “%s”\\n" "$*"
10 | printf "► “%s”\\n" "$*"
11 | }
12 |
--------------------------------------------------------------------------------
/scripts/.lib/001-go.sh:
--------------------------------------------------------------------------------
1 | _go_os()
2 | {
3 | local os
4 | os=$(uname -s | tr '[:upper:]' '[:lower:]')
5 | printf "%s" "${os}"
6 | }
7 |
--------------------------------------------------------------------------------
/scripts/build-dsl/script:
--------------------------------------------------------------------------------
1 | mkdir -p "cmd/$1"
2 | sed "s|//__DSL__||" cmd/dsl/main.go > "cmd/$1/main.go"
3 | sed -i "s|__DSLMOD__|$1|g" "cmd/$1/main.go"
4 | GOOS=$(_go_os) CGO_ENABLED=0 go build \
5 | -trimpath -ldflags '-s -w -extldflags "-static"' \
6 | -o "bin/$1" "./cmd/$1"
7 |
--------------------------------------------------------------------------------
/scripts/build-pie/script:
--------------------------------------------------------------------------------
1 | GOOS=linux CGO_ENABLED=0 go build \
2 | -buildmode=pie -trimpath -ldflags '-s -w -extldflags "-static -Wl,-z,now,-z,relro"' \
3 | -o "ll" .
4 |
--------------------------------------------------------------------------------
/scripts/build-standalone/script:
--------------------------------------------------------------------------------
1 | GOOS=$(_go_os) CGO_ENABLED=0 go build \
2 | -trimpath -ldflags '-s -w -extldflags "-static"' \
3 | -o "bin/$1" "./cmd/$1"
4 |
--------------------------------------------------------------------------------
/scripts/build-test/script:
--------------------------------------------------------------------------------
1 | cp cmd/standalone/main.go cmd/test
2 | GOOS=$(_go_os) CGO_ENABLED=0 go build \
3 | -trimpath -ldflags '-s -w -extldflags "-static"' \
4 | -o bin/test "./cmd/test"
5 |
--------------------------------------------------------------------------------
/scripts/build/script:
--------------------------------------------------------------------------------
1 | GOOS=$(_go_os) CGO_ENABLED=0 go build \
2 | -trimpath -ldflags '-s -w -extldflags "-static"' \
3 | -o "bin/ll" ./cmd/ll
4 |
--------------------------------------------------------------------------------
/scripts/docs/script:
--------------------------------------------------------------------------------
1 | awk '/^.*--#/{$1="";print $0}/^.*--#$/{print "\\n"}' "tests/${1}.lua" | cut -f2- -d' ' > "docs/${1}.adoc"
2 |
--------------------------------------------------------------------------------
/scripts/godocs/script:
--------------------------------------------------------------------------------
1 | awk '/^.*\/\/#/{$1="";print $0}/^.*\/\/#$/{print "\\n"}' "${1}.go" | cut -f2- -d' ' > "docs/go-${1}.adoc"
2 |
--------------------------------------------------------------------------------
/scripts/install/script:
--------------------------------------------------------------------------------
1 | cp "$1/github/LadyLua/ll" /usr/bin/ll
2 |
--------------------------------------------------------------------------------
/scripts/lint/script:
--------------------------------------------------------------------------------
1 | __mark gosec -exlude-dir external .
2 | $HOME/bin/gosec.v2.7.0 -exclude-dir external .
3 | __mark staticcheck *.go
4 | $HOME/bin/staticcheck.2020.2.3 exec.go fs.go global.go html.go lib.go ll.go os.go uid.go
5 | __mark selene lua/*.lua
6 | $HOME/bin/selene.0.11.0 lua/exec.lua lua/fmt.lua lua/table.lua lua/string.lua
7 |
--------------------------------------------------------------------------------
/scripts/show-functions/script:
--------------------------------------------------------------------------------
1 | grep -F "function(" "lua/${1}.lua"
2 |
--------------------------------------------------------------------------------
/scripts/template-test/script:
--------------------------------------------------------------------------------
1 | cp scripts/template-test/template.txt "tests/$1.lua"
2 |
--------------------------------------------------------------------------------
/scripts/template-test/template.txt:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require 'test'
3 | --# = ??
4 | --# :toc:
5 | --# :toc-placement!:
6 | --#
7 | --# ???/
8 | --#
9 | --# toc::[]
10 | --#
11 | --# == *??.??*(_String_, _String_)
12 | --# ??
13 | --#
14 | --# === Arguments
15 | --# [options="header",width="72%"]
16 | --# |===
17 | --# |Type |Description
18 | --# |??| ??
19 | --# |??| ??
20 | --# |===
21 | --#
22 | --# === Returns
23 | --# [options="header",width="72%"]
24 | --# |===
25 | --# |Type |Description
26 | --# |??| ??
27 | --# |===
28 | local ??_?? = function()
29 | T.is_function(??.??)
30 | local x = "one"
31 | local y = "two"
32 | local z = ??.??(x, y)
33 | T.equal(z, "one\ntwo")
34 | end
35 | if included then
36 | return function()
37 | T["??.??"] = ??_??
38 | end
39 | else
40 | T["??.??"] = ??_??
41 | end
42 |
--------------------------------------------------------------------------------
/scripts/test/script:
--------------------------------------------------------------------------------
1 | bin/test
2 |
--------------------------------------------------------------------------------
/selene.toml:
--------------------------------------------------------------------------------
1 | std = "ll"
2 |
3 | [rules]
4 | global_usage = "allow"
5 |
--------------------------------------------------------------------------------
/stylua.toml:
--------------------------------------------------------------------------------
1 | quote_style = "AutoPreferDouble"
2 | indent_width = 8
3 | indent_type = "Tabs"
4 | column_width = 120
5 |
--------------------------------------------------------------------------------
/tests/argparse.lua:
--------------------------------------------------------------------------------
1 | package.path = "internal/lua/?.lua"
2 | local included = pcall(debug.getlocal, 4, 1)
3 | local T = require("test")
4 | local A = require("argparse")
5 | local expect = T.expect
6 | local is_table = T.is_table
7 | local new = function()
8 | local parser = A()
9 | local p = parser:parse({})
10 | is_table(p)
11 | end
12 | local one_arg = function()
13 | local parser = A()
14 | parser:argument("foo")
15 | local args = parser:parse({"bar"})
16 | expect("bar")(args.foo)
17 | end
18 | local opt_arg = function()
19 | local parser = A()
20 | parser:argument("foo"):args("?")
21 | local args = parser:parse({"bar"})
22 | expect("bar")(args.foo)
23 | end
24 | local many_args = function()
25 | local parser = A()
26 | parser:argument("foo1")
27 | parser:argument("foo2")
28 | local args = parser:parse({"bar", "baz"})
29 | expect("bar")(args.foo1)
30 | expect("baz")(args.foo2)
31 | end
32 | local wildcard_args = function()
33 | local parser = A()
34 | parser:argument("foo"):args("*")
35 | local args = parser:parse({"bar", "baz", "qu"})
36 | expect("bar")(args.foo[1])
37 | expect("baz")(args.foo[2])
38 | expect("qu")(args.foo[3])
39 | end
40 | local hyphens = function()
41 | local parser = A()
42 | parser:argument("foo")
43 | local args = parser:parse({"-"})
44 | expect("-")(args.foo)
45 | args = parser:parse({"--", "-q"})
46 | expect("-q")(args.foo)
47 | end
48 | local commands_after_args = function()
49 | local parser = A("name")
50 | parser:argument("file")
51 | parser:command("create")
52 | parser:command("remove")
53 | local args = parser:parse{"temp.txt", "remove"}
54 | expect("temp.txt")(args.file)
55 | expect(true)(args.remove)
56 | end
57 | local command_flags = function()
58 | local parser = A("name")
59 | local install = parser:command("install")
60 | install:flag "-q" "--quiet"
61 | local args = parser:parse{"install", "-q"}
62 | expect(true)(args.install)
63 | expect(true)(args.quiet)
64 | end
65 | local nested_commands = function()
66 | local parser = A("name")
67 | local install = parser:command("install")
68 | install:command("bar")
69 | local args = parser:parse{"install", "bar"}
70 | expect(true)(args.install)
71 | expect(true)(args.bar)
72 | end
73 | local action_args = function()
74 | local parser = A()
75 | local foo
76 | parser:argument("foo"):action(function(_, _, passed)
77 | foo = passed
78 | end)
79 | local baz
80 | parser:argument("baz"):args("*"):action(function(_, _, passed)
81 | baz = passed
82 | end)
83 | parser:parse({"a"})
84 | expect("a")(foo)
85 | expect(0)(#baz)
86 | parser:parse({"b", "c"})
87 | expect("b")(foo)
88 | expect("c")(baz[1])
89 | parser:parse({"d", "e", "f"})
90 | expect("d")(foo)
91 | expect("e")(baz[1])
92 | expect("f")(baz[2])
93 | end
94 | if included then
95 | return function()
96 | T["new parser"] = new
97 | T["one argument"] = one_arg
98 | T["optional argument"] = opt_arg
99 | T["several arguments"] = many_args
100 | T["wildcard arguments"] = wildcard_args
101 | T["hyphens"] = hyphens
102 | T["commands after arguments"] = commands_after_args
103 | T["command flags"] = command_flags
104 | T["nested commands"] = nested_commands
105 | T["action on arguments"] = action_args
106 | end
107 | else
108 | T["new parser"] = new
109 | T["one argument"] = one_arg
110 | T["optional argument"] = opt_arg
111 | T["several arguments"] = many_args
112 | T["wildcard arguments"] = wildcard_args
113 | T["hyphens"] = hyphens
114 | T["commands after arguments"] = commands_after_args
115 | T["command flags"] = command_flags
116 | T["nested commands"] = nested_commands
117 | T["action on arguments"] = action_args
118 | end
119 |
--------------------------------------------------------------------------------
/tests/exec_cmd.lua:
--------------------------------------------------------------------------------
1 | local l = exec.cmd("l")
2 | l()
3 | fmt.print("first l() ok\n")
4 | fmt.print("next l() will fail\n")
5 | l.error = "custom error"
6 | l.errexit = true
7 | l()
8 |
--------------------------------------------------------------------------------
/tests/extension_json.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local J = require("json")
4 | extend("json")
5 | local expect = T.expect
6 | --# = extension: json
7 | --# :toc:
8 | --# :toc-placement!:
9 | --#
10 | --# Additional functions for the `json` module.
11 | --#
12 | --# To load and patch `json` namespace:
13 | --# ----
14 | --# extend("json")
15 | --# ----
16 | --#
17 | --# toc::[]
18 | --#
19 | --# == *json.array*(_String_)
20 | --# JSON array iterator
21 | --#
22 | --# === Arguments
23 | --# [options="header",width="72%"]
24 | --# |===
25 | --# |Type |Description
26 | --# |string |JSON
27 | --# |===
28 | local json_array = function()
29 | T.is_function(J.array)
30 | local t = {
31 | "one",
32 | "two",
33 | "three",
34 | }
35 | local e = {}
36 | for x, y in J.array(J.encode(t)) do
37 | e[x] = y
38 | end
39 | expect(t[1])(e[1])
40 | expect(t[2])(e[2])
41 | expect(t[3])(e[3])
42 | end
43 | --#
44 | --# == *json.object*(_String_)
45 | --# JSON object iterator.
46 | --#
47 | --# === Arguments
48 | --# [options="header",width="72%"]
49 | --# |===
50 | --# |Type |Description
51 | --# |string |JSON
52 | --# |===
53 | local json_object = function()
54 | T.is_function(J.object)
55 | local t = {
56 | one = 1,
57 | two = 2,
58 | three = 3,
59 | }
60 | local e = {}
61 | for x, y in J.object(J.encode(t)) do
62 | e[x] = y
63 | end
64 | expect(t.one)(e.one)
65 | expect(t.two)(e.two)
66 | expect(t.three)(e.three)
67 | end
68 | if included then
69 | return function()
70 | T["json array iterator"] = json_array
71 | T["json object iterator"] = json_object
72 | end
73 | else
74 | T["json array iterator"] = json_array
75 | T["json object iterator"] = json_object
76 | end
77 |
--------------------------------------------------------------------------------
/tests/fmt.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local fmt = require("fmt")
3 | local T = require("test")
4 | --# = fmt
5 | --# :toc:
6 | --# :toc-placement!:
7 | --#
8 | --# Format string variants that wraps `string.format`. +
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *fmt.print*(_String_, _..._)
13 | --# Print formatted string to io.stdout.
14 | --#
15 | --# === Arguments
16 | --# [width="72%"]
17 | --# |===
18 | --# |string| Format string
19 | --# |...| Values for the format string
20 | --# |===
21 | local fmt_print = function()
22 | T.is_function(fmt.print)
23 | local x = "prints to STDOUT"
24 | if not included then
25 | fmt.print("%s\n", x)
26 | end
27 | end
28 | --#
29 | --# == *fmt.warn*(_String_, _..._)
30 | --# Print formatted string to io.stderr.
31 | --#
32 | --# === Arguments
33 | --# [width="72%"]
34 | --# |===
35 | --# |string| Format string
36 | --# |...| Values for the format string
37 | --# |===
38 | local fmt_warn = function()
39 | T.is_function(fmt.warn)
40 | local x = "prints to STDERR"
41 | if not included then
42 | fmt.warn("%s\n", x)
43 | end
44 | end
45 | --#
46 | --# == *fmt.error*(_String_, _..._) -> _Nil_, _String_
47 | --# Shortcut for following the Lua convention of returning `nil` and `string` during error conditions.
48 | --#
49 | --# === Arguments
50 | --# [width="72%"]
51 | --# |===
52 | --# |string| Format string
53 | --# |...| Values for the format string
54 | --# |===
55 | --#
56 | --# === Returns
57 | --# [width="72%"]
58 | --# |===
59 | --# |nil| nil
60 | --# |string| Error message
61 | --# |===
62 | local fmt_error = function()
63 | T.is_function(fmt.warn)
64 | local x, y = fmt.error("%s", "message")
65 | T.is_nil(x)
66 | T.equal(y, "message")
67 | end
68 | --#
69 | --# == *fmt.panic*(_String_, _..._)
70 | --# Print formatted string to io.stderr and exit immediately with code 1.
71 | --#
72 | --# === Arguments
73 | --# [width="72%"]
74 | --# |===
75 | --# |string| Format string
76 | --# |...| Values for the format string
77 | --# |===
78 | local fmt_panic = function()
79 | T.is_function(fmt.panic)
80 | local x = "prints to STDERR and exit with code 1"
81 | if not included then
82 | fmt.panic("%s\n", x)
83 | end
84 | end
85 | --#
86 | --# == *fmt.assert*(_Value_, _String_, _..._)
87 | --# Print formatted string to io.stderr and exit immediately with code 1 if argument #1 is falsy(nil or false).
88 | --#
89 | --# === Arguments
90 | --# [width="72%"]
91 | --# |===
92 | --# |value| Any Lua type that can return nil or false
93 | --# |string| Format string
94 | --# |...| Values for the format string
95 | --# |===
96 | local fmt_assert = function()
97 | T.is_function(fmt.assert)
98 | local x = "prints to STDERR when argument #1 is falsy"
99 | if not included then
100 | fmt.assert(false, "%s\n", x)
101 | end
102 | end
103 | if included then
104 | return function()
105 | T["fmt.print"] = fmt_print
106 | T["fmt.warn"] = fmt_warn
107 | T["fmt.error"] = fmt_error
108 | T["fmt.panic"] = fmt_panic
109 | T["fmt.assert"] = fmt_assert
110 | end
111 | else -- ran
112 | fmt_print()
113 | fmt_warn()
114 | fmt_error()
115 | fmt_panic()
116 | fmt_assert()
117 | end
118 |
--------------------------------------------------------------------------------
/tests/fsnotify.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local fsnotify = require("fsnotify")
4 | --# = fsnotify
5 | --# :toc:
6 | --# :toc-placement!:
7 | --#
8 | --# Wait for filesystem create, delete, and write events. All functions block until the specified event is detected.
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *fsnotify.create*(_String_) -> _Boolean_
13 | --# Wait for a create event on path.
14 | --#
15 | --# === Arguments
16 | --# [options="header",width="72%"]
17 | --# |===
18 | --# |Type |Description
19 | --# |string |Path to wait on
20 | --# |===
21 | --#
22 | --# === Returns
23 | --# [options="header",width="72%"]
24 | --# |===
25 | --# |Type |Description
26 | --# |boolean |`true` if create event happened
27 | --# |===
28 | local fsnotify_create = function()
29 | T.is_function(fsnotify.create)
30 | end
31 | --#
32 | --# == *fsnotify.write*(_String_) -> _Boolean_
33 | --# Wait for a write event on path.
34 | --#
35 | --# === Arguments
36 | --# [options="header",width="72%"]
37 | --# |===
38 | --# |Type |Description
39 | --# |string |Path to wait on
40 | --# |===
41 | --#
42 | --# === Returns
43 | --# [options="header",width="72%"]
44 | --# |===
45 | --# |Type |Description
46 | --# |boolean |`true` if write event happened
47 | --# |===
48 | local fsnotify_write = function()
49 | T.is_function(fsnotify.write)
50 | end
51 | --#
52 | --# == *fsnotify.remove*(_String_) -> _Boolean_
53 | --# Wait for a remove event on path.
54 | --#
55 | --# === Arguments
56 | --# [options="header",width="72%"]
57 | --# |===
58 | --# |Type |Description
59 | --# |string |Path to wait on
60 | --# |===
61 | --#
62 | --# === Returns
63 | --# [options="header",width="72%"]
64 | --# |===
65 | --# |Type |Description
66 | --# |boolean |`true` if remove event happened
67 | --# |===
68 | local fsnotify_remove = function()
69 | T.is_function(fsnotify.remove)
70 | end
71 | if included then
72 | return function()
73 | T["fsnotify.create"] = fsnotify_create
74 | T["fsnotify.write"] = fsnotify_write
75 | T["fsnotify.remove"] = fsnotify_remove
76 | end
77 | else
78 | T["fsnotify.create"] = fsnotify_create
79 | T["fsnotify.write"] = fsnotify_write
80 | T["fsnotify.remove"] = fsnotify_remove
81 | end
82 |
--------------------------------------------------------------------------------
/tests/graph.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local graph = require("graph")
3 | local G = graph.new()
4 | local T = require("test")
5 | local expect = T.expect
6 |
7 | local one = function()
8 | G:add("a", "b")
9 | G:add("b", "c")
10 | G:add("0", "a")
11 | local t1 = G:sort()
12 | expect("0")(t1[1])
13 | expect("a")(t1[2])
14 | expect("b")(t1[3])
15 | expect("c")(t1[4])
16 | end
17 | local two = function()
18 | G:add("1", "2", "3", "a")
19 | local t2 = G:sort()
20 | expect("0")(t2[1])
21 | expect("1")(t2[2])
22 | expect("2")(t2[3])
23 | expect("3")(t2[4])
24 | expect("a")(t2[5])
25 | expect("b")(t2[6])
26 | expect("c")(t2[7])
27 | end
28 | local three = function()
29 | G:add({ "1", "1.5" })
30 | G:add({ "1.5", "a" })
31 | local t3 = G:sort()
32 | expect("0")(t3[1])
33 | expect("1")(t3[2])
34 | expect("2")(t3[3])
35 | expect("3")(t3[4])
36 | expect("1.5")(t3[5])
37 | expect("a")(t3[6])
38 | expect("b")(t3[7])
39 | expect("c")(t3[8])
40 | end
41 | local fail = function()
42 | G:add("first", "second")
43 | G:add("second", "third", "first")
44 | local sorted, err = G:sort()
45 | expect(nil)(sorted)
46 | expect("There is a circular dependency in the graph. It is not possible to derive a topological sort.")(err)
47 | end
48 | if included then
49 | return function()
50 | T["graph #1"] = one
51 | T["graph #2"] = two
52 | T["graph #3"] = three
53 | T["graph fail"] = fail
54 | end
55 | else
56 | T["graph #1"] = one
57 | T["graph #2"] = two
58 | T["graph #3"] = three
59 | T["graph fail"] = fail
60 | end
61 |
--------------------------------------------------------------------------------
/tests/guard.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local G = require("guard")
4 | local expect = T.expect
5 | --# = guard
6 | --# :toc:
7 | --# :toc-placement!:
8 | --#
9 | --# Elixir-style guards. One way to avoid nested conditionals.
10 | --#
11 | --# toc::[]
12 | --#
13 | --# == *guard*() -> _Table_
14 | --# Returns new guard factory.
15 | --#
16 | --# === Returns
17 | --# [options="header",width="72%"]
18 | --# |===
19 | --# |Type |Description
20 | --# |table |Guardian table
21 | --# |===
22 | local guard = function()
23 | T.is_table(G)
24 | local tbl = G()
25 | T.is_table(tbl)
26 | end
27 | --#
28 | --# == *.any*(_function_)
29 | --# Fallthrough for a guard chain.
30 | --#
31 | --# === Arguments
32 | --# [options="header",width="72%"]
33 | --# |===
34 | --# |type |description
35 | --# |function |Default case function
36 | --# |===
37 | local any = function()
38 | local tbl = G()
39 | local f = function()
40 | return "default"
41 | end
42 | local f2 = function()
43 | return "new_any"
44 | end
45 | local g = tbl.any(f)
46 | expect("default")(g())
47 | g.any(f2)
48 | expect("new_any")(g())
49 | end
50 | --#
51 | --# == *.when*(_function_, _function_)
52 | --# Expects two functions arguments: the first one being a filter function, and the second one being a function to be evaluated. the filter function should return a boolean. if it returns `true`, the second function argument is evaluated and the guard returns itself right after.
53 | --#
54 | --# === Arguments
55 | --# [options="header",width="72%"]
56 | --# |===
57 | --# |type |description
58 | --# |function |filter
59 | --# |function |main function
60 | --# |===
61 | local when = function()
62 | local tbl = G()
63 | T.is_function(tbl.when)
64 | local x = tbl.when(function()
65 | end, function()
66 | end)
67 | T.is_table(x)
68 | T.error_raised(x)
69 | local is_odd = function(n)
70 | return n % 2 ~= 0
71 | end
72 | local double = function(n)
73 | return n * 2
74 | end
75 | local g = G().when(is_odd, double)
76 | expect(6)(g(3))
77 | T.error_raised(g, "guard: No guard defined for given arguments.", 0)
78 | g.any(function()
79 | return "default case"
80 | end)
81 | expect("default case")(g(2))
82 | end
83 | local chain = function()
84 | local g = G()
85 | local truthy = function()
86 | return true
87 | end
88 | local falsy = function()
89 | return false
90 | end
91 | local f_one = function()
92 | return 1
93 | end
94 | local f_two = function()
95 | return 2
96 | end
97 | local f_three = function()
98 | return 3
99 | end
100 | local f_four = function()
101 | return 4
102 | end
103 | g.when(falsy, f_one).when(truthy, f_two).when(f_three).when(f_four)
104 | local h = G().when(falsy, f_one).when(falsy, f_two).when(falsy, f_three)
105 | expect(2)(g())
106 | T.not_equal(1, g()) --falsy
107 | T.not_equal(3, g()) --falsy
108 | T.not_equal(4, g()) --FIFO
109 | T.error_raised(h)
110 | h.any(f_four)
111 | expect(4)(h())
112 | end
113 | if included then
114 | return function()
115 | T["guard"] = guard
116 | T["any"] = any
117 | T["when"] = when
118 | T["chain"] = chain
119 | end
120 | else
121 | T["guard"] = guard
122 | T["any"] = any
123 | T["when"] = when
124 | T["chain"] = chain
125 | end
126 |
--------------------------------------------------------------------------------
/tests/ksuid.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | --# = ksuid
4 | --# :toc:
5 | --# :toc-placement!:
6 | --#
7 | --# Generate unique IDs. This is a https://github.com/segmentio/ksuid[ksuid] wrapper.
8 | --#
9 | --# toc::[]
10 | --#
11 | --# == *ksuid.new*() -> _String_
12 | --# Generate an ID.
13 | --#
14 | --# === Returns
15 | --# [options="header",width="72%"]
16 | --# |===
17 | --# |Type |Description
18 | --# |string |ksuid string
19 | --# |===
20 | local ksuid_new = function()
21 | local U = require("ksuid")
22 | T.is_function(U.new)
23 | local s = U.new()
24 | local n = U.new()
25 | T.is_string(s)
26 | T.equal(tonumber(#s), 27)
27 | T.not_equal(s, n)
28 | end
29 | if included then
30 | return function()
31 | T["ksuid.new"] = ksuid_new
32 | end
33 | else
34 | T["ksuid.new"] = ksuid_new
35 | end
36 |
--------------------------------------------------------------------------------
/tests/logger.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local logger = require("logger")
4 | local api
5 | --# = logger
6 | --# :toc:
7 | --# :toc-placement!:
8 | --#
9 | --# Structured logging to STDERR, STDOUT, or file.
10 | --# A https://github.com/rs/zerolog[zerolog] wrapper.
11 | --#
12 | --# toc::[]
13 | --#
14 | --# == *logger.new*() -> _Userdata_
15 | --#
16 | --# Initialize object to access methods below.
17 | --#
18 | --# === Arguments
19 | --# [options="header",width="72%"]
20 | --# |===
21 | --# |Type |Description
22 | --# |string |`stdout`, `stderr`, or path to a file, default is `stderr`
23 | --# |===
24 | --#
25 | --# === Returns
26 | --# [options="header",width="72%"]
27 | --# |===
28 | --# |Type |Description
29 | --# |userdata| Userdata with methods below
30 | --# |===
31 | local logger_new = function()
32 | T.is_function(logger.new)
33 | api = logger.new()
34 | T.is_userdata(api)
35 | end
36 | --#
37 | --# == *logger.time*() -> _String_
38 | --#
39 | --# Get same timestamp format used in logs.
40 | --#
41 | --# === Returns
42 | --# [options="header",width="72%"]
43 | --# |===
44 | --# |Type |Description
45 | --# |string| Timestamp
46 | --# |===
47 | local logger_time = function()
48 | T.is_function(logger.time)
49 | local t = logger.time()
50 | T.is_string(t)
51 | end
52 |
53 | --#
54 | --# == *:{info, debug, warn, error}* (_String_, _Table_)
55 | --#
56 | --# Log to specified log level.
57 | --#
58 | --# === Arguments
59 | --# [options="header",width="72%"]
60 | --# |===
61 | --# |Type |Description
62 | --# |string| message
63 | --# |table | key-value map
64 | --# |===
65 | local logger_info = function()
66 | T.is_function(api.info)
67 | end
68 | local logger_debug = function()
69 | T.is_function(api.debug)
70 | end
71 | local logger_warn = function()
72 | T.is_function(api.warn)
73 | end
74 | local logger_error = function()
75 | T.is_function(api.error)
76 | end
77 | local logger_try = function()
78 | local l = logger.new("/tmp/logger_try")
79 | local json = require("json")
80 | l:info("test", { one = "a", two = "b" })
81 | local s = fs.read("/tmp/logger_try")
82 | local t = json.decode(s)
83 | T.equal(t.one, "a")
84 | T.equal(t.two, "b")
85 | T.equal(t.message, "test")
86 | T.equal(t.level, "info")
87 | T.is_string(t.time)
88 | os.remove("/tmp/logger_try")
89 | end
90 | if included then
91 | return function()
92 | T["logger.new"] = logger_new
93 | T["logger.time"] = logger_time
94 | T[":info"] = logger_info
95 | T[":debug"] = logger_debug
96 | T[":warn"] = logger_warn
97 | T[":error"] = logger_error
98 | T["file"] = logger_try
99 | end
100 | else
101 | T["logger.new"] = logger_new
102 | T["logger.time"] = logger_time
103 | T[":info"] = logger_info
104 | T[":debug"] = logger_debug
105 | T[":warn"] = logger_warn
106 | T[":error"] = logger_error
107 | T["file"] = logger_try
108 | end
109 |
--------------------------------------------------------------------------------
/tests/lua.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local expect = T.expect
4 | local multiple_assignment = function()
5 | local x = function()
6 | return 0
7 | end
8 | local t = { 9 }
9 | local z = { z = 8 }
10 | local a, b, c, d, e = 1, t[1], x(), z.z, 4
11 | expect(1)(a)
12 | expect(9)(b)
13 | expect(0)(c)
14 | expect(8)(d)
15 | expect(4)(e)
16 | end
17 | local complex_multi_assign = function()
18 | local a = {}
19 | local d = "e"
20 | local f = 1
21 | f, a.d = f, d
22 | expect("e")(a.d)
23 | expect(false)(f == 1) -- bug
24 | end
25 | local map_overwrite = function()
26 | local t = {
27 | [1] = 1,
28 | "2"
29 | }
30 | expect(1)(#t)
31 | end
32 | if included then
33 | return function()
34 | T["simple multiple assignment"] = multiple_assignment
35 | T["complex multi assign #315"] = complex_multi_assign
36 | T["map vs list"] = map_overwrite
37 | end
38 | else
39 | T["simple multiple assignment"] = multiple_assignment
40 | T["complex multi assign #315"] = complex_multi_assign
41 | T["map vs list"] = map_overwrite
42 | end
43 |
--------------------------------------------------------------------------------
/tests/lz4.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local lz4 = require("lz4")
4 | --# = lz4
5 | --# :toc:
6 | --# :toc-placement!:
7 | --#
8 | --# LZ4 compression and decompression.
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *lz4.compress*(_String_) -> _String_
13 | --# Compress data.
14 | --#
15 | --# === Arguments
16 | --# [options="header",width="72%"]
17 | --# |===
18 | --# |Type |Description
19 | --# |string |Data
20 | --# |===
21 | --#
22 | --# === Returns
23 | --# [options="header",width="72%"]
24 | --# |===
25 | --# |Type |Description
26 | --# |string |Compressed binary data
27 | --# |===
28 | local lz4_compress = function()
29 | T.is_function(lz4.compress)
30 | local lz4c = exec.ctx("lz4")
31 | local data = "AAA111ZZZ"
32 | local compressed = lz4.compress(data)
33 | lz4c.stdin = compressed
34 | local r, so = lz4c({ "-d", "-c" })
35 | T.is_true(r)
36 | T.equal(so, data)
37 | end
38 | --#
39 | --# == *lz4.decompress*(_String_) -> _String_
40 | --# Decompress lz4 data.
41 | --#
42 | --# === Arguments
43 | --# [options="header",width="72%"]
44 | --# |===
45 | --# |Type |Description
46 | --# |string |Compressed
47 | --# |===
48 | --#
49 | --# === Returns
50 | --# [options="header",width="72%"]
51 | --# |===
52 | --# |Type |Description
53 | --# |string |Decompressed data
54 | --# |===
55 | local lz4_decompress = function()
56 | local crypto = require("crypto")
57 | T.is_function(lz4.decompress)
58 | local ls = fs.read("/bin/ls")
59 | local sum = crypto.sha256(ls)
60 | local compressed = lz4.compress(ls)
61 | local data = lz4.decompress(compressed)
62 | T.equal(sum, crypto.sha256(data))
63 | end
64 | if included then
65 | return function()
66 | T["lz4.compress"] = lz4_compress
67 | T["lz4.decompress"] = lz4_decompress
68 | end
69 | else
70 | T["lz4.compress"] = lz4_compress
71 | T["lz4.decompress"] = lz4_decompress
72 | end
73 |
--------------------------------------------------------------------------------
/tests/map.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local bimap = require("map")
3 | local T = require("test")
4 | local expect = T.expect
5 | local func = T.is_function
6 | local tbl = T.is_table
7 | --# = map
8 | --# :toc:
9 | --# :toc-placement!:
10 | --#
11 | --# Bidirectional map implementation.
12 | --#
13 | --# toc::[]
14 | --#
15 | --# == *map.new*() -> _Table_, _Table_
16 | --# Create a new map.
17 | --#
18 | --# === Returns
19 | --# [options="header",width="72%"]
20 | --# |===
21 | --# |Type |Description
22 | --# |table |Array side
23 | --# |table |Map side
24 | --# |===
25 | local new = function()
26 | func(bimap.new)
27 | local l, r = bimap.new()
28 | tbl(l)
29 | tbl(r)
30 | end
31 | local raw = function()
32 | local l, r = bimap.new()
33 | l.test = true
34 | l.nope = false
35 | local left = l("raw")
36 | local right = r("raw")
37 | expect(true)(left["test"])
38 | expect(false)(left["nope"])
39 | expect("test")(right[true])
40 | expect("nope")(right[false])
41 | end
42 | local len = function()
43 | local t = { 1 }
44 | expect(1)(#t)
45 | local l, r = bimap.new()
46 | l.test = 1
47 | l.nope = 2
48 | expect(0)(l("len"))
49 | expect(2)(r("len"))
50 | end
51 | local testing = function(l, r)
52 | expect(2)(l.bar)
53 | expect("bar")(r[2])
54 | local r1 = r("raw")
55 | expect("foo")(r1[1])
56 | expect("bar")(r1[2])
57 | expect("baz")(r1[3])
58 | local t1 = l("raw")
59 | expect(1)(t1.foo)
60 | expect(2)(t1.bar)
61 | expect(3)(t1.baz)
62 | expect(3)(r("len"))
63 | l.baz = nil
64 | expect(2)(#(r("raw")))
65 | r[r("len")] = nil
66 | local r2 = r("raw")
67 | expect("foo")(r2[1])
68 | local l1 = l("raw")
69 | expect(1)(l1.foo)
70 | expect(1)(r("len"))
71 | l.spam = "eggs"
72 | r.eggs = "chunky"
73 | l["chunky"] = "bacon"
74 | expect("bacon")(l["chunky"])
75 | expect("chunky")(r["bacon"])
76 | expect(nil)(l["spam"])
77 | expect(nil)(r["eggs"])
78 | local r3 = r("raw")
79 | local l2 = l("raw")
80 | expect("foo")(r3[1])
81 | expect("chunky")(r3.bacon)
82 | expect(1)(l2.foo)
83 | expect("bacon")(l2.chunky)
84 | local fn = function()
85 | l.evil = 1
86 | end
87 | T.error_raised(
88 | fn,
89 | 'cannot assign value "1" to key "evil": ' .. 'already assigned to key "foo"'
90 | )
91 | end
92 | local left = function()
93 | local l, r = bimap.new()
94 | l.foo = 1
95 | l.bar = 2
96 | l.baz = 3
97 | testing(l, r)
98 | end
99 | local right = function()
100 | local l, r = bimap.new{"foo", "bar", "baz"}
101 | testing(r, l)
102 | end
103 | local iter = function()
104 | local l, r = bimap.new{"foo", "bar", "baz"}
105 | local t = {}
106 | local x = l("raw")
107 | for n = 1, l("len") do
108 | t[n] = x[n]
109 | end
110 | expect("foo")(t[1])
111 | expect("bar")(t[2])
112 | expect("baz")(t[3])
113 | end
114 | if included then
115 | return function()
116 | T["new"] = new
117 | T["raw argument"] = raw
118 | T["len argument"] = len
119 | T["left"] = left
120 | T["right"] = right
121 | T["iteration"] = iter
122 | end
123 | else
124 | T["new"] = new
125 | T["raw argument"] = raw
126 | T["len argument"] = len
127 | T["left"] = left
128 | T["right"] = right
129 | T["iteration"] = iter
130 | end
131 |
--------------------------------------------------------------------------------
/tests/mysql.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local mysql = require("mysql")
4 | --# = mysql
5 | --# :toc:
6 | --# :toc-placement!:
7 | --#
8 | --# Access MySQL or MariaDB databases.
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *mysql.escape*(_String_) -> _String_
13 | --# Escape a query.
14 | --#
15 | --# == *mysql.new*
16 | --# Initialize mysql instance.
17 | --#
18 | --# === Returns
19 | --# [options="header",width="72%"]
20 | --# |===
21 | --# |Type |Description
22 | --# |object |Instance of mysql that you can index into
23 | --# |===
24 | --#
25 | --# == *close*
26 | --# Close mysql instance.
27 | --#
28 | --# == *set_timeout*(_Number_)
29 | --# Set timeout.
30 | --#
31 | --# === Arguments
32 | --# [options="header",width="72%"]
33 | --# |===
34 | --# |Type |Description
35 | --# |number |Timeout in ms
36 | --# |===
37 | --#
38 | --# == *set_keepalive*(_Number_, _Number_)
39 | --#
40 | --# === Arguments
41 | --# [options="header",width="72%"]
42 | --# |===
43 | --# |Type |Description
44 | --# |number |Timeout in ms
45 | --# |number |Max idle connections(poolSize)
46 | --# |===
47 | --#
48 | --# == *connect*(_Table_)
49 | --#
50 | --# === Arguments
51 | --# [options="header",width="72%"]
52 | --# |===
53 | --# |Type |Description
54 | --# |table |See map below
55 | --# |===
56 | --#
57 | --# === Map
58 | --# [options="header",width="72%"]
59 | --# |===
60 | --# |host |
61 | --# |port |
62 | --# |database |
63 | --# |user |
64 | --# |password |
65 | --# |===
66 | --#
67 | --# == *query*(_String_[, ...]) -> _Table_
68 | --#
69 | --# === Arguments
70 | --# [options="header",width="72%"]
71 | --# |===
72 | --# |Type |Description
73 | --# |string |SQL query
74 | --# |===
75 | --#
76 | --# === Returns
77 | --# [options="header",width="72%"]
78 | --# |===
79 | --# |Type |Description
80 | --# |table |Query results, empty table if no results
81 | --# |===
82 | local mysql_new = function()
83 | T.is_function(mysql.new)
84 | local c = mysql.new()
85 | T.is_userdata(c)
86 | c:close()
87 | end
88 | local mysql_close = function()
89 | local c = mysql.new()
90 | T.is_function(c.close)
91 | c:close()
92 | end
93 | local mysql_connect = function()
94 | local c = mysql.new()
95 | T.is_function(c.connect)
96 | local password = os.getenv("MYSQL_PASSWORD")
97 | local ok, err = c:connect({
98 | host = "",
99 | port = "",
100 | database = "",
101 | user = "",
102 | password = password,
103 | })
104 | T.is_true(ok)
105 | T.is_nil(err)
106 | c:close()
107 | end
108 | local mysql_query = function()
109 | local c = mysql.new()
110 | T.is_function(c.connect)
111 | local password = os.getenv("MYSQL_PASSWORD")
112 | local ok, err = c:connect({
113 | host = "127.0.0.1",
114 | port = "3306",
115 | database = "mysql",
116 | user = "root",
117 | password = password,
118 | })
119 | T.is_true(ok)
120 | T.is_nil(err)
121 | local qok, qerr = c:query("SELECT * FROM user LIMIT 1")
122 | T.is_nil(qerr)
123 | T.is_table(qok)
124 | T.is_table(qok[1])
125 | T.equal(qok[1].password_expired, "N")
126 | local cok, cerr = c:query([[SELECT * FROM user where max_user_connections=?]], 0)
127 | T.is_nil(cerr)
128 | T.is_table(cok)
129 | T.equal(next(cok), 1)
130 | local nok, nerr = c:query([[SELECT * FROM user where max_user_connections=?]], 1)
131 | T.is_nil(nerr)
132 | T.is_table(nok)
133 | T.is_nil(next(nok))
134 | c:close()
135 | end
136 | if included then
137 | return function()
138 | T["mysql.new"] = mysql_new
139 | T["close"] = mysql_close
140 | T["connect"] = mysql_connect
141 | T["query"] = mysql_query
142 | end
143 | else
144 | T["mysql.new"] = mysql_new
145 | T["close"] = mysql_close
146 | T["connect"] = mysql_connect
147 | T["query"] = mysql_query
148 | end
149 |
--------------------------------------------------------------------------------
/tests/object.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local Object = require("object")
4 | local Point = Object:extend("Point")
5 | Point.scale = 2 -- Class field!
6 |
7 | function Point:init(x, y)
8 | self.x = x or 0
9 | self.y = y or 0
10 | end
11 |
12 | function Point:resize()
13 | self.x = self.x * self.scale
14 | self.y = self.y * self.scale
15 | end
16 |
17 | function Point.__call()
18 | return "called"
19 | end
20 |
21 | local Rectangle = Point:extend("Rectangle")
22 |
23 | function Rectangle:resize()
24 | Rectangle.super.resize(self) -- Extend Point's `resize()`.
25 | self.w = self.w * self.scale
26 | self.h = self.h * self.scale
27 | end
28 |
29 | function Rectangle:init(x, y, w, h)
30 | Rectangle.super.init(self, x, y) -- Initialize Point first!
31 | self.w = w or 0
32 | self.h = h or 0
33 | end
34 |
35 | function Rectangle:__index(key)
36 | if key == "width" then
37 | return self.w
38 | end
39 | if key == "height" then
40 | return self.h
41 | end
42 | end
43 |
44 | function Rectangle:__newindex(key, value)
45 | if key == "width" then
46 | self.w = value
47 | elseif key == "height" then
48 | self.h = value
49 | end
50 | end
51 |
52 | local rect = Rectangle:new(2, 4, 6, 8)
53 | local extend = function()
54 | T.expect(6)(rect.w)
55 | end
56 | local is = function()
57 | T.expect(true)(rect:is(Rectangle))
58 | T.expect(true)(rect:is("Rectangle"))
59 | end
60 | local is_not = function()
61 | T.expect(false)(rect:is(Point))
62 | end
63 | local has = function()
64 | T.expect(1)(rect:has("Point"))
65 | end
66 | local has_object = function()
67 | T.expect(2)(Rectangle:has(Object))
68 | end
69 | local called = function()
70 | T.expect("called")(rect())
71 | end
72 | local extend2 = function()
73 | T.expect(666)(rect.w)
74 | T.expect(8)(rect.height)
75 | end
76 |
77 | if included then
78 | return function()
79 | T["extend"] = extend
80 | T["is"] = is
81 | T["is not"] = is_not
82 | T["has"] = has
83 | T["has object"] = has_object
84 | T["called"] = called
85 | rect.width = 666
86 | T["extend2"] = extend2
87 | end
88 | else
89 | T["extend"] = extend
90 | T["is"] = is
91 | T["is not"] = is_not
92 | T["has"] = has
93 | T["has object"] = has_object
94 | T["called"] = called
95 | rect.width = 666
96 | T["extend2"] = extend2
97 | end
98 |
--------------------------------------------------------------------------------
/tests/os.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | --# = os
4 | --# :toc:
5 | --# :toc-placement!:
6 | --#
7 | --# Extensions to the `os` namespace.
8 | --#
9 | --# toc::[]
10 | --#
11 | --# == *os.hostname*() -> _String_
12 | --# Get current hostname.
13 | --#
14 | --# === Returns
15 | --# [width="72%"]
16 | --# |===
17 | --# |string |Hostname
18 | --# |===
19 | local os_hostname = function()
20 | T.is_function(os.hostname)
21 | T.is_string(os.hostname())
22 | end
23 | --#
24 | --# == *os.outbound_ip*() -> _String_
25 | --# Get IP used for outbound connections.
26 | --#
27 | --# === Returns
28 | --# [width="72%"]
29 | --# |===
30 | --# |string |IP
31 | --# |===
32 | local os_outbound_ip = function()
33 | T.is_function(os.outbound_ip)
34 | T.is_string(os.outbound_ip())
35 | end
36 | --#
37 | --# == *os.sleep(_Number_) -> _Boolean_
38 | --# Sleep for a number of milliseconds.
39 | --#
40 | --# === Arguments
41 | --# [width="72%"]
42 | --# |===
43 | --# |number |Milliseconds
44 | --# |===
45 | --#
46 | --# === Returns
47 | --# [width="72%"]
48 | --# |===
49 | --# |boolean |`true`
50 | --# |===
51 | local os_sleep = function()
52 | T.is_function(os.sleep)
53 | T.is_true(os.sleep(500))
54 | end
55 | --#
56 | --# == *os.setenv*(_String_, _String_) -> _Boolean_
57 | --# Set environment variable.
58 | --#
59 | --# === Arguments
60 | --# [width="72%"]
61 | --# |===
62 | --# |string |Variable
63 | --# |string |Value
64 | --# |===
65 | --#
66 | --# === Returns
67 | --# [width="72%"]
68 | --# |===
69 | --# |boolean |`true` if successful
70 | --# |===
71 | local os_setenv = function()
72 | T.is_function(os.setenv)
73 | T.is_true(os.setenv("TESTLADYLUAOSSETENV", "1"))
74 | local e = os.getenv("TESTLADYLUAOSSETENV")
75 | T.equal(e, "1")
76 | end
77 | if included then
78 | return function()
79 | T["os.hostname"] = os_hostname
80 | T["os.outbound_ip"] = os_outbound_ip
81 | T["os.sleep"] = os_sleep
82 | T["os.setenv"] = os_setenv
83 | end
84 | else
85 | T["os.hostname"] = os_hostname
86 | T["os.outbound_ip"] = os_outbound_ip
87 | T["os.sleep"] = os_sleep
88 | T["os.setenv"] = os_setenv
89 | end
90 |
--------------------------------------------------------------------------------
/tests/pushover.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local pushover = require("pushover")
4 | local api
5 | --# = pushover
6 | --# :toc:
7 | --# :toc-placement!:
8 | --#
9 | --# Send Pushover messages via the API.
10 | --#
11 | --# toc::[]
12 | --#
13 | --# == *pushover.new*()
14 | --#
15 | --# Initialize object to access methods below. Requires a valid token in the environment variable `PUSHOVER_TOKEN`.
16 | --#
17 | --# === Returns
18 | --# [options="header",width="72%"]
19 | --# |===
20 | --# |Type |Description
21 | --# |userdata| Userdata with methods below
22 | --# |===
23 | local pushover_new = function()
24 | T.is_function(pushover.new)
25 | api = pushover.new()
26 | T.is_userdata(api)
27 | end
28 | --#
29 | --# == *:message*(_String_, _String_)
30 | --#
31 | --# Send a message to device.
32 | --#
33 | --# === Arguments
34 | --# [options="header",width="72%"]
35 | --# |===
36 | --# |Type |Description
37 | --# |string| Device ID
38 | --# |string| message
39 | --# |===
40 | --#
41 | --# === Returns
42 | --# [options="header",width="72%"]
43 | --# |===
44 | --# |Type |Description
45 | --# |string| Response from API
46 | --# |===
47 | local pushover_message = function()
48 | T.is_function(api.message)
49 | end
50 | if included then
51 | return function()
52 | T["pushover.new"] = pushover_new
53 | T[":message"] = pushover_message
54 | end
55 | else
56 | T["pushover.new"] = pushover_new
57 | T[":message"] = pushover_message
58 | end
59 |
--------------------------------------------------------------------------------
/tests/slack.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local slack = require("slack")
4 | --# = slack
5 | --# :toc:
6 | --# :toc-placement!:
7 | --#
8 | --# Wrapper for the Slack API.
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *slack.message*(_String_) -> _Boolean_
13 | --# Send webhook text. Requires the string after the `https://hooks.slack.com/services/` URL in the `SLACK_WEBHOOK` environment variable.
14 | --#
15 | --# === Arguments
16 | --# [options="header",width="72%"]
17 | --# |===
18 | --# |Type |Description
19 | --# |string |Message
20 | --# |===
21 | --#
22 | --# === Returns
23 | --# [options="header",width="72%"]
24 | --# |===
25 | --# |Type |Description
26 | --# |boolean| `true` if successful
27 | --# |===
28 | local slack_message = function()
29 | T.is_function(slack.message)
30 | end
31 | --# == *slack.attachment*(_Table_) -> _Boolean_
32 | --# Send webhook attachment containing values from the argument. Requires the string after the `https://hooks.slack.com/services/` URL in the `SLACK_WEBHOOK` environment variable.
33 | --#
34 | --# === Arguments
35 | --# [options="header",width="72%"]
36 | --# |===
37 | --# |Type |Description
38 | --# |table |See valid values from https://github.com/slack-go/slack[repo]
39 | --# |===
40 | --#
41 | --# === Returns
42 | --# [options="header",width="72%"]
43 | --# |===
44 | --# |Type |Description
45 | --# |boolean| `true` if successful
46 | --# |===
47 | local slack_attachment = function()
48 | T.is_function(slack.attachment)
49 | end
50 | if included then
51 | return function()
52 | T["slack.message"] = slack_message
53 | T["slack.attachment"] = slack_attachment
54 | end
55 | else
56 | T["slack.message"] = slack_message
57 | T["slack.attachment"] = slack_attachment
58 | end
59 |
--------------------------------------------------------------------------------
/tests/ssh_config.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local ssh_config = require("ssh_config")
4 | --# = ssh_config
5 | --# :toc:
6 | --# :toc-placement!:
7 | --#
8 | --# Get values from ~/.ssh/config
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *ssh_config.port*(_String_) -> _String_
13 | --# Get configured Port for Host.
14 | --#
15 | --# === Arguments
16 | --# [options="header",width="72%"]
17 | --# |===
18 | --# |Type |Description
19 | --# |string |Host
20 | --# |===
21 | --#
22 | --# === Returns
23 | --# [options="header",width="72%"]
24 | --# |===
25 | --# |Type |Description
26 | --# |string |Port
27 | --# |===
28 | local ssh_config_port = function()
29 | T.is_function(ssh_config.port)
30 | end
31 | --#
32 | --# == *ssh_config.hostname*(_String_) -> _String_
33 | --# Get configured Hostname for Host.
34 | --#
35 | --# === Arguments
36 | --# [options="header",width="72%"]
37 | --# |===
38 | --# |Type |Description
39 | --# |string |Host
40 | --# |===
41 | --#
42 | --# === Returns
43 | --# [options="header",width="72%"]
44 | --# |===
45 | --# |Type |Description
46 | --# |string |Hostname
47 | --# |===
48 | local ssh_config_hostname = function()
49 | T.is_function(ssh_config.hostname)
50 | end
51 | --#
52 | --# == *ssh_config.identity_file*(_String_) -> _String_
53 | --# Get configured IdentityFile for Host.
54 | --#
55 | --# === Arguments
56 | --# [options="header",width="72%"]
57 | --# |===
58 | --# |Type |Description
59 | --# |string |Host
60 | --# |===
61 | --#
62 | --# === Returns
63 | --# [options="header",width="72%"]
64 | --# |===
65 | --# |Type |Description
66 | --# |string |Path of key
67 | --# |===
68 | local ssh_config_identityfile = function()
69 | T.is_function(ssh_config.identity_file)
70 | end
71 | --#
72 | --# == *ssh_config.hosts*() -> _Table_
73 | --# Get all hosts configured in ~/.ssh/config
74 | --#
75 | --# === Returns
76 | --# [options="header",width="72%"]
77 | --# |===
78 | --# |Type |Description
79 | --# |table|List of hosts
80 | --# |===
81 | local ssh_config_hosts = function()
82 | T.is_function(ssh_config.hosts)
83 | T.is_table(ssh_config.hosts())
84 | end
85 | if included then
86 | return function()
87 | T["ssh_config.port"] = ssh_config_port
88 | T["ssh_config.hostname"] = ssh_config_hostname
89 | T["ssh_config.identityfile"] = ssh_config_identityfile
90 | T["ssh_config.hosts"] = ssh_config_hosts
91 | end
92 | else
93 | T["ssh_config.port"] = ssh_config_port
94 | T["ssh_config.hostname"] = ssh_config_hostname
95 | T["ssh_config.identityfile"] = ssh_config_identityfile
96 | T["ssh_config.hosts"] = ssh_config_hosts
97 | end
98 |
--------------------------------------------------------------------------------
/tests/state.lua:
--------------------------------------------------------------------------------
1 | local state = require("state")
2 | state.debug = require("tests.state.debug_plain").out
3 |
4 | local composite_s = require("tests.state.composite")
5 | composite_s.before = function()
6 | print("MACHINE STARTED")
7 | end
8 |
9 | local hsm = state.init(composite_s) -- create hsm from root composite state
10 |
11 | local function send(e)
12 | print("TEST sending event", e)
13 | hsm.send(e)
14 | end
15 | local function loop(e)
16 | print("===", hsm.loop())
17 | end
18 |
19 | --package.path = package.path .. ";;;tools/?.lua;tools/?/init.lua"
20 | --local to_dot = require 'to_dot'
21 |
22 | send(composite_s.events.e_on)
23 | send("e_restart")
24 |
25 | --to_dot.to_function(composite_s, print)
26 |
27 | send("e_off")
28 | send(composite_s.events.e_on)
29 | while hsm.loop() do
30 | end
31 |
--------------------------------------------------------------------------------
/tests/state/composite.lua:
--------------------------------------------------------------------------------
1 | --- Uses an embedded hsm in a state.
2 |
3 | local state = require("state")
4 |
5 | local helloworld_s = require("tests.state.helloworld") -- load a fsm from a library
6 |
7 | local off_s = state.state({
8 | before = function() --[[print "TEST STATE off"]]
9 | end,
10 | op = function() --[[return true]]
11 | end, --single shot doo function, uncomment return for polling
12 | })
13 | local e_on = {}
14 | local t21 = state.transition({
15 | from = off_s,
16 | to = helloworld_s, --target is a composite state, will start it
17 | events = { e_on }, --event is an object
18 | guard = function(e)
19 | return true
20 | end, --guard function
21 | effect = function(e) --function called on transition
22 | --print ('TEST switching on', os.time())
23 | end,
24 | })
25 | local t22 = state.transition({
26 | from = helloworld_s,
27 | to = off_s,
28 | events = { "e_off" },
29 | timeout = 7.0,
30 | effect = function(e) --function called on transition
31 | --print ('TEST switching off', os.time(), 'timeout:'..tostring(e==state.EV_TIMEOUT))
32 | end,
33 | })
34 |
35 | local composite_s = state.state({
36 | events = { e_on = e_on }, -- publish events
37 | states = { off = off_s, helloworld = helloworld_s }, --can provide names to states
38 | transitions = { ON = t21, OFF = t22 }, --can provide names to transitions
39 | initial = off_s,
40 | })
41 |
42 | return composite_s
43 |
--------------------------------------------------------------------------------
/tests/state/debug_plain.lua:
--------------------------------------------------------------------------------
1 | --- Debug formatter that generates readable output.
2 | -- @usage local state = require 'state'
3 | -- local debug_plain = require 'tools.debug_plain'
4 | -- state.debug = debug_plain.out
5 |
6 | local M = {}
7 |
8 | local debug_names = {}
9 |
10 | local function pick_debug_name(v, nv)
11 | if debug_names[v] then
12 | return debug_names[v]
13 | end
14 | if type(nv) == "string" then
15 | debug_names[v] = nv
16 | else
17 | debug_names[v] = tostring(v._name or v)
18 | end
19 | if v.container and v.container._name ~= "." then -- build path for states
20 | debug_names[v] = debug_names[v.container] .. "." .. debug_names[v]
21 | end
22 | return debug_names[v]
23 | end
24 |
25 | --- Function to be used to write.
26 | -- Defaults to `print`
27 | M.print = print
28 |
29 | -- -- Function to be passed assigned to `state.debug`.
30 | M.out = function(action, p1, p2, p3, p4)
31 | if action == "step" then
32 | M.print(
33 | action
34 | .. "\t"
35 | .. debug_names[p1.from]
36 | .. "\t--"
37 | .. debug_names[p1]
38 | .. "["
39 | .. pick_debug_name(p2)
40 | .. "]->\t"
41 | .. debug_names[p1.to]
42 | )
43 | elseif action == "init" then
44 | M.print(action .. "\t" .. debug_names[p1])
45 | elseif action == "tmout" then
46 | --M.print(action, p1, p2, debug_names[p3],'--'..debug_names[p4]..'->', debug_names[p4.to])
47 | --called before init
48 | M.print(action .. "\t" .. (debug_names[p1] or tostring(p1)) .. "\t" .. tostring(p2))
49 | elseif action == "event" then
50 | M.print(action .. tostring(p1) .. '\t"' .. pick_debug_name(p1, p2) .. '"')
51 | elseif action == "state" then
52 | debug_names[p1.EV_DONE] = "EV_DONE"
53 | M.print(action .. "\t" .. tostring(p1) .. '\t"' .. pick_debug_name(p1, p2) .. '"')
54 | elseif action == "trans" then
55 | M.print(action .. "\t" .. tostring(p1) .. '\t"' .. pick_debug_name(p1, p2) .. '"')
56 | elseif action == "trsel" then
57 | M.print(
58 | action
59 | .. "\t"
60 | .. debug_names[p1]
61 | .. "\t--"
62 | .. debug_names[p2]
63 | .. "["
64 | .. pick_debug_name(p3)
65 | .. "]->\t"
66 | .. debug_names[p2.to]
67 | )
68 | end
69 | end
70 |
71 | return M
72 |
--------------------------------------------------------------------------------
/tests/state/helloworld.lua:
--------------------------------------------------------------------------------
1 | --- Two state flip-flop.
2 |
3 | local state = require("state")
4 | local debug_plain = require("tests.state.debug_plain")
5 | state.debug = debug_plain.out
6 |
7 | local hello_s = state.state({
8 | after = function()
9 | --print("HW STATE hello")
10 | end,
11 | }) --state with exit func
12 | local world_s = state.state({
13 | before = function()
14 | --print("HW STATE world")
15 | end,
16 | }) --state with entry func
17 | local t11 = state.transition({
18 | from = hello_s,
19 | to = world_s,
20 | events = { hello_s.EV_DONE },
21 | }) --transition on state completion
22 | local t12 = state.transition({
23 | from = world_s,
24 | to = hello_s,
25 | events = { "e_restart" },
26 | timeout = 2.0,
27 | }) --transition with timeout, event is a string
28 |
29 | local a = 0
30 | local helloworld_s = state.state({
31 | states = { hello = hello_s, world = world_s }, --composite state
32 | transitions = { to_world = t11, to_hello = t12 },
33 | initial = hello_s, --initial state for machine
34 | op = coroutine.wrap(function() -- a long running doo with yields
35 | while true do
36 | a = a + 1
37 | coroutine.yield(true)
38 | end
39 | end),
40 | before = function()
41 | --print("HW doo running")
42 | end,
43 | after = function()
44 | --print("HW doo iteration count", a)
45 | end, -- will show efect of doo on exit
46 | })
47 |
48 | return helloworld_s
49 |
--------------------------------------------------------------------------------
/tests/telegram.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | local telegram = require("telegram")
4 | local bot
5 | --# = telegram
6 | --# :toc:
7 | --# :toc-placement!:
8 | --#
9 | --# Send Telegram messages via the Bot API.
10 | --#
11 | --# toc::[]
12 | --#
13 | --# == *telegram.new*()
14 | --#
15 | --# Initialize object to access methods below. Requires a valid BOT token in the environment variable `TELEGRAM_TOKEN`.
16 | --#
17 | --# === Returns
18 | --# [options="header",width="72%"]
19 | --# |===
20 | --# |Type |Description
21 | --# |userdata| Userdata containing methods below
22 | --# |===
23 | local telegram_new = function()
24 | T.is_function(telegram.new)
25 | bot = telegram.new()
26 | T.is_userdata(bot)
27 | end
28 | --#
29 | --# == *:channel*(_String_, _String_)
30 | --#
31 | --# Post a channel message.
32 | --#
33 | --# === Arguments
34 | --# [options="header",width="72%"]
35 | --# |===
36 | --# |Type |Description
37 | --# |string| channel id e.g. "-12312313"
38 | --# |string| message
39 | --# |===
40 | --#
41 | --# === Returns
42 | --# [options="header",width="72%"]
43 | --# |===
44 | --# |Type |Description
45 | --# |boolean| true
46 | --# |===
47 | --#
48 | local telegram_channel = function()
49 | T.is_function(bot.channel)
50 | end
51 | --#
52 | --# == *:message*(_String_, _String_)
53 | --#
54 | --# Send a message to Telegram user.
55 | --#
56 | --# === Arguments
57 | --# [options="header",width="72%"]
58 | --# |===
59 | --# |Type |Description
60 | --# |number| user id e.g. 9348484
61 | --# |string| message
62 | --# |===
63 | --#
64 | --# === Returns
65 | --# [options="header",width="72%"]
66 | --# |===
67 | --# |Type |Description
68 | --# |boolean| true
69 | --# |===
70 | local telegram_message = function()
71 | T.is_function(bot.message)
72 | end
73 | if included then
74 | return function()
75 | T["telegram.new"] = telegram_new
76 | T[":channel"] = telegram_channel
77 | T[":message"] = telegram_message
78 | end
79 | else
80 | T["telegram.new"] = telegram_new
81 | T[":channel"] = telegram_channel
82 | T[":message"] = telegram_message
83 | end
84 |
--------------------------------------------------------------------------------
/tests/ulid.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | --# = ulid
4 | --# :toc:
5 | --# :toc-placement!:
6 | --#
7 | --# Generate random strings in ULID format.
8 | --# This is a https://github.com/oklog/ulid/[ulid] wrapper.
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *ulid.new*() -> _String_
13 | --# Generate an ID.
14 | --#
15 | --# === Returns
16 | --# [options="header",width="72%"]
17 | --# |===
18 | --# |Type |Description
19 | --# |string |ULID string
20 | --# |===
21 | local ulid_new = function()
22 | local U = require("ulid")
23 | T.is_function(U.new)
24 | local s = U.new()
25 | local n = U.new()
26 | T.is_string(s)
27 | T.equal(tonumber(#s), 26)
28 | T.not_equal(s, n)
29 | end
30 | if included then
31 | return function()
32 | T["ulid.new"] = ulid_new
33 | end
34 | else
35 | T["ulid.new"] = ulid_new
36 | end
37 |
--------------------------------------------------------------------------------
/tests/uuid.lua:
--------------------------------------------------------------------------------
1 | local included = pcall(debug.getlocal, 4, 1)
2 | local T = require("test")
3 | --# = uuid
4 | --# :toc:
5 | --# :toc-placement!:
6 | --#
7 | --# Generate random strings in UUID format.
8 | --# This is a https://github.com/hashicorp/go-uuid[go-uuid] wrapper.
9 | --#
10 | --# toc::[]
11 | --#
12 | --# == *uuid.new*() -> _String_
13 | --# Generate an ID.
14 | --#
15 | --# === Returns
16 | --# [options="header",width="72%"]
17 | --# |===
18 | --# |Type |Description
19 | --# |string |uuid string
20 | --# |===
21 | local uuid_new = function()
22 | local U = require("uuid")
23 | T.is_function(U.new)
24 | local s = U.new()
25 | local n = U.new()
26 | T.is_string(s)
27 | T.equal(tonumber(#s), 36)
28 | T.not_equal(s, n)
29 | end
30 | if included then
31 | return function()
32 | T["uuid.new"] = uuid_new
33 | end
34 | else
35 | T["uuid.new"] = uuid_new
36 | end
37 |
--------------------------------------------------------------------------------