feat: enhance DatabaseManagerService and QueryExecuterService with timeout settings, add AxiosPlugin for HTTP requests, and update DatabasePlugin to use query method
This commit is contained in:
@ -79,6 +79,8 @@ export class DatabaseManagerService extends DatabaseEncryptionService {
|
|||||||
user: queryUser ? database.q_username : database.c_username,
|
user: queryUser ? database.q_username : database.c_username,
|
||||||
password: this.decryptPassword(database.password),
|
password: this.decryptPassword(database.password),
|
||||||
database: database.database,
|
database: database.database,
|
||||||
|
idleTimeout: 150e3,
|
||||||
|
connectTimeout: 2e3,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,7 @@ export class QueryExecuterService {
|
|||||||
{
|
{
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
removeOnFail: true,
|
removeOnFail: true,
|
||||||
attempts: 3,
|
attempts: 0,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -130,6 +130,8 @@ export class QueryExecuterService {
|
|||||||
|
|
||||||
const vm = new Vm({
|
const vm = new Vm({
|
||||||
memoryLimit: 128,
|
memoryLimit: 128,
|
||||||
|
timeLimit: BigInt(100e9),
|
||||||
|
cpuTimeLimit: BigInt(5e9),
|
||||||
modules: modules,
|
modules: modules,
|
||||||
plugins: plugins,
|
plugins: plugins,
|
||||||
});
|
});
|
||||||
|
|||||||
54
src/vm/plugins/axios.plugin.ts
Normal file
54
src/vm/plugins/axios.plugin.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { Plugin } from "../plugin.class";
|
||||||
|
|
||||||
|
export class AxiosPlugin extends Plugin {
|
||||||
|
constructor(name: string) {
|
||||||
|
super(name, ["get", "post", "put", "delete", "head", "options", "patch"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static init(name: string): AxiosPlugin {
|
||||||
|
return new AxiosPlugin(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private configure(config) {
|
||||||
|
if (config.timeout > 10e3) {
|
||||||
|
config.timeout = 10e3;
|
||||||
|
} else {
|
||||||
|
config.timeout = 5e3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(url: string, config?: any): Promise<any> {
|
||||||
|
return await axios.get(url, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async post(url: string, data?: any, config?: any): Promise<any> {
|
||||||
|
return await axios.post(url, data, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async put(url: string, data?: any, config?: any): Promise<any> {
|
||||||
|
return await axios.put(url, data, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(url: string, config?: any): Promise<any> {
|
||||||
|
return await axios.delete(url, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async head(url: string, config?: any): Promise<any> {
|
||||||
|
return await axios.head(url, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async options(url: string, config?: any): Promise<any> {
|
||||||
|
return await axios.options(url, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async patch(url: string, data?: any, config?: any): Promise<any> {
|
||||||
|
return await axios.patch(url, data, this.configure(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
onFinish() {
|
||||||
|
// No resources to clean up
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ export class DatabasePlugin extends Plugin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
super(name, ["execute"]);
|
super(name, ["query"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async init(
|
static async init(
|
||||||
@ -20,6 +20,8 @@ export class DatabasePlugin extends Plugin {
|
|||||||
user: string;
|
user: string;
|
||||||
password: string;
|
password: string;
|
||||||
database: string;
|
database: string;
|
||||||
|
idleTimeout: number;
|
||||||
|
connectTimeout: number;
|
||||||
}
|
}
|
||||||
): Promise<DatabasePlugin> {
|
): Promise<DatabasePlugin> {
|
||||||
const dbConnection = await mysql.createConnection({
|
const dbConnection = await mysql.createConnection({
|
||||||
@ -28,19 +30,18 @@ export class DatabasePlugin extends Plugin {
|
|||||||
port: config.port,
|
port: config.port,
|
||||||
password: config.password,
|
password: config.password,
|
||||||
database: config.database,
|
database: config.database,
|
||||||
|
idleTimeout: config.idleTimeout,
|
||||||
|
connectTimeout: config.connectTimeout,
|
||||||
enableKeepAlive: true,
|
enableKeepAlive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await dbConnection.query("SET SESSION MAX_EXECUTION_TIME=2000;");
|
||||||
|
|
||||||
return new DatabasePlugin(name, dbConnection);
|
return new DatabasePlugin(name, dbConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(query): Promise<any> {
|
async query(query): Promise<any> {
|
||||||
const [rows, fields] = await this.dbConnection.query(query);
|
return await this.dbConnection.query(query);
|
||||||
|
|
||||||
return {
|
|
||||||
rows: rows,
|
|
||||||
fields: fields ?? [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onFinish() {
|
onFinish() {
|
||||||
|
|||||||
@ -10,15 +10,21 @@ export class Vm {
|
|||||||
private jail: any;
|
private jail: any;
|
||||||
private plugins: Plugin[];
|
private plugins: Plugin[];
|
||||||
private isolate: ivm.Isolate;
|
private isolate: ivm.Isolate;
|
||||||
|
private timeLimit?: bigint;
|
||||||
|
private cpuTimeLimit?: bigint;
|
||||||
|
|
||||||
constructor(configs: {
|
constructor(configs: {
|
||||||
memoryLimit: number;
|
memoryLimit: number;
|
||||||
|
timeLimit?: bigint;
|
||||||
|
cpuTimeLimit?: bigint;
|
||||||
modules: VModule[];
|
modules: VModule[];
|
||||||
plugins: Plugin[];
|
plugins: Plugin[];
|
||||||
}) {
|
}) {
|
||||||
this.memoryLimit = configs.memoryLimit;
|
this.memoryLimit = configs.memoryLimit;
|
||||||
this.modules = configs.modules;
|
this.modules = configs.modules;
|
||||||
this.plugins = configs.plugins;
|
this.plugins = configs.plugins;
|
||||||
|
this.timeLimit = configs.timeLimit;
|
||||||
|
this.cpuTimeLimit = configs.cpuTimeLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(): Promise<Vm> {
|
async init(): Promise<Vm> {
|
||||||
@ -111,11 +117,23 @@ export class Vm {
|
|||||||
|
|
||||||
const compiledScript = await this.isolate.compileScript(scriptWithResult);
|
const compiledScript = await this.isolate.compileScript(scriptWithResult);
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (
|
||||||
|
this.isolate.cpuTime > this.cpuTimeLimit ||
|
||||||
|
this.isolate.wallTime > this.timeLimit
|
||||||
|
) {
|
||||||
|
this.isolate.dispose();
|
||||||
|
|
||||||
|
rejectPromise(new Error("Script execution timed out"));
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
compiledScript.run(this.context);
|
compiledScript.run(this.context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await resultPromise;
|
return await resultPromise;
|
||||||
} finally {
|
} finally {
|
||||||
|
clearInterval(interval);
|
||||||
this.onFinish();
|
this.onFinish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { QueryExecuterService } from "src/query/executer/query.executer.service"
|
|||||||
import { DatabasePlugin } from "./plugins/database.plugin";
|
import { DatabasePlugin } from "./plugins/database.plugin";
|
||||||
import { Query } from "src/query/entities/query.entity";
|
import { Query } from "src/query/entities/query.entity";
|
||||||
import { QueryPlugin } from "./plugins/query.plugin";
|
import { QueryPlugin } from "./plugins/query.plugin";
|
||||||
|
import { AxiosPlugin } from "./plugins/axios.plugin";
|
||||||
|
|
||||||
export const registeredPlugins = {
|
export const registeredPlugins = {
|
||||||
db: async (service: QueryExecuterService, query: Query) => {
|
db: async (service: QueryExecuterService, query: Query) => {
|
||||||
@ -17,6 +18,9 @@ export const registeredPlugins = {
|
|||||||
|
|
||||||
return DatabasePlugin.init("db", databaseConnection);
|
return DatabasePlugin.init("db", databaseConnection);
|
||||||
},
|
},
|
||||||
|
axios: async () => {
|
||||||
|
return AxiosPlugin.init("axios");
|
||||||
|
},
|
||||||
query: async (service: QueryExecuterService, query: Query) => {
|
query: async (service: QueryExecuterService, query: Query) => {
|
||||||
return QueryPlugin.init(query, service);
|
return QueryPlugin.init(query, service);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import "module/squel";
|
import "module/squel";
|
||||||
import "plugin/db";
|
import "plugin/db";
|
||||||
|
import "plugin/axios";
|
||||||
|
|
||||||
function createSQL(id) {
|
function createSQL(id) {
|
||||||
return squel.select().from("test").where("id = ?", id).toString();
|
return squel.select().from("test").where("id = ?", id).toString();
|
||||||
@ -11,13 +12,22 @@ function createSQL(id) {
|
|||||||
async function main(input, headers) {
|
async function main(input, headers) {
|
||||||
const sql = createSQL(input.id);
|
const sql = createSQL(input.id);
|
||||||
|
|
||||||
await db.execute("START TRANSACTION");
|
await db.query("START TRANSACTION");
|
||||||
|
|
||||||
// log(await db.execute('insert into test (name) values ("Test")'));
|
// log(await db.query('insert into test (name) values ("Test")'));
|
||||||
|
|
||||||
const res = await db.execute(sql);
|
log(new Date().toISOString());
|
||||||
|
// const a = await axios.get("https://httpbin.dev/delay/10", {
|
||||||
|
// timeout: 50000000,
|
||||||
|
// });
|
||||||
|
|
||||||
log(res);
|
// log(a);
|
||||||
|
|
||||||
|
const res = await db.query(`
|
||||||
|
SELECT SLEEP(10000);
|
||||||
|
`);
|
||||||
|
|
||||||
|
log(new Date().toISOString());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response: {
|
response: {
|
||||||
|
|||||||
Reference in New Issue
Block a user