Skip to content

Commit

Permalink
move language to micro-service
Browse files Browse the repository at this point in the history
  • Loading branch information
greywen committed Aug 9, 2022
1 parent 74bb21e commit ef168de
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 62 deletions.
1 change: 0 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import {
DataResource,
DataDepartment,
UserTimesheet,
Language,
QuestionBank,
]),
],
Expand Down
4 changes: 4 additions & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ interface IConfig {
port: number;
environment: ServerEnvironment;
};
services: {
codeService: string;
};
dingTalk: {
bossId: string;
conversationId: string;
Expand Down Expand Up @@ -74,6 +77,7 @@ export default <IConfig>{
port: config.get('server.port'),
environment: config.get('server.environment'),
},
services: config.get('services'),
dingTalk: {
bossId: config.get('dingTalk.bossId'),
conversationId: config.get('dingTalk.conversationId'),
Expand Down
14 changes: 2 additions & 12 deletions src/controllers/code.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,7 @@ export class CodeController {
testcase,
);

const _result = await this.codeService.run(
language,
codeCommand,
language.timeout * 1000,
);
const _result = await this.codeService.run(languageId, codeCommand);
result.push(_result);

if (once || !_result.isSuccess) {
Expand Down Expand Up @@ -92,13 +88,7 @@ export class CodeController {

async runImplement(body: ICodeRunBody) {
const { code, languageId } = body;
const language = await this.codeService.getLanguage(languageId);
const codeCommand = await this.codeService.prepareCode(language, code);
return await this.codeService.run(
language,
codeCommand,
language.timeout * 1000,
);
return await this.codeService.run(languageId, code);
}

@Get('languages')
Expand Down
5 changes: 5 additions & 0 deletions src/dtos/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ export interface IQuestionDto {
desribe: string;
code: string;
}

export interface ICodeResult {
isSuccess: boolean;
data: any;
}
10 changes: 6 additions & 4 deletions src/entities/language.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ export class Language {
name: string; // 语言名称 node
@Column('varchar', { length: 20 })
version: string; // 语言版本 v16.13.1
@Column('varchar', { length: 100, nullable: true })
image: string; // 镜像名 node
@Column('varchar', { length: 50 })
iamge: string; // 镜像名 node
@Column('varchar', { length: 50 })
file: string; // 保存文件名 index.js
fileName: string; // 保存文件名 index.js
@Column('text', { default: null })
beforInjectionCodeCmd: string; // 注入代码前cmd命令 创建项目/文件夹等
@Column('text', { default: null })
cmd: string; // 运行代码的命令 node index.js
afterInjectionCodeCmd: string; // 注入代码后cmd命令 编译/有运行等
@Column('smallint')
timeout: number; // 运行超时时间 秒 60
@Column('smallint')
Expand Down
14 changes: 14 additions & 0 deletions src/models/language.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export class LanguageModel {
id: number;
name: string; // 语言名称 node
version: string; // 语言版本 v16.13.1
image: string; // 镜像名 node
fileName: string; // 保存文件名 index.js
beforInjectionCodeCmd: string; // 注入代码前cmd命令 创建项目/文件夹等
afterInjectionCodeCmd: string; // 注入代码后cmd命令 编译/有运行等
timeout: number; // 运行超时时间 秒 60
memory: number; // 分配容器内存大小 MB 100
cpuset: string; // 允许容器使用CPU核心 0-4 或者 1,2,4
captureCode: string; // 数据收集代码 运行时长,占用内存等
initialCode: string; // 初始代码
}
70 changes: 25 additions & 45 deletions src/services/code.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Language } from '@entities/language.entity';
import config from '@config/config';
import { ICodeResult } from '@dtos/code';
import { IQuestionCase, QuestionBank } from '@entities/questionBank.entity';
import { LanguageModel } from '@models/language.model';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import spawnPromise from '@utils/spawnPromise';
import { httpGet, httpPost } from '@utils/httpRequest';
import { Repository } from 'typeorm';

@Injectable()
export class CodeService {
constructor(
@InjectRepository(Language)
private readonly languageRepository: Repository<Language>,
@InjectRepository(QuestionBank)
private readonly questionRepository: Repository<QuestionBank>,
) {}
Expand All @@ -21,24 +21,23 @@ export class CodeService {
}

async getLanguage(languageId: number) {
return await this.languageRepository.findOneBy({
id: languageId,
});
const languages = await this.getLanguages();
return languages.find((x) => x.id == languageId);
}

async getLanguages() {
return await this.languageRepository.find();
return await httpGet<LanguageModel[]>(
`${config.services.codeService}/languages`,
);
}

async prepareCode(language: Language, code: string) {
const command = `code="${code}"
cat <<< "$code" > ${language.file}
${language.cmd}
`
.split('${code}')
.join(code);
console.log('command \n ', command);
return command;
prepareCodeCommands(language: LanguageModel, code: string) {
const commands = `${language.beforInjectionCodeCmd}
code="${code.replace(/"/g, '\\"')}"
cat <<< "$code" > ${language.fileName}
${language.afterInjectionCodeCmd}
`;
return commands;
}

async prepareTestCaseCode(
Expand All @@ -53,7 +52,7 @@ export class CodeService {
}

async prepareRunCommand(
language: Language,
language: LanguageModel,
code: string,
entry: string,
cases: IQuestionCase,
Expand All @@ -64,34 +63,15 @@ export class CodeService {
language.captureCode,
);
code += testCaseCode;
return await this.prepareCode(language, code);
return await this.prepareCodeCommands(language, code);
}

async run(
language: Language,
codeCommand: string,
timeout: number,
): Promise<any> {
return await spawnPromise(
'docker',
[
'run',
'--rm',
'-i',
`--memory=${language.memory}m`,
`--cpuset-cpus=${language.cpuset}`,
language.iamge,
'/bin/bash',
'-c',
codeCommand,
],
{ timeout: timeout },
)
.then((data) => {
return { isSuccess: true, data: data };
})
.catch((error) => {
return { isSuccess: false, data: error };
});
async run(languageId: number, code: string): Promise<any> {
return await httpPost<ICodeResult>(`${config.services.codeService}/run`, {
body: JSON.stringify({
languageId: languageId,
code: code,
}),
});
}
}
28 changes: 28 additions & 0 deletions src/utils/httpRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import fetch from 'node-fetch';
export async function httpRequest<T>(
input: RequestInfo | URL,
init?: RequestInit,
): Promise<T> {
const res = await fetch(input, {
headers: {
'Content-Type': 'application/json',
},
...init,
}).then((res): Promise<T> => res.json());
return res;
}

export async function httpPost<T>(
input: RequestInfo | URL,
init?: RequestInit,
): Promise<T> {
init.method = 'POST';
return httpRequest<T>(input, init);
}

export async function httpGet<T>(
input: RequestInfo | URL,
init?: RequestInit,
): Promise<T> {
return httpRequest<T>(input, { method: 'GET', ...init });
}
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
],
"@entities/*": [
"./src/entities/*"
],
"@models/*": [
"./src/models/*"
]
}
}
Expand Down

0 comments on commit ef168de

Please sign in to comment.