Add clusterio module with API for lua code

Add a shared API for lua code through a module named clusterio.
This commit is contained in:
Hornwitser committed 2020-01-04 17:34:16 +01:00
1 parent 221dc855f4
commit 66aa7e1e43
9 files changed
+139 -43

No files matched your search

+13 -2
View File
@@ -11,6 +11,7 @@ const link = require("lib/link");
const plugin = require("lib/plugin");
const errors = require("lib/errors");
const prometheus = require('lib/prometheus');
const luaTools = require('lib/luaTools');
/**
@@ -175,7 +176,7 @@ class Instance extends link.Link{
module = Object.assign({
version: plugin.info.version,
dependencies: {},
dependencies: { 'clusterio': '*' },
path: modulePath,
load: [],
require: [],
@@ -203,7 +204,7 @@ class Instance extends link.Link{
module = Object.assign({
path: path.join('modules', entry.name),
dependencies: {},
dependencies: { 'clusterio': '*' },
load: [],
require: [],
}, module);
@@ -218,12 +219,22 @@ class Instance extends link.Link{
});
await this.server.start(saveName);
await this.server.disableAchievements()
await this.updateInstanceData();
for (let pluginInstance of this.plugins.values()) {
await pluginInstance.onStart();
}
}
/**
* Update instance information on the Factorio side
*/
async updateInstanceData() {
let name = luaTools.escapeString(this.config.name);
await this.server.sendRcon(`/sc clusterio_private.update_instance(${this.config.id}, "${name}")`, true);
}
/**
* Stop the instance
*/
+2 -1
View File
@@ -223,7 +223,8 @@ The following entries are supported in the module.json file:
node-semver package for a full description of what operators are
supported. The events for dependencies is invoked before the events
of the dependent, and starting an instance will fail if the
dependencies cannot be satisfied.
dependencies cannot be satisfied. If not specified it will default
to depending on `clusterio`.
- `require`:
Lua files to require in `control.lua`. This should only really be
needed if you want to make a global function available for use in
+17
View File
@@ -0,0 +1,17 @@
/**
* Escapes a string for inclusion into a lua string
*/
function escapeString(content) {
return content
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/'/g, "\\'")
.replace(/\0/g, "\\0")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
;
}
module.exports = {
escapeString,
}
+17
View File
@@ -0,0 +1,17 @@
local api = {}
-- Table of events raised by clusterio
api.events = {
-- Raised after the name and id of an instance has been updated
-- This may occur even if the id and name didn't change.
-- Event data:
-- instance_id: The id of the instance.
-- instance_name: the name of the instance.
on_instance_updated = script.generate_event_name(),
}
return api
+52
View File
@@ -0,0 +1,52 @@
local api = require('modules/clusterio/api')
local impl = {}
local function init()
if not global.clusterio then
global.clusterio = {
instance_id = nil,
instance_name = nil,
}
end
end
-- Internal API
clusterio_private = {}
function clusterio_private.update_instance(new_id, new_name)
init()
global.clusterio.instance_id = new_id
global.clusterio.instance_name = new_name
script.raise_event(api.events.on_instance_updated, {
instance_id = new_id,
instance_name = new_name,
})
end
function impl.add_remote_interface()
remote.add_interface('clusterio_api', {
-- Returns a table of events raised by clusterio
get_events = function()
return api.events
end,
-- Returns the instance id the game is run under
-- This may change over time and/or be nil.
get_instance_id = function()
init()
return global.clusterio.instance_id
end,
-- Returns the name of the instance the game runs under.
-- This may change over time and/or be nil.
get_instance_name = function()
init()
return global.clusterio.instance_name
end,
})
end
return impl
+6
View File
@@ -0,0 +1,6 @@
{
"name": "clusterio",
"version": "0.0.0",
"dependencies": {},
"load": ["impl.lua"]
}
+2 -16
View File
@@ -1,4 +1,5 @@
const plugin = require("lib/plugin");
const luaTools = require("lib/luaTools");
/**
@@ -8,20 +9,6 @@ function removeTags(content) {
return content.replace(/(\[gps=-?\d+,-?\d+\]|\[train=\d+\])/g, "");
}
/**
* Escapes a string for inclusion into a lua string
*/
function escapeLuaString(content) {
return content
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/'/g, "\\'")
.replace(/\0/g, "\\0")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
;
}
class InstancePlugin extends plugin.BaseInstancePlugin {
constructor(...args) {
super(...args);
@@ -34,7 +21,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin {
async chatEventHandler(message) {
// TODO check if cross server chat is enabled
let content = `[${message.data.instance_name}] ${removeTags(message.data.content)}`;
await this.instance.server.sendRcon(`/sc game.print('${escapeLuaString(content)}')`, true);
await this.instance.server.sendRcon(`/sc game.print('${luaTools.escapeString(content)}')`, true);
}
async onOutput(output) {
@@ -54,5 +41,4 @@ module.exports = {
// For testing only
_removeTags: removeTags,
_escapeLuaString: escapeLuaString,
}
-24
View File
@@ -19,30 +19,6 @@ describe("global_chat plugin", function() {
});
});
describe("escapeLuaSrting", function() {
it("should escape backslashes", function() {
assert.equal(instance._escapeLuaString("\\a"), "\\\\a");
});
it("should escape double quotes", function() {
assert.equal(instance._escapeLuaString('"a"'), '\\"a\\"');
});
it("should escape single quotes", function() {
assert.equal(instance._escapeLuaString("'a'"), "\\'a\\'");
});
it("should escape nul bytes", function() {
assert.equal(instance._escapeLuaString("a\0b"), "a\\0b");
});
it("should escape newlines", function() {
assert.equal(instance._escapeLuaString("a\nb"), "a\\nb");
});
it("should escape carriage return", function() {
assert.equal(instance._escapeLuaString("a\rb"), "a\\rb");
});
it("should escape all combined", function() {
assert.equal(instance._escapeLuaString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg");
});
});
describe("class InstancePlugin", function() {
let instancePlugin;
+30
View File
@@ -0,0 +1,30 @@
const assert = require('assert').strict;
const luaTools = require('lib/luaTools');
describe("lib/luaTools", function() {
describe("escapeString()", function() {
it("should escape backslashes", function() {
assert.equal(luaTools.escapeString("\\a"), "\\\\a");
});
it("should escape double quotes", function() {
assert.equal(luaTools.escapeString('"a"'), '\\"a\\"');
});
it("should escape single quotes", function() {
assert.equal(luaTools.escapeString("'a'"), "\\'a\\'");
});
it("should escape nul bytes", function() {
assert.equal(luaTools.escapeString("a\0b"), "a\\0b");
});
it("should escape newlines", function() {
assert.equal(luaTools.escapeString("a\nb"), "a\\nb");
});
it("should escape carriage return", function() {
assert.equal(luaTools.escapeString("a\rb"), "a\\rb");
});
it("should escape all combined", function() {
assert.equal(luaTools.escapeString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg");
});
});
});