Initial commit
This commit is contained in:
commit
07ec57a453
27 changed files with 1853 additions and 0 deletions
50
src/struct/CompilerClient.js
Normal file
50
src/struct/CompilerClient.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
const { AkairoClient, CommandHandler, ListenerHandler } = require('discord-akairo');
|
||||
const LanguageHandler = require('./LanguageHandler');
|
||||
const path = require('path');
|
||||
|
||||
class CompilerClient extends AkairoClient {
|
||||
constructor(config) {
|
||||
super({
|
||||
ownerID: config.owner
|
||||
}, {
|
||||
disabledEveryone: true,
|
||||
disabledEvents: ['TYPING_START']
|
||||
});
|
||||
|
||||
this.commandHandler = new CommandHandler(this, {
|
||||
directory: path.join(__dirname, '../commands'),
|
||||
prefix: '>',
|
||||
allowMention: true,
|
||||
commandUtil: true,
|
||||
commandUtilLifetime: 3e5,
|
||||
handleEdits: true
|
||||
});
|
||||
|
||||
this.listenerHandler = new ListenerHandler(this, {
|
||||
directory: path.join(__dirname, '../listeners')
|
||||
});
|
||||
|
||||
this.languageHandler = new LanguageHandler(this, {
|
||||
directory: path.join(__dirname, '../languages')
|
||||
});
|
||||
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.commandHandler.useListenerHandler(this.listenerHandler);
|
||||
this.listenerHandler.setEmitters({
|
||||
commandHandler: this.commandHandler,
|
||||
listenerHandler: this.listenerHandler,
|
||||
languageHandler: this.languageHandler
|
||||
});
|
||||
|
||||
this.commandHandler.loadAll();
|
||||
this.listenerHandler.loadAll();
|
||||
this.languageHandler.loadAll();
|
||||
this.languageHandler.buildDocker();
|
||||
return this.login(this.config.token);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CompilerClient;
|
22
src/struct/Language.js
Normal file
22
src/struct/Language.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const { AkairoModule } = require('discord-akairo');
|
||||
|
||||
class Language extends AkairoModule {
|
||||
constructor(id, {
|
||||
category,
|
||||
highlight,
|
||||
aliases,
|
||||
options = {}
|
||||
} = {}) {
|
||||
super(id, { category });
|
||||
|
||||
this.highlight = highlight;
|
||||
this.aliases = aliases;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
runWith() {
|
||||
return { id: this.id, env: {} };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Language;
|
107
src/struct/LanguageHandler.js
Normal file
107
src/struct/LanguageHandler.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
const { AkairoHandler } = require('discord-akairo');
|
||||
const { Collection } = require('discord.js');
|
||||
const Language = require('./Language');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
class LanguageHandler extends AkairoHandler {
|
||||
constructor(client, {
|
||||
directory,
|
||||
classToHandle = Language,
|
||||
extensions = ['.js', '.ts'],
|
||||
automateCategories,
|
||||
loadFilter
|
||||
}) {
|
||||
super(client, {
|
||||
directory,
|
||||
classToHandle,
|
||||
extensions,
|
||||
automateCategories,
|
||||
loadFilter
|
||||
});
|
||||
|
||||
this.aliases = new Collection();
|
||||
}
|
||||
|
||||
register(language, filepath) {
|
||||
super.register(language, filepath);
|
||||
|
||||
for (let alias of language.aliases) {
|
||||
const conflict = this.aliases.get(alias.toLowerCase());
|
||||
if (conflict) throw new TypeError(`Alias conflict of ${alias} between ${language.id} and ${conflict}`);
|
||||
|
||||
alias = alias.toLowerCase();
|
||||
this.aliases.set(alias, language.id);
|
||||
}
|
||||
}
|
||||
|
||||
deregister(language) {
|
||||
for (let alias of language.aliases) {
|
||||
alias = alias.toLowerCase();
|
||||
this.aliases.delete(alias);
|
||||
}
|
||||
|
||||
super.deregister(language);
|
||||
}
|
||||
|
||||
findLanguage(alias) {
|
||||
return this.modules.get(this.aliases.get(alias.toLowerCase()));
|
||||
}
|
||||
|
||||
buildDocker() {
|
||||
for (const [, { id }] of this.modules) {
|
||||
childProcess.execSync(`docker build -t "1computer1/comp_iler:${id}" ./docker/${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
evalCode(message, { language, code, options }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const name = `comp_iler-${message.id}-${Date.now()}`;
|
||||
const { id, env } = language.runWith(options);
|
||||
const proc = childProcess.spawn('docker', [
|
||||
'run', '--rm', `--name=${name}`,
|
||||
'--net=none', '--cpus=0.5', '-m=256m',
|
||||
...Object.entries(env).map(([k, v]) => `-e${k}=${v}`),
|
||||
`1computer1/comp_iler:${id}`,
|
||||
'/bin/sh', '/var/run/run.sh', code
|
||||
]);
|
||||
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (process.platform === 'win32') {
|
||||
childProcess.execSync(`docker kill --signal=9 ${name} >nul 2>nul`);
|
||||
} else {
|
||||
childProcess.execSync(`docker kill --signal=9 ${name} >/dev/null 2>/dev/nul`);
|
||||
}
|
||||
|
||||
reject(new Error('Evaluation timed out'));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
let data = '';
|
||||
proc.stdout.on('data', chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
proc.stderr.on('data', chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
proc.on('error', error => {
|
||||
error.data = data;
|
||||
reject(error);
|
||||
});
|
||||
|
||||
proc.on('exit', status => {
|
||||
if (status !== 0) {
|
||||
reject(new Error(data));
|
||||
} else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LanguageHandler;
|
Loading…
Add table
Add a link
Reference in a new issue