Port globalChat to new plugin system

Port the globalChat plugin to the new plugin system.  Since there's no
config system yet the config options for it is removed.
This commit is contained in:
Hornwitser committed 2019-12-14 17:51:54 +01:00
1 parent bcceae687f
commit b71c392b32
10 files changed
+199 -70

No files matched your search

-1
View File
@@ -50,7 +50,6 @@ sharedPlugins/*
!sharedPlugins/inventoryImports/
!sharedPlugins/UPSdisplay/
!sharedPlugins/researchSync/
!sharedPlugins/globalChat/
!sharedPlugins/clusterioMod/
!sharedPlugins/statisticsExporter/
+3
View File
@@ -64,6 +64,9 @@ Version 2.0.0
- Removed oddball limits to slaves.json size.
- Moved slave specific configuration into its own configuration file.
- Removed unused binary option from plugin config.
- Removed info and shout command from globalChat plugin
- Removed mirrorAllChat and enableCrossServerShout configuration options for
globalChat plugin.
### Breaking Changes
-2
View File
@@ -40,8 +40,6 @@
"useNeuralNetDoleDivider": true,
"msBetweenCommands": 10,
"allowRemoteCommandExecution": true,
"enableCrossServerShout": true,
"mirrorAllChat": false,
"__comment7": "Autosave interval for items in the master storage in milliseconds. Defaults to one minute when set to 0 or not set.",
"autosaveInterval": 600000,
"__comment8": "This setting only affects the master. It makes every import for things that arent 'electricity' return a maximum of 0. Effectively disables teleport chests.",
+23
View File
@@ -0,0 +1,23 @@
let link = require("lib/link");
let plugin = require("lib/plugin");
module.exports = {
name: "global_chat",
title: "Global Chat",
description: "Forwards chat between instances.",
version: "2.0.0-alpha",
instanceEntrypoint: "instance",
messages: {
chat: new link.Event({
type: 'global_chat:chat',
links: ['instance-slave', 'slave-master', 'master-slave', 'slave-instance'],
forwardTo: 'master',
broadcastTo: 'instance',
eventProperties: {
"instance_name": { type: "string" },
"content": { type: "string" },
},
}),
},
}
+58
View File
@@ -0,0 +1,58 @@
const plugin = require("lib/plugin");
/**
* Removes gps and train tags from messags
*/
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);
}
async init() {
// XXX Nothing?
}
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)}')`);
}
async onOutput(output) {
if (output.type === "action" && output.action === "CHAT") {
this.info.messages.chat.send(this.instance, {
instance_name: this.instance.name,
content: output.message,
});
}
}
// TODO implement info command in lua?
}
module.exports = {
InstancePlugin,
// For testing only
_removeTags: removeTags,
_escapeLuaString: escapeLuaString,
}
+91
View File
@@ -0,0 +1,91 @@
const assert = require('assert').strict;
const mock = require('../../../test/mock');
const lines = require('../../../test/lib/factorio/lines');
const instance = require('../instance');
const info = require('../info');
describe("global_chat plugin", function() {
describe("removeTags()", function() {
it("should pass through an ordinary string", function() {
assert.equal(instance._removeTags("string"), "string");
});
it("should strip out gps tag", function() {
assert.equal(instance._removeTags("Look at [gps=12,-4]"), "Look at ");
});
it("should strip out train tag", function() {
assert.equal(instance._removeTags("Train [train=1235]"), "Train ");
});
});
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;
before(async function() {
instancePlugin = new instance.InstancePlugin(info, new mock.MockInstance());
await instancePlugin.init();
});
describe(".chatEventHandler()", function() {
it("should send received chat as command", async function() {
instancePlugin.instance.server.rconCommands = [];
await instancePlugin.chatEventHandler({ data: { instance_name: "test", content: "User: message" } });
assert.deepEqual(
instancePlugin.instance.server.rconCommands,
["/sc game.print('[test] User: message')"],
);
});
});
describe(".onOutput()", function() {
it("should forward chat", async function() {
let count = 0;
for (let [_, output] of lines.testLines) {
if (output.type === "action" && output.action === "CHAT") {
instancePlugin.instance.connector.sentMessages = [];
await instancePlugin.onOutput(output);
assert(instancePlugin.instance.connector.sentMessages.length, "message was not sent");
count++;
}
}
assert(count > 0, "no lines were tested");
});
it("should ignore regular output", async function() {
let count = 0;
for (let [_, output] of lines.testLines) {
if (output.type !== "action" || output.action !== "CHAT") {
instancePlugin.instance.connector.sentMessages = [];
await instancePlugin.onOutput(output);
assert(!instancePlugin.instance.connector.sentMessages.length, "message was sent");
count++;
}
}
assert(count > 0, "no lines were tested");
});
})
});
});
-9
View File
@@ -1,9 +0,0 @@
/*
Clusterio plugin to allow for chat between instances.
*/
module.exports = {
// Name of package. For display somewhere I guess.
name: "globalChat",
version: "1.0.0",
description: "Clusterio plugin to allow for chat between instances.",
}
-52
View File
@@ -1,52 +0,0 @@
module.exports = class remoteCommands {
constructor(mergedConfig, messageInterface, extras){
this.messageInterface = messageInterface;
this.config = mergedConfig;
this.socket = extras.socket;
this.instances = {};
this.socket.emit("registerChatReciever");
this.socket.on("gameChat", async data => {
if(data.instanceID && data.instanceID != this.config.unique.toString()){
if(data.data.includes("[CHAT]")
// if this isn't used as an info command or something (reduce spam)
&& !data.data.includes("!info")
// check if we are allowed to cross chat at all, default to true
&& (mergedConfig.enableCrossServerShout == undefined || mergedConfig.enableCrossServerShout)
// check if we are supposed to relay this message
&& (mergedConfig.mirrorAllChat || data.data.toLowerCase().includes("/shout") || data.data.toLowerCase().includes("!shout"))){
let words = data.data.trim().split(" ");
words.shift();
words.shift();
words.shift();
let message = words.join(" ").replace(/[";]/g, " ").replace(/[']/g,"").replace("/shout ", "").replace("!shout ","").replace(/\[gps=.*?\]/g, "").replace(/\[train=.*?\]/g, "");
if(data.data.includes("[gps=")){
//Nothing
}else{
this.messageInterface("/silent-command game.print('[" + data.instanceName + "] " + message + "')");
}
}
}
});
}
async factorioOutput(data){
try{
this.socket.emit("gameChat", {
instanceID: this.config.unique.toString(),
instanceName: this.config.name,
data,
});
if(data.includes("[CHAT]") && data.includes("!info")){
let infoMessage = [
"=== Server info ===",
"Name: "+await this.getInstanceName(this.config.unique)+" ("+this.config.unique+")",
];
infoMessage.forEach((line, i) => {
setTimeout(()=>this.messageInterface("/silent-command game.print('"+line+"')"),i*200);
});
}
}catch(e){console.log(e)}
}
}
-4
View File
@@ -1,4 +0,0 @@
// These are libraries that does not have any units test, they are
// required here in order to track coverage for them.
require('../index');
+24 -2
View File
@@ -1,5 +1,7 @@
const events = require("events");
const link = require("lib/link");
class MockSocket {
constructor() {
@@ -23,7 +25,7 @@ class MockSocket {
close() {
this.closeCalled = true;
}
};
}
class MockConnector extends events.EventEmitter {
constructor() {
@@ -50,9 +52,29 @@ class MockConnector extends events.EventEmitter {
disconnect() {
this.disconnectCalled = true;
}
};
}
class MockServer {
constructor() {
this.rconCommands = [];
}
async sendRcon(command) {
this.rconCommands.push(command);
}
}
class MockInstance extends link.Link {
constructor() {
super('instance', 'slave', new MockConnector());
this.server = new MockServer();
this.name = "test";
}
}
module.exports = {
MockSocket,
MockConnector,
MockInstance,
};