mirror of
https://github.com/engineer-man/piston.git
synced 2025-04-23 21:46:27 +02:00
feat: tooling api
This commit is contained in:
parent
7e09a3f9cd
commit
452b9d91d3
7 changed files with 90 additions and 12 deletions
|
@ -59,6 +59,7 @@ const SIGNALS = [
|
|||
function get_job(body: RequestBody): Promise<Job> {
|
||||
let {
|
||||
language,
|
||||
tool,
|
||||
version,
|
||||
args,
|
||||
stdin,
|
||||
|
@ -159,6 +160,7 @@ function get_job(body: RequestBody): Promise<Job> {
|
|||
run: run_memory_limit,
|
||||
compile: compile_memory_limit,
|
||||
},
|
||||
tool
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -291,6 +293,22 @@ router.post('/execute', async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.post('/tooling',async (req, res) => {
|
||||
try {
|
||||
const job = await get_job(req.body);
|
||||
|
||||
await job.prime();
|
||||
|
||||
const result = await job.analysis();
|
||||
|
||||
await job.cleanup();
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (error) {
|
||||
return res.status(400).json(error)
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/runtimes', (req, res) => {
|
||||
const runtimes = _runtimes.map(rt => {
|
||||
return {
|
||||
|
@ -298,6 +316,7 @@ router.get('/runtimes', (req, res) => {
|
|||
version: rt.version.raw,
|
||||
aliases: rt.aliases,
|
||||
runtime: rt.runtime,
|
||||
tooling: rt.tooling
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import { spawn } from 'child_process';
|
|||
import { join, relative, dirname } from 'node:path';
|
||||
import config from './config.js';
|
||||
import * as globals from './globals.js';
|
||||
import { type Runtime } from './runtime.js';
|
||||
import {
|
||||
mkdir,
|
||||
chown,
|
||||
|
@ -18,7 +19,7 @@ import { readdirSync, readFileSync } from 'node:fs';
|
|||
import wait_pid from 'waitpid';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import { File, ResponseBody } from './types.js';
|
||||
import { File, LimitObject, ResponseBody } from './types.js';
|
||||
|
||||
const job_states = {
|
||||
READY: Symbol('Ready to be primed'),
|
||||
|
@ -42,35 +43,40 @@ setInterval(() => {
|
|||
export default class Job {
|
||||
uuid: string;
|
||||
logger: Logger;
|
||||
runtime: any;
|
||||
runtime: Runtime;
|
||||
tool?: string;
|
||||
files: File[];
|
||||
args: string[];
|
||||
stdin: string;
|
||||
timeouts: { compile: number; run: number };
|
||||
memory_limits: { compile: number; run: number };
|
||||
timeouts: LimitObject;
|
||||
memory_limits: LimitObject;
|
||||
uid: number;
|
||||
gid: number;
|
||||
state: symbol;
|
||||
dir: string;
|
||||
constructor({
|
||||
runtime,
|
||||
tool,
|
||||
files,
|
||||
args,
|
||||
stdin,
|
||||
timeouts,
|
||||
memory_limits,
|
||||
}: {
|
||||
runtime: unknown;
|
||||
runtime: Runtime;
|
||||
tool?: string;
|
||||
files: File[];
|
||||
args: string[];
|
||||
stdin: string;
|
||||
timeouts: { compile: number; run: number };
|
||||
memory_limits: { compile: number; run: number };
|
||||
timeouts: LimitObject;
|
||||
memory_limits: LimitObject;
|
||||
}) {
|
||||
this.uuid = uuidv4();
|
||||
|
||||
this.logger = create(`job/${this.uuid}`, {});
|
||||
|
||||
|
||||
this.tool = tool;
|
||||
|
||||
this.runtime = runtime;
|
||||
this.files = files.map((file: File, i: number) => ({
|
||||
name: file.name || `file${i}.code`,
|
||||
|
@ -80,6 +86,7 @@ export default class Job {
|
|||
: 'utf8',
|
||||
}));
|
||||
|
||||
|
||||
this.args = args;
|
||||
this.stdin = stdin;
|
||||
|
||||
|
@ -193,6 +200,7 @@ export default class Job {
|
|||
env: {
|
||||
...this.runtime.env_vars,
|
||||
PISTON_LANGUAGE: this.runtime.language,
|
||||
PISTON_TOOLING: this.tool
|
||||
},
|
||||
stdio: 'pipe',
|
||||
cwd: this.dir,
|
||||
|
@ -271,6 +279,45 @@ export default class Job {
|
|||
});
|
||||
}
|
||||
|
||||
async analysis() {
|
||||
if (this.state !== job_states.PRIMED) {
|
||||
throw new Error(
|
||||
'Job must be in primed state, current state: ' +
|
||||
this.state.toString()
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.runtime.tooling.includes(this.tool)) {
|
||||
throw new Error(
|
||||
`Tool ${this.tool} does not exist on ${this.runtime.toString()}`
|
||||
)
|
||||
}
|
||||
|
||||
this.logger.info(`Tooling job runtime=${this.runtime.toString()}; tooling=${this.tool}`);
|
||||
|
||||
const code_files =
|
||||
(this.runtime.language === 'file' && this.files) ||
|
||||
this.files.filter((file: File) => file.encoding == 'utf8');
|
||||
|
||||
|
||||
const output = await this.safe_call(
|
||||
join(this.runtime.pkgdir, 'tooling'),
|
||||
code_files.map(x => x.name),
|
||||
this.timeouts.run,
|
||||
this.memory_limits.run
|
||||
);
|
||||
|
||||
this.logger.debug('Analyzing')
|
||||
|
||||
|
||||
return {
|
||||
output,
|
||||
language: this.runtime.language,
|
||||
tool: this.tool,
|
||||
version: this.runtime.version.raw
|
||||
}
|
||||
}
|
||||
|
||||
async execute() {
|
||||
if (this.state !== job_states.PRIMED) {
|
||||
throw new Error(
|
||||
|
|
|
@ -12,6 +12,7 @@ export const runtimes: Runtime[] = [];
|
|||
|
||||
export class Runtime {
|
||||
language: string;
|
||||
tooling: string[];
|
||||
version: SemVer;
|
||||
aliases: string[];
|
||||
pkgdir: string;
|
||||
|
@ -26,10 +27,11 @@ export class Runtime {
|
|||
_env_vars?: Record<string, any>;
|
||||
constructor(o: {
|
||||
language: string;
|
||||
tooling?: string[];
|
||||
version: SemVer;
|
||||
aliases: string[];
|
||||
pkgdir: string;
|
||||
runtime?: any;
|
||||
runtime?: string;
|
||||
timeouts: { run: number; compile: number };
|
||||
memory_limits: { run: number; compile: number };
|
||||
max_process_count: number;
|
||||
|
@ -38,6 +40,7 @@ export class Runtime {
|
|||
output_max_size: number;
|
||||
}) {
|
||||
this.language = o.language;
|
||||
this.tooling = o.tooling;
|
||||
this.version = o.version;
|
||||
this.aliases = o.aliases || [];
|
||||
this.pkgdir = o.pkgdir;
|
||||
|
@ -128,6 +131,7 @@ export class Runtime {
|
|||
aliases,
|
||||
provides,
|
||||
limit_overrides,
|
||||
tooling
|
||||
} = info;
|
||||
const version = parse(_version);
|
||||
|
||||
|
@ -145,6 +149,7 @@ export class Runtime {
|
|||
new Runtime({
|
||||
language: lang.language,
|
||||
aliases: lang.aliases,
|
||||
tooling,
|
||||
version,
|
||||
pkgdir: package_dir,
|
||||
runtime: language,
|
||||
|
@ -160,6 +165,7 @@ export class Runtime {
|
|||
new Runtime({
|
||||
language,
|
||||
version,
|
||||
tooling,
|
||||
aliases,
|
||||
pkgdir: package_dir,
|
||||
...Runtime.compute_all_limits(language, limit_overrides),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export interface Metadata {
|
||||
language: string;
|
||||
version: string;
|
||||
tooling?: string[];
|
||||
aliases?: string[];
|
||||
dependencies?: Record<string, string>;
|
||||
provides: {
|
||||
|
@ -23,6 +24,8 @@ export type Limit =
|
|||
|
||||
export type Limits = Record<Limit, number>;
|
||||
|
||||
export type LimitObject = { compile: number; run: number; };
|
||||
|
||||
export type LanguageMetadata = {
|
||||
language: string;
|
||||
version: string;
|
||||
|
@ -37,6 +40,7 @@ export type File = {
|
|||
};
|
||||
export type RequestBody = {
|
||||
language: string;
|
||||
tool?: string;
|
||||
version: string;
|
||||
files: Array<File>;
|
||||
stdin?: string;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue