2021-02-20 23:39:03 +01:00
|
|
|
const logger = require('logplease').create('runtime');
|
|
|
|
const semver = require('semver');
|
|
|
|
const config = require('./config');
|
|
|
|
const globals = require('./globals');
|
|
|
|
const fss = require('fs');
|
|
|
|
const path = require('path');
|
2021-02-20 15:13:56 +01:00
|
|
|
|
2021-02-20 23:39:03 +01:00
|
|
|
const runtimes = [];
|
2021-02-20 15:13:56 +01:00
|
|
|
|
|
|
|
class Runtime {
|
2021-10-02 14:08:36 +02:00
|
|
|
constructor({
|
2021-10-08 15:16:57 +02:00
|
|
|
language,
|
|
|
|
version,
|
|
|
|
aliases,
|
|
|
|
pkgdir,
|
|
|
|
runtime,
|
|
|
|
timeouts,
|
|
|
|
memory_limits,
|
|
|
|
max_process_count,
|
|
|
|
max_open_files,
|
|
|
|
max_file_size,
|
|
|
|
output_max_size,
|
2021-10-02 14:08:36 +02:00
|
|
|
}) {
|
2021-05-08 02:30:40 +02:00
|
|
|
this.language = language;
|
|
|
|
this.version = version;
|
|
|
|
this.aliases = aliases || [];
|
|
|
|
this.pkgdir = pkgdir;
|
|
|
|
this.runtime = runtime;
|
2021-10-02 14:08:36 +02:00
|
|
|
this.timeouts = timeouts;
|
|
|
|
this.memory_limits = memory_limits;
|
|
|
|
this.max_process_count = max_process_count;
|
|
|
|
this.max_open_files = max_open_files;
|
|
|
|
this.max_file_size = max_file_size;
|
|
|
|
this.output_max_size = output_max_size;
|
|
|
|
}
|
|
|
|
|
2021-10-08 15:16:57 +02:00
|
|
|
static compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
limit_name,
|
|
|
|
language_limit_overrides
|
|
|
|
) {
|
2021-10-02 14:08:36 +02:00
|
|
|
return (
|
2021-10-08 15:16:57 +02:00
|
|
|
(config.limit_overrides[language_name] &&
|
|
|
|
config.limit_overrides[language_name][limit_name]) ||
|
|
|
|
(language_limit_overrides &&
|
|
|
|
language_limit_overrides[limit_name]) ||
|
|
|
|
config[limit_name]
|
2021-10-02 14:08:36 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
static compute_all_limits(language_name, language_limit_overrides) {
|
|
|
|
return {
|
|
|
|
timeouts: {
|
2021-10-08 15:16:57 +02:00
|
|
|
compile: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'compile_timeout',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
|
|
|
run: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'run_timeout',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
2021-10-02 14:08:36 +02:00
|
|
|
},
|
|
|
|
memory_limits: {
|
2021-10-08 15:16:57 +02:00
|
|
|
compile: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'compile_memory_limit',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
|
|
|
run: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'run_memory_limit',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
2021-10-02 14:08:36 +02:00
|
|
|
},
|
2021-10-08 15:16:57 +02:00
|
|
|
max_process_count: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'max_process_count',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
|
|
|
max_open_files: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'max_open_files',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
|
|
|
max_file_size: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'max_file_size',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
|
|
|
output_max_size: this.compute_single_limit(
|
|
|
|
language_name,
|
|
|
|
'output_max_size',
|
|
|
|
language_limit_overrides
|
|
|
|
),
|
|
|
|
};
|
2021-04-25 05:02:57 +02:00
|
|
|
}
|
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
static load_package(package_dir) {
|
|
|
|
let info = JSON.parse(
|
|
|
|
fss.read_file_sync(path.join(package_dir, 'pkg-info.json'))
|
2021-02-20 23:39:03 +01:00
|
|
|
);
|
2021-05-08 02:30:40 +02:00
|
|
|
|
2021-10-08 15:16:57 +02:00
|
|
|
let {
|
|
|
|
language,
|
|
|
|
version,
|
|
|
|
build_platform,
|
|
|
|
aliases,
|
|
|
|
provides,
|
|
|
|
limit_overrides,
|
|
|
|
} = info;
|
2021-05-08 02:30:40 +02:00
|
|
|
version = semver.parse(version);
|
|
|
|
|
|
|
|
if (build_platform !== globals.platform) {
|
|
|
|
logger.warn(
|
|
|
|
`Package ${language}-${version} was built for platform ${build_platform}, ` +
|
|
|
|
`but our platform is ${globals.platform}`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (provides) {
|
|
|
|
// Multiple languages in 1 package
|
|
|
|
provides.forEach(lang => {
|
|
|
|
runtimes.push(
|
|
|
|
new Runtime({
|
|
|
|
language: lang.language,
|
|
|
|
aliases: lang.aliases,
|
|
|
|
version,
|
|
|
|
pkgdir: package_dir,
|
|
|
|
runtime: language,
|
2021-10-08 15:16:57 +02:00
|
|
|
...Runtime.compute_all_limits(
|
|
|
|
lang.language,
|
|
|
|
lang.limit_overrides
|
|
|
|
),
|
2021-05-08 02:30:40 +02:00
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
runtimes.push(
|
|
|
|
new Runtime({
|
|
|
|
language,
|
|
|
|
version,
|
|
|
|
aliases,
|
|
|
|
pkgdir: package_dir,
|
2021-10-08 15:16:57 +02:00
|
|
|
...Runtime.compute_all_limits(language, limit_overrides),
|
2021-05-08 02:30:40 +02:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.debug(`Package ${language}-${version} was loaded`);
|
2021-02-20 15:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
get compiled() {
|
|
|
|
if (this._compiled === undefined) {
|
|
|
|
this._compiled = fss.exists_sync(path.join(this.pkgdir, 'compile'));
|
|
|
|
}
|
2021-02-20 15:13:56 +01:00
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
return this._compiled;
|
2021-02-20 15:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
get env_vars() {
|
|
|
|
if (!this._env_vars) {
|
|
|
|
const env_file = path.join(this.pkgdir, '.env');
|
|
|
|
const env_content = fss.read_file_sync(env_file).toString();
|
2021-03-13 06:01:04 +01:00
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
this._env_vars = {};
|
2021-03-13 06:01:04 +01:00
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
env_content
|
|
|
|
.trim()
|
|
|
|
.split('\n')
|
|
|
|
.map(line => line.split('=', 2))
|
|
|
|
.forEach(([key, val]) => {
|
|
|
|
this._env_vars[key.trim()] = val.trim();
|
|
|
|
});
|
|
|
|
}
|
2021-03-13 06:01:04 +01:00
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
return this._env_vars;
|
2021-02-20 15:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
toString() {
|
|
|
|
return `${this.language}-${this.version.raw}`;
|
|
|
|
}
|
2021-05-08 02:20:21 +02:00
|
|
|
|
2021-05-08 02:30:40 +02:00
|
|
|
unregister() {
|
|
|
|
const index = runtimes.indexOf(this);
|
|
|
|
runtimes.splice(index, 1); //Remove from runtimes list
|
|
|
|
}
|
2021-02-20 15:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-02-20 23:39:03 +01:00
|
|
|
module.exports = runtimes;
|
|
|
|
module.exports.Runtime = Runtime;
|
2021-05-08 02:20:21 +02:00
|
|
|
module.exports.get_runtimes_matching_language_version = function (lang, ver) {
|
2021-05-08 02:30:40 +02:00
|
|
|
return runtimes.filter(
|
|
|
|
rt =>
|
|
|
|
(rt.language == lang || rt.aliases.includes(lang)) &&
|
|
|
|
semver.satisfies(rt.version, ver)
|
|
|
|
);
|
2021-02-20 23:39:03 +01:00
|
|
|
};
|
2021-05-08 02:20:21 +02:00
|
|
|
module.exports.get_latest_runtime_matching_language_version = function (
|
2021-05-08 02:30:40 +02:00
|
|
|
lang,
|
|
|
|
ver
|
2021-05-08 02:20:21 +02:00
|
|
|
) {
|
2021-05-08 02:30:40 +02:00
|
|
|
return module.exports
|
|
|
|
.get_runtimes_matching_language_version(lang, ver)
|
|
|
|
.sort((a, b) => semver.rcompare(a.version, b.version))[0];
|
2021-02-20 23:39:03 +01:00
|
|
|
};
|
2021-04-25 05:02:57 +02:00
|
|
|
|
2021-05-08 02:20:21 +02:00
|
|
|
module.exports.get_runtime_by_name_and_version = function (runtime, ver) {
|
2021-05-08 02:30:40 +02:00
|
|
|
return runtimes.find(
|
|
|
|
rt =>
|
|
|
|
(rt.runtime == runtime ||
|
|
|
|
(rt.runtime === undefined && rt.language == runtime)) &&
|
|
|
|
semver.satisfies(rt.version, ver)
|
|
|
|
);
|
2021-05-08 02:20:21 +02:00
|
|
|
};
|
2021-04-25 05:02:57 +02:00
|
|
|
|
2021-05-07 21:22:25 +02:00
|
|
|
module.exports.load_package = Runtime.load_package;
|