feat: tooling api

This commit is contained in:
Endercheif 2023-03-15 22:30:13 -07:00
parent 7e09a3f9cd
commit 452b9d91d3
No known key found for this signature in database
GPG key ID: 7767459A0C8BEE00
7 changed files with 90 additions and 12 deletions

View file

@ -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
};
});

View file

@ -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(

View file

@ -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),

View file

@ -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;