Add support for command plugins (#2757)
This commit is contained in:
commit
1b38e6cc02
@ -19,62 +19,6 @@ const colorCodeMap = [
|
|||||||
["15", "Light Grey"],
|
["15", "Light Grey"],
|
||||||
];
|
];
|
||||||
|
|
||||||
const commands = [
|
|
||||||
"/as",
|
|
||||||
"/away",
|
|
||||||
"/back",
|
|
||||||
"/ban",
|
|
||||||
"/banlist",
|
|
||||||
"/bs",
|
|
||||||
"/close",
|
|
||||||
"/collapse",
|
|
||||||
"/connect",
|
|
||||||
"/cs",
|
|
||||||
"/ctcp",
|
|
||||||
"/cycle",
|
|
||||||
"/dehop",
|
|
||||||
"/deop",
|
|
||||||
"/devoice",
|
|
||||||
"/disconnect",
|
|
||||||
"/expand",
|
|
||||||
"/ho",
|
|
||||||
"/hop",
|
|
||||||
"/hs",
|
|
||||||
"/ignore",
|
|
||||||
"/ignorelist",
|
|
||||||
"/invite",
|
|
||||||
"/invitelist",
|
|
||||||
"/join",
|
|
||||||
"/kick",
|
|
||||||
"/leave",
|
|
||||||
"/list",
|
|
||||||
"/me",
|
|
||||||
"/mode",
|
|
||||||
"/ms",
|
|
||||||
"/msg",
|
|
||||||
"/nick",
|
|
||||||
"/notice",
|
|
||||||
"/ns",
|
|
||||||
"/op",
|
|
||||||
"/os",
|
|
||||||
"/part",
|
|
||||||
"/query",
|
|
||||||
"/quote",
|
|
||||||
"/quit",
|
|
||||||
"/raw",
|
|
||||||
"/rejoin",
|
|
||||||
"/rs",
|
|
||||||
"/say",
|
|
||||||
"/send",
|
|
||||||
"/server",
|
|
||||||
"/slap",
|
|
||||||
"/topic",
|
|
||||||
"/unban",
|
|
||||||
"/unignore",
|
|
||||||
"/voice",
|
|
||||||
"/whois",
|
|
||||||
];
|
|
||||||
|
|
||||||
const condensedTypes = [
|
const condensedTypes = [
|
||||||
"away",
|
"away",
|
||||||
"back",
|
"back",
|
||||||
@ -95,7 +39,7 @@ const timeFormats = {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
colorCodeMap,
|
colorCodeMap,
|
||||||
commands,
|
commands: [],
|
||||||
condensedTypes,
|
condensedTypes,
|
||||||
condensedTypesQuery,
|
condensedTypesQuery,
|
||||||
timeFormats,
|
timeFormats,
|
||||||
|
8
client/js/socket-events/commands.js
Normal file
8
client/js/socket-events/commands.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const constants = require("../constants");
|
||||||
|
const socket = require("../socket");
|
||||||
|
|
||||||
|
socket.on("commands", function(commands) {
|
||||||
|
if (commands) {
|
||||||
|
constants.commands = commands;
|
||||||
|
}
|
||||||
|
});
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
require("./auth");
|
require("./auth");
|
||||||
require("./change_password");
|
require("./change_password");
|
||||||
|
require("./commands");
|
||||||
require("./init");
|
require("./init");
|
||||||
require("./join");
|
require("./join");
|
||||||
require("./more");
|
require("./more");
|
||||||
|
@ -11,6 +11,7 @@ const Helper = require("./helper");
|
|||||||
const UAParser = require("ua-parser-js");
|
const UAParser = require("ua-parser-js");
|
||||||
const uuidv4 = require("uuid/v4");
|
const uuidv4 = require("uuid/v4");
|
||||||
const escapeRegExp = require("lodash/escapeRegExp");
|
const escapeRegExp = require("lodash/escapeRegExp");
|
||||||
|
const inputs = require("./plugins/inputs");
|
||||||
|
|
||||||
const MessageStorage = require("./plugins/messageStorage/sqlite");
|
const MessageStorage = require("./plugins/messageStorage/sqlite");
|
||||||
const TextFileMessageStorage = require("./plugins/messageStorage/text");
|
const TextFileMessageStorage = require("./plugins/messageStorage/text");
|
||||||
@ -40,33 +41,6 @@ const events = [
|
|||||||
"list",
|
"list",
|
||||||
"whois",
|
"whois",
|
||||||
];
|
];
|
||||||
const inputs = [
|
|
||||||
"ban",
|
|
||||||
"ctcp",
|
|
||||||
"msg",
|
|
||||||
"part",
|
|
||||||
"rejoin",
|
|
||||||
"action",
|
|
||||||
"away",
|
|
||||||
"connect",
|
|
||||||
"disconnect",
|
|
||||||
"ignore",
|
|
||||||
"invite",
|
|
||||||
"kick",
|
|
||||||
"kill",
|
|
||||||
"mode",
|
|
||||||
"nick",
|
|
||||||
"notice",
|
|
||||||
"quit",
|
|
||||||
"raw",
|
|
||||||
"topic",
|
|
||||||
"list",
|
|
||||||
"whois",
|
|
||||||
].reduce(function(plugins, name) {
|
|
||||||
const plugin = require(`./plugins/inputs/${name}`);
|
|
||||||
plugin.commands.forEach((command) => plugins[command] = plugin);
|
|
||||||
return plugins;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
function Client(manager, name, config = {}) {
|
function Client(manager, name, config = {}) {
|
||||||
_.merge(this, {
|
_.merge(this, {
|
||||||
@ -362,12 +336,20 @@ Client.prototype.inputLine = function(data) {
|
|||||||
const irc = target.network.irc;
|
const irc = target.network.irc;
|
||||||
let connected = irc && irc.connection && irc.connection.connected;
|
let connected = irc && irc.connection && irc.connection.connected;
|
||||||
|
|
||||||
if (Object.prototype.hasOwnProperty.call(inputs, cmd) && typeof inputs[cmd].input === "function") {
|
if (Object.prototype.hasOwnProperty.call(inputs.userInputs, cmd) && typeof inputs.userInputs[cmd].input === "function") {
|
||||||
const plugin = inputs[cmd];
|
const plugin = inputs.userInputs[cmd];
|
||||||
|
|
||||||
if (connected || plugin.allowDisconnected) {
|
if (connected || plugin.allowDisconnected) {
|
||||||
connected = true;
|
connected = true;
|
||||||
plugin.input.apply(client, [target.network, target.chan, cmd, args]);
|
plugin.input.apply(client,
|
||||||
|
[
|
||||||
|
target.network,
|
||||||
|
target.chan,
|
||||||
|
cmd,
|
||||||
|
args,
|
||||||
|
(command) => this.inputLine({target: data.target, text: command}),
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (connected) {
|
} else if (connected) {
|
||||||
irc.raw(text);
|
irc.raw(text);
|
||||||
|
54
src/plugins/inputs/index.js
Normal file
54
src/plugins/inputs/index.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
const clientSideCommands = ["/collapse", "/expand"];
|
||||||
|
|
||||||
|
const passThroughCommands = [
|
||||||
|
"/as",
|
||||||
|
"/bs",
|
||||||
|
"/cs",
|
||||||
|
"/ho",
|
||||||
|
"/hs",
|
||||||
|
"/join",
|
||||||
|
"/ms",
|
||||||
|
"/ns",
|
||||||
|
"/os",
|
||||||
|
"/rs",
|
||||||
|
];
|
||||||
|
|
||||||
|
const userInputs = [
|
||||||
|
"action",
|
||||||
|
"away",
|
||||||
|
"ban",
|
||||||
|
"connect",
|
||||||
|
"ctcp",
|
||||||
|
"disconnect",
|
||||||
|
"ignore",
|
||||||
|
"invite",
|
||||||
|
"kick",
|
||||||
|
"kill",
|
||||||
|
"list",
|
||||||
|
"mode",
|
||||||
|
"msg",
|
||||||
|
"nick",
|
||||||
|
"notice",
|
||||||
|
"part",
|
||||||
|
"quit",
|
||||||
|
"raw",
|
||||||
|
"rejoin",
|
||||||
|
"topic",
|
||||||
|
"whois",
|
||||||
|
].reduce(function(plugins, name) {
|
||||||
|
const plugin = require(`./${name}`);
|
||||||
|
plugin.commands.forEach((command) => (plugins[command] = plugin));
|
||||||
|
return plugins;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const getCommands = () =>
|
||||||
|
Object.keys(userInputs)
|
||||||
|
.map((command) => `/${command}`)
|
||||||
|
.concat(clientSideCommands)
|
||||||
|
.concat(passThroughCommands)
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getCommands,
|
||||||
|
userInputs,
|
||||||
|
};
|
@ -6,6 +6,7 @@ const path = require("path");
|
|||||||
const Helper = require("../../helper");
|
const Helper = require("../../helper");
|
||||||
const themes = require("./themes");
|
const themes = require("./themes");
|
||||||
const packageMap = new Map();
|
const packageMap = new Map();
|
||||||
|
const inputs = require("../inputs");
|
||||||
|
|
||||||
const stylesheets = [];
|
const stylesheets = [];
|
||||||
|
|
||||||
@ -15,11 +16,15 @@ module.exports = {
|
|||||||
loadPackages,
|
loadPackages,
|
||||||
};
|
};
|
||||||
|
|
||||||
const packageApis = function(packageName) {
|
const packageApis = function(clientManager, packageName) {
|
||||||
return {
|
return {
|
||||||
Stylesheets: {
|
Stylesheets: {
|
||||||
addFile: addStylesheet.bind(this, packageName),
|
addFile: addStylesheet.bind(this, packageName),
|
||||||
},
|
},
|
||||||
|
Commands: {
|
||||||
|
add: (command, func) => inputs.userInputs[command] = func,
|
||||||
|
runAsUser: (line, userName, target) => clientManager.findClient(userName).inputLine({target, text: line}),
|
||||||
|
},
|
||||||
Config: {
|
Config: {
|
||||||
getConfig: () => Helper.config,
|
getConfig: () => Helper.config,
|
||||||
},
|
},
|
||||||
@ -38,7 +43,7 @@ function getPackage(name) {
|
|||||||
return packageMap.get(name);
|
return packageMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPackages() {
|
function loadPackages(clientManager) {
|
||||||
const packageJson = path.join(Helper.getPackagesPath(), "package.json");
|
const packageJson = path.join(Helper.getPackagesPath(), "package.json");
|
||||||
let packages;
|
let packages;
|
||||||
|
|
||||||
@ -75,7 +80,7 @@ function loadPackages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (packageFile.onServerStart) {
|
if (packageFile.onServerStart) {
|
||||||
packageFile.onServerStart(packageApis(packageName));
|
packageFile.onServerStart(packageApis(clientManager, packageName));
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(`Package ${colors.bold(packageName)} loaded`);
|
log.info(`Package ${colors.bold(packageName)} loaded`);
|
||||||
|
@ -16,12 +16,12 @@ const colors = require("chalk");
|
|||||||
const net = require("net");
|
const net = require("net");
|
||||||
const Identification = require("./identification");
|
const Identification = require("./identification");
|
||||||
const changelog = require("./plugins/changelog");
|
const changelog = require("./plugins/changelog");
|
||||||
|
const inputs = require("./plugins/inputs");
|
||||||
|
|
||||||
const themes = require("./plugins/packages/themes");
|
const themes = require("./plugins/packages/themes");
|
||||||
themes.loadLocalThemes();
|
themes.loadLocalThemes();
|
||||||
|
|
||||||
const packages = require("./plugins/packages/index");
|
const packages = require("./plugins/packages/index");
|
||||||
packages.loadPackages();
|
|
||||||
|
|
||||||
// The order defined the priority: the first available plugin is used
|
// The order defined the priority: the first available plugin is used
|
||||||
// ALways keep local auth in the end, which should always be enabled.
|
// ALways keep local auth in the end, which should always be enabled.
|
||||||
@ -173,6 +173,7 @@ module.exports = function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
manager = new ClientManager();
|
manager = new ClientManager();
|
||||||
|
packages.loadPackages(manager);
|
||||||
|
|
||||||
new Identification((identHandler) => {
|
new Identification((identHandler) => {
|
||||||
manager.init(identHandler, sockets);
|
manager.init(identHandler, sockets);
|
||||||
@ -582,6 +583,7 @@ function initializeClient(socket, client, token, lastMessage) {
|
|||||||
networks: client.networks.map((network) => network.getFilteredClone(client.lastActiveChannel, lastMessage)),
|
networks: client.networks.map((network) => network.getFilteredClone(client.lastActiveChannel, lastMessage)),
|
||||||
token: tokenToSend,
|
token: tokenToSend,
|
||||||
});
|
});
|
||||||
|
socket.emit("commands", inputs.getCommands());
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!Helper.config.public && token === null) {
|
if (!Helper.config.public && token === null) {
|
||||||
|
@ -17,19 +17,6 @@ describe("client-side constants", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(".commands", function() {
|
|
||||||
it("should be a non-empty array", function() {
|
|
||||||
expect(constants.commands).to.be.an("array").that.is.not.empty;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should only contain strings with no whitespaces and starting with /", function() {
|
|
||||||
constants.commands.forEach((command) => {
|
|
||||||
expect(command).to.be.a("string").that.does.not.match(/\s/);
|
|
||||||
expect(command[0]).to.equal("/");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(".condensedTypes", function() {
|
describe(".condensedTypes", function() {
|
||||||
it("should be a non-empty array", function() {
|
it("should be a non-empty array", function() {
|
||||||
expect(constants.condensedTypes).to.be.an("array").that.is.not.empty;
|
expect(constants.condensedTypes).to.be.an("array").that.is.not.empty;
|
||||||
|
21
test/plugins/inputs/indexTest.js
Normal file
21
test/plugins/inputs/indexTest.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const inputs = require("../../../src/plugins/inputs");
|
||||||
|
|
||||||
|
describe("inputs", function() {
|
||||||
|
describe(".getCommands", function() {
|
||||||
|
it("should return a non-empty array", function() {
|
||||||
|
expect(inputs.getCommands()).to.be.an("array").that.is.not.empty;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should only return strings with no whitespaces and starting with /", function() {
|
||||||
|
inputs.getCommands().forEach((command) => {
|
||||||
|
expect(command)
|
||||||
|
.to.be.a("string")
|
||||||
|
.that.does.not.match(/\s/);
|
||||||
|
expect(command[0]).to.equal("/");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user