Skip to content

Commit

Permalink
Add code api
Browse files Browse the repository at this point in the history
  • Loading branch information
greywen committed Aug 5, 2022
1 parent 46b8852 commit e24eebb
Show file tree
Hide file tree
Showing 16 changed files with 486 additions and 19 deletions.
32 changes: 16 additions & 16 deletions processes.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"apps": [
{
"name": "summer",
"script": "./dist/main.js",
"cwd": "./",
"instances": "1",
"exec_mode": "cluster",
"max_restarts": "10",
"error_file": "./logs/err.log",
"out_file": "./logs/out.log",
"log_date_format": "YYYY-MM-DD HH:mm:ss Z",
"watch": ["dist", "config"]
}
]
}
{
"apps": [
{
"name": "summer",
"script": "./dist/main.js",
"cwd": "./",
"instances": "2",
"exec_mode": "cluster",
"max_restarts": "10",
"error_file": "./logs/err.log",
"out_file": "./logs/out.log",
"log_date_format": "YYYY-MM-DD HH:mm:ss Z",
"watch": ["dist", "config"]
}
]
}
20 changes: 18 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
TimeSheetController,
UserController,
InformController,
CodeController,
} from './controllers';
import {
jwtModuleOptions,
Expand All @@ -28,9 +29,16 @@ import {
UserService,
InformService,
TimeSheetService,
CodeService,
} from './services';
import { JwtStrategy, WsGuard } from './strategys';
import { DataResource, DataDepartment, UserTimesheet } from './entities';
import {
DataResource,
DataDepartment,
UserTimesheet,
Language,
QuestionBank,
} from './entities';

@Module({
imports: [
Expand All @@ -39,7 +47,13 @@ import { DataResource, DataDepartment, UserTimesheet } from './entities';
RedisModule.forRoot(redisModuleOptions),
ScheduleModule.forRoot(),
TypeOrmModule.forRoot(typeOrmOptions),
TypeOrmModule.forFeature([DataResource, DataDepartment, UserTimesheet]),
TypeOrmModule.forFeature([
DataResource,
DataDepartment,
UserTimesheet,
Language,
QuestionBank,
]),
],
controllers: [
AppController,
Expand All @@ -49,6 +63,7 @@ import { DataResource, DataDepartment, UserTimesheet } from './entities';
TimeSheetController,
UserController,
InformController,
CodeController,
],
providers: [
WsGuard,
Expand All @@ -59,6 +74,7 @@ import { DataResource, DataDepartment, UserTimesheet } from './entities';
AuthService,
UserService,
InformService,
CodeService,
TimeSheetService,
TimeSheetSocket,
TimeSheetSchedule,
Expand Down
127 changes: 127 additions & 0 deletions src/controllers/code.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { ICodeRunBody, IQuestionDto } from '@dtos/code';
import { Controller, UseGuards, Post, Body, Get, Param } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { CodeService } from '@services/code.service';
import recorder from '@utils/recorder';
import { sleep } from '@utils/utils';
import { v4 as uuid } from 'uuid';
import { ICodeLanguageDto } from '@dtos/code';
const MAX_WAITING_TIME = 360;

@UseGuards(AuthGuard('jwt'))
@Controller('code')
export class CodeController {
constructor(private readonly codeService: CodeService) {}
@Post('run/case')
async runByCase(@Body() body: ICodeRunBody): Promise<any> {
const id = uuid();
let waitTime = 0;
let result = null;

recorder.add({
id: id,
fn: async () => await this.runByCaseImplement(body),
});

while (!result) {
await sleep(0.2);
result = recorder.get(id);

waitTime++;
if (waitTime > MAX_WAITING_TIME) {
result = { isSuccess: false, message: '运行超时' };
}
}

return result;
}

async runByCaseImplement(body: ICodeRunBody) {
const { code, questionId, languageId, once } = body;

const question = await this.codeService.getQuestion(questionId);
const language = await this.codeService.getLanguage(languageId);
const result = [];

for (const testcase of question.cases) {
const codeCommand = await this.codeService.prepareRunCommand(
language,
code,
question.entry,
testcase,
);

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

if (once || !_result.isSuccess) {
break;
}
}

return result;
}

@Post('run')
async run(@Body() body: ICodeRunBody): Promise<any> {
const id = uuid();
let waitTime = 0;
let result = null;

recorder.add({
id: id,
fn: async () => await this.runImplement(body),
});

while (!result) {
await sleep(0.1);
result = recorder.get(id);

waitTime++;
if (waitTime > MAX_WAITING_TIME) {
result = { isSuccess: false, data: '执行超时.' };
}
}

return result;
}

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

@Get('languages')
async getLanguages() {
const data = await this.codeService.getLanguages();
return data.map((x) => {
return {
id: x.id,
name: x.name,
initialCode: x.initialCode,
version: x.version,
} as ICodeLanguageDto;
});
}

@Get('question/:questionId')
async getQuestion(@Param('questionId') questionId: string) {
const data = await this.codeService.getQuestion(questionId);
return {
id: data.id,
name: data.name,
desribe: data.describe,
code: data.code,
} as IQuestionDto;
}
}
1 change: 1 addition & 0 deletions src/controllers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './auth.controller';
export * from './timesheet.controller';
export * from './user.controller';
export * from './inform.controller';
export * from './code.controller';
20 changes: 20 additions & 0 deletions src/dtos/code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export interface ICodeRunBody {
once?: boolean;
code: string;
questionId: string;
languageId: number;
}

export interface ICodeLanguageDto {
id: number;
name: string;
initialCode: string;
version: string;
}

export interface IQuestionDto {
id: string;
name: string;
desribe: string;
code: string;
}
2 changes: 2 additions & 0 deletions src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './data.department.entity';
export * from './data.permission.entity';
export * from './timesheet.enetity';
export * from './language.entity';
export * from './questionBank.entity';
29 changes: 29 additions & 0 deletions src/entities/language.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';

@Entity({ name: 'language' })
export class Language {
@PrimaryColumn({ generated: 'increment' })
id: number;
@Column('varchar', { unique: true, length: 30 })
name: string; // 语言名称 node
@Column('varchar', { length: 20 })
version: string; // 语言版本 v16.13.1
@Column('varchar', { length: 50 })
iamge: string; // 镜像名 node
@Column('varchar', { length: 50 })
file: string; // 保存文件名 index.js
@Column('varchar', { length: 50 })
cmd: string; // 运行代码的命令 node index.js
@Column('smallint')
timeout: number; // 运行超时时间 秒 60
@Column('smallint')
memory: number; // 分配容器内存大小 MB 100
@Column('varchar', { length: 10 })
cpuset: string; // 允许容器使用CPU核心 0-4 或者 1,2,4
@Column('text')
captureCode: string; // 数据收集代码 运行时长,占用内存等
@Column('text', { nullable: true })
initialCode: string; // 初始代码
@Column('timestamp')
craeteTime: string;
}
26 changes: 26 additions & 0 deletions src/entities/questionBank.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Column, Entity } from 'typeorm';

@Entity({ name: 'question_bank' })
export class QuestionBank {
@Column({ primary: true, generated: 'uuid' })
id: string;
@Column('varchar', { length: 100 })
name: string; // 题目名称
@Column('varchar', { length: 50 })
entry: string; // 入口方法
@Column('text')
code: string; // 默认填充代码
@Column('text')
describe?: string; // 题目描述
@Column('jsonb', { array: false, default: () => "'[]'", nullable: true })
cases?: IQuestionCase[]; // 测试cases
@Column('jsonb', { array: false, default: () => "'[]'", nullable: true })
contributor?: string[]; // 贡献者 可以多个
@Column('date')
createTime: string;
}

export class IQuestionCase {
case: any;
assert: any;
}
Loading

0 comments on commit e24eebb

Please sign in to comment.