boon 🌟
allow your Lua code to live in the cloud(s)
Introduction
Boon is a modified Lua runtime which was built with some broad goals:
- Allow Lua chunks to be executed as HTTP server (maybe even
(micro)service-able)
- Allow Lua chunks to communicate with other servers and databases
- Allow the runtime to be extensible
It ships with a lot of out-of-the-box usable add-ons to communicate via HTTP
(addons/generic/http_client
), handle JSON data (addons/generic/json
), to
be run as HTTP server (addons/http/*
) and talk to databases
(addons/databases
). Contributions are welcome!
It also ships with pre-loaded modules (boon_generic.lua
, boon_http.lua
)
which create a more natural interface to the underlying functionality
(See Caveats for more detail).
Usage
To get started immediately; Utilize the prepared Docker setup. And just run
following commands.
# To create and access Docker container ...
$ make demo
# ... (In container) to run a local Lua script as entrypoint
# (e.g. `examples/welcome.lua` when run in boon root)
$ boon -entrypoint=path/to/file.lua
# ... now take a look at http://localhost:8080
For a more details on the exposed functions, check out the Lua API Docs.
Checkout Docker Hub for the
official ready-to-use images.
Building
Boon uses aarzilli/golua. So when
building (e.g. cmd/server/boon.go
, cmd/cli/boon.go
) keep in mind that
boon uses CGO and requires -tags
to build with specific Lua versions.
For a quick start you can run make docker-luajit
, which creates two
alpine-based images boon:test
and boon:luajit
. Both of them are alpine
images and come with a default boon
and boon_cli
binary. (Do not use
boon:test
for production)
Benchmark
on MacBook Air M1 '20 – 8Gb RAM
compiled with -tags luajit, file used as HTTP handler did some JSON encoding
and rendered some response
$ ./wrk -t1000 -c1000 -d30s http://127.0.0.1:8080/
Running 30s test @ http://127.0.0.1:8080/
1000 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 37.66ms 47.18ms 566.97ms 84.43%
Req/Sec 49.90 55.59 1.44k 91.23%
1422566 requests in 30.11s, 379.87MB read
Socket errors: connect 0, read 150, write 0, timeout 0
Requests/sec: 47243.04
Transfer/sec: 12.62MB
Lua API
-- GENERAL
boon.log(lua_string) -- write to log (in log format)
-- GENERIC
boon.json.decode(json_string) -- returns JSON value Lua table
boon.json.encode(lua_table) -- returns JSON string of Lua table
boon.http.methods.patch -- 'PATCH'
boon.http.methods.post -- 'POST'
boon.http.methods.get -- 'GET'
boon.http.methods.put -- 'PUT'
boon.http.methods.delete -- 'DELETE'
local request = {
target=target_url,
method=http_method,
body=http_body_if_needed,
headers={} -- table of headers e.g. ['content-type']='application/json'
}
boon.http.request(request)
ok, db = boon.postgres.connect(connection_string) -- connects to a postgres database (if not possible, ok == false and db == nil)
results = db.query(query_string) -- fetches results from database (returns lua table)
lastId, noRowsAffected = db.exec(query_string) -- executes a query on the database
ok = db.ping() -- pings the database
-- HTTP
boon.method -- HTTP request method
boon.scheme -- HTTP request scheme (http/https)
boon.host -- HTTP request host
boon.path -- HTTP request path
boon.query -- HTTP request query string
boon.response.set_header(name, value) -- sets response header (must be called before boon.response.status)
boon.response.status(code) -- sets the rsponse code e.g. 200
boon.response.write(content_string) -- writes to response
boon.redirect(target_url, code) -- redirects to target_url with status code
boon.request.set_header(name, value) -- sets request header (this is relevant when using redirect, since the CURRENT request object is used for the redirect)
value = boon.request.get_header(name) -- returns the value set for the header requested
paramTable = boon.request.query_parameters() -- returns all sent query parameters
formParams = boon.request.form_parameters() -- returns all sent post (and query) parameters; or nil and error
fileBytes, meta = boon.request.file(name) -- returns bytes of a uploaded file and meta info (e.g. content-type, ...); or nil and error
Caveats
This package uses aarzilli/golua; which
has some caveats on it's own. By default pcall
and xpcall
are both
renamed with prefix unsafe_*
. This is because Lua errors are incompatible
with Go ones, so every extension created technically should not be called in
a pcall
or xpcall
callback. If you do it might crash your software if
some error arises on Go side. To handle this problem there are chunks
pre-loaded (boon_generic.lua
, boon_http.lua
). The resulting module should
be used to call ANY extension boon
contains out-of-the-box (as the docs
implicate). Any external extension should ship it's own module. The module
should be used to do argument type checks or any other necessary steps,
before arguments are passed into the Go context. By doing this, it is
generally safe to use pcall
and xpcall
.