Wrapper around the luaSandbox extension for Hydrogen.
Silicon is built to be used with the ClanCats/Container which hydrogen is built around.
There is a simple bash script to run the examples through docker in case luaSandbox is not installed locally.
$ bash run-example.sh ./examples/01_simple_eval.php
First bind the runner to the container:
@silicon.runner: @silicon
@silicon: Silicon\SiliconRunner(@container)
- setDefaultPreloadCache(@silicon.cache)
@silicon.cache: Silicon\SiliconPreloadCache(:const.PATH_CACHE)
In most cases you want to use a preload cache, this will dump all lua code from available modules in binary form to disk. Which improves initialization time for each sandbox. This is optional so feel free to leave that out. Note: If you are not using the hydrogen framework, you need to use an actual path instead of :const.PATH_CACHE
Now you can use the silicon runner create a sandbox and run some lua code in it.
$silicon = $container->get('silicon');
$context = $silicon->boot();
$result = $context->eval(<<<'LUA'
function distance(x1, y1, x2, y2)
local dx = x1 - x2
local dy = y1 - y2
return math.sqrt(dx * dx + dy * dy)
end
return distance(10, 5, 50, 100)
LUA);
var_dump($result); // float(103.07764064044152)
The function distance
has been declared in our lua context now, so we can also directly call it:
$result = $context->invokeFunction('distance', 5, 5, 10, 10);
var_dump($result); // float(7.0710678118654755)
When booting up a Sandbox you can pass execution constraints to ensure no resource exhaustion.
$silicon = $container->get('silicon');
$options = new LuaContextOptions;
$options->memoryLimit = LuaContextOptions::MEML_32MB;
$options->CPUTimeLimit = 30.0; // 30 seconds
$context = $silicon->boot($options);
Silicon comes with a console built in for simpler debugging and realtime feedback:
console.log(42)
console.warn("noooo")
console.error({'Something', 'Went', 'Wrong'})
Output:
// int(42)
// string("noooo")
// [3]{
// 1: string("Something")
// 2: string("Went")
// 3: string("Wrong")
// }
foreach($context->console()->all() as $message) {
echo $message[1] . PHP_EOL;
}
To define a custom module it needs to be bound to the container which is passed to runner or the sandbox itself, here an example how you create a email module with sendmail. (Obviously do not do this!)
@my_lua_mailer: App\LuaMailer
= silicon.module: 'email'
All you have to do is to implement the SiliconModuleInterface
:
class LuaMailer implements SiliconModuleInterface
{
public function getExposedFunctions(LuaContext $ctx) : ?array {
return [
'send' => [$this, 'exposeSend']
];
}
public function preloadLua() : ?string {
return null;
}
public function exposeSend(string $to, string $subject, string $message) {
mail($to, $subject, $message . '\n\nSend from Lua!');
}
}
In lua you will be able to use that module as follows:
local to = 'support@cineman.ch'
local subject = 'Please dont spam us'
local message = 'Hello there'
email.send(to, subject, message)