Lua Engine
The Lua Engine
Introduction
The JSLEE scripting service provides full support for the Lua 5.2 language. This scripting engine is based on the luaj library.
To include the Lua engine in your JSLEE, configure the handler as follows:
{
"selfcare": {
"handler": "nz.co.nsquared.slee.scriptengine.LuaScriptEngineVerticle",
"instance-count": 1,
"configuration": {
"scripts": [
],
"lib-path": [
"lua/?.lua"
, "lua/?/?.lua"
, "lua/?/?/?.lua"
]
}
}
}
Library Path Configuration
Lua scripts can require()
modules of code. The lua scripting engine supports module includes by searching the
lib-path
provided in the configuration. If a lib path is not provided, the system will search the path provided
by the Java system property luaj.package.path
.
lib-path
may be either an array of paths, or a semi-colon separated string of paths. Note that to retrieve scripts
in subdirectories these need to be explicitly listed using the form lua/?/?.lua
.
There is no default for lib-path
, however it is recommended that:
{
"lib-path": [
"lua/?.lua"
, "lua/?/?.lua"
, "lua/?/?/?.lua"
]
}
is used as the minimum, and any user-supplied library paths are included in this list. It is
important that the JSLEE
interface is included into your script.
Regardless of the path and what is require()
d into scripts, the following standard libraries
are included in every Lua script by default (no require()
necessary):
base
bit32
coroutine
io
math
os
package
string
table
luajava
Script Configuration
The scripts to run within the JSLEE are configured using the scripts
array. An example
configuration would be:
{
"scripts": [
{
"class": "nz.co.nsquared.slee.smpp.event.SMPPMessageEvent",
"script": "return JSLEE.handler ({ handle = function () print ('Hello, world!') end })"
},
{
"name": "lua-from-file",
"file": "/path/to/file.lua",
"config": "return { a = 1 }"
}
]
}
To configure the JSLEE, either or both of a class
or a name
value must be provided,
along with either an inline script
or a file
to compile.
If using class
, this must be the fully qualified name of the event that
will be listened for over the event bus, sent by another JSLEE service.
If using name
, this must be a unique name that will be used as the endpoint address
that other JSLEE services can send messages to directly.
Both name
and class
may be defined, however only one instance of each
will be used after reading the configuration; warnings will be raised for duplicate
values that are skipped. Should a message be received that qualifies for handling
under both name
and class
matches, the script that is defined for the name
will be
chosen in preference.
Specifying a script
allows for an inline Lua script to be provided. For very short scripts
this might be reasonable, however in practice this is suggested only for debugging and testing
(e.g. to dump the received message before passing on to the real endpoint).
For longer scripts, a file
can be specified giving the path to a Lua file. The full
content of the file referenced will be evaluated. In addition, specific information can
be passed to the executed file in the optional config
string, which is an arbitrary Lua
string that is evaluated and has its return value passed to the script’s begin()
function.
For example:
{
"scripts": [
{
"class": "nz.co.nsquared.slee.smpp.event.SMPPMessageEvent",
"file": "selfcare.lua",
"config": "return { Timeout = 500 }"
}
]
}
In this example, the Lua table returned by this script will be passed in to the begin()
method from selfcare.lua
.
This value can then be used as required at runtime, allowing for configuration outside the script.
Note that the config
value is ignored if the script
value is present.
Conforming to the API
The Lua provided must conform to the following API by providing a number of methods to perform actual tasks in a Lua table:
Method | Required? | Description |
---|---|---|
begin() |
no | This method is called once after a successful compiliation of the Lua. This allows for initialisation of the script. This is optional |
handle() |
yes | This method is called for each incoming event the script engine receives of the JSLEE message type associated with the script. |
A Lua table with these methods should be returned from any script compiled for the engine, however when creating this object, it is important to call:
return JSLEE.handler(yourhandler)
To ensure that the handler the Lua script engine actually gets conforms to our API requirements (in particular it wraps your handler in a coroutine).
The begin()
Method
The begin()
method receives the following arguments:
Argument | Type | Description |
---|---|---|
logger |
LoggerDelegate |
A delegate object that wraps a org.slf4j.Logger interface object. |
config |
any | The result of the execution of the script embedded in the JSLEE script engine service configuration. |
The begin()
method must complete successfully otherwise it will cause the
shutdown of the JSLEE. Further, this method cannot interact with other service -
the JSLEE doesn’t provide the appropriate interfaces or structure. All actions
of the begin()
method must be pure Lua code.
The handle()
Method
The handle method receives the following arguments:
Argument | Type | Description |
---|---|---|
uuid |
String |
The unique ID of the event that the handler is handling. |
event |
any | A reference to the object the handler is for (e.g. SMPPMessage ) that the handler should handle. If the Lua scripting engine is aware of the message type, this will be wrapped in a Lua based delegate object with a more useful Lua interface, and be unwrapped from the message event used to actually send the message over the VertX event bus. |
message |
Event |
The actual event sent over the VertX event bus. |
fromAddress |
Address |
The Vert.X event bus address of the sending service/endpoint. |
The handle()
method is responsible for handling the event to the point
where it can respond back to the source of the event with a success or
failure.
The handle method may do this by calling JSLEE.succeeded(result)
or
JSLEE.failed(errorCode, errorMessage)
. In either case this will result
in the provided result information being sent back to the source as either
success or failure.
Only the first call to either of these methods is used. Subsequent calls to these methods are ignored.
Be sure to provide a result that the source of the handled message will understand - e.g. it is not useful to send an EDR back to the SMPP service.
Note that a Lua handler may reply to the source of the event before completing its processing. E.g. a SMPP handler may immediately reply to the source, then perform the business logic to actually complete processing of the SMS.
Calling the Lua error()
method will, if it is the first result provided,
cause a failure to be sent back to the calling method. If a result has
already been provided, then the error is not sent back. In any case however,
error()
calls result in an error message being printed to the system log.
The handle()
method may send messages to other JSLEE service
(and receive replies) using the JSLEE.send
method.
Logging from Lua Scripts
Logging from Lua scripts can be done using the print()
method, which
prints to stdout. However this is usually not the best approach. Instead,
use the logger provided as the begin()
method’s first argument, or
call JSLEE.logger()
to get a logger in the handle()
method, and use this.
The Logger returned in each case supports the following methods, which
are delegated to the org.slf4j.Logger
object. The following methods
are available:
- The
is....Enabled
methods, such asisTraceEnabled
- The
debug
,info
,warn
,error
andtrace
methods which take a single string as input.
EDRs from Lua Scripts
Lua scripts can create EDRs using the JSLEE.createSuccessEdr
or JSLEE.createFailureEdr
functions. Refer to the JSLEE
module documentation for usage details for these functions.
Note that EDR configuration must be enabled on the Lua handler service for any EDR output of any type to occur.
Lua Script Example
The following Lua script declares the framework for a Lua handler:
local JSLEE = require("n2.jslee.JSLEE")
-- Our table which holds our begin and handle methods
local h = {}
-- Begin method. JSLEE methods can't be used here unless
-- explicitly mentioned.
function h.begin (logger, userConfig)
end
function h.handle (uuid, event)
logger = JSLEE.logger()
log:debug("[myhandler] Received request to handle event " .. uuid)
-- actual handling
-- return an appropriate value to the source of the event.
JSLEE.succeeded (0)
end
return JSLEE.handler(h)
The JSLEE
Lua API
Each JSLEE Lua script must include and use the JSLEE
API to perform
the appropriate actions within the script. The available methods are
documented in the JSLEE Lua library.
Lua API Wrappers
To provide more effective APIs to use from within Lua, some objects have wrappers which are used by the Lua script engine.
For example, if handling a SMPPMessageEvent
, the JSLEE
Lua API
will automatically extract out the SMPPMessage
object and wrap it
in the SMPPMessage Lua API available in lib/n2/jslee/SMPPMessage.lua
.
Wrappers:
Wrapper | Description |
---|---|
SMPPMessage | The SMPPMessage wrapper wraps the Java SMPPMessage object. If your handler is for a SMPPMessageEvent , this API is what you receive as the event object automatically. |
See the associated Lua API object for documentation of methods.