diff --git a/packages/vjudge/package.json b/packages/vjudge/package.json index 3ad27b2ac..c788178d6 100644 --- a/packages/vjudge/package.json +++ b/packages/vjudge/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/vjudge", - "version": "1.5.0-next.11", + "version": "1.5.0-next.12", "description": "Submit problems to remote oj", "main": "package.json", "repository": "https://github.com/hydro-dev/Hydro.git", diff --git a/packages/vjudge/src/interface.ts b/packages/vjudge/src/interface.ts index 0b623c72c..4cf5f196c 100644 --- a/packages/vjudge/src/interface.ts +++ b/packages/vjudge/src/interface.ts @@ -1,3 +1,5 @@ +import { JudgeResultBody } from 'hydrooj'; + export interface RemoteAccount { _id: string; type: string; @@ -20,6 +22,7 @@ declare module 'hydrooj/src/interface' { mountInfo?: any; } } +type NextFunction = (body: Partial) => void; export interface IBasicProvider { ensureLogin(): Promise; getProblem(id: string, meta: Record): Promise<{ @@ -32,8 +35,8 @@ export interface IBasicProvider { }>; entryProblemLists?: string[]; listProblem(page: number, resync: boolean, listId: string): Promise; - submitProblem(id: string, lang: string, code: string, info: any, next: any, end: any): Promise; - waitForSubmission(id: string, next: any, end: any): Promise; + submitProblem(id: string, lang: string, code: string, info: any, next: NextFunction, end: NextFunction): Promise; + waitForSubmission(id: string, next: NextFunction, end: NextFunction): Promise; } export interface BasicProvider { diff --git a/packages/vjudge/src/providers/csgoj.ts b/packages/vjudge/src/providers/csgoj.ts new file mode 100644 index 000000000..86fa65c4f --- /dev/null +++ b/packages/vjudge/src/providers/csgoj.ts @@ -0,0 +1,199 @@ +/* eslint-disable no-await-in-loop */ +import { PassThrough } from 'stream'; +import { JSDOM } from 'jsdom'; +import * as superagent from 'superagent'; +import proxy from 'superagent-proxy'; +import { STATUS } from '@hydrooj/utils/lib/status'; +import { sleep } from '@hydrooj/utils/lib/utils'; +import { Logger } from 'hydrooj/src/logger'; +import { IBasicProvider, RemoteAccount } from '../interface'; + +proxy(superagent as any); +const logger = new Logger('remote/csgoj'); +const statusDict = { + 0: STATUS.STATUS_COMPILING, + 1: STATUS.STATUS_COMPILING, + 2: STATUS.STATUS_COMPILING, + 3: STATUS.STATUS_JUDGING, + 4: STATUS.STATUS_ACCEPTED, + 5: STATUS.STATUS_WRONG_ANSWER, + 6: STATUS.STATUS_WRONG_ANSWER, + 7: STATUS.STATUS_TIME_LIMIT_EXCEEDED, + 8: STATUS.STATUS_MEMORY_LIMIT_EXCEEDED, + 9: STATUS.STATUS_OUTPUT_LIMIT_EXCEEDED, + 10: STATUS.STATUS_RUNTIME_ERROR, + 11: STATUS.STATUS_COMPILE_ERROR, +}; + +/* langs +csgoj: + display: CsgOJ + execute: /bin/echo Invalid + hidden: true + remote: csgoj +csgoj.0: + display: C + monaco: c + highlight: c astyle-c + comment: // +csgoj.1: + display: C++ + monaco: cpp + highlight: cpp astyle-c + comment: // +csgoj.2: + display: Pascal + monaco: pascal + highlight: pascal + comment: // +csgoj.3: + display: Java + monaco: java + highlight: java astyle-java + comment: // +*/ + +const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'; + +export default class CSGOJProvider implements IBasicProvider { + constructor(public account: RemoteAccount, private save: (data: any) => Promise) { + if (account.cookie) this.cookie = account.cookie; + } + + cookie: string[] = []; + + get(url: string) { + logger.debug('get', url); + if (!url.includes('//')) url = `${this.account.endpoint || 'https://cpc.csgrandeur.cn'}${url}`; + const req = superagent.get(url) + .set('Cookie', this.cookie) + .set('User-Agent', userAgent); + if (this.account.proxy) return req.proxy(this.account.proxy); + return req; + } + + post(url: string) { + logger.debug('post', url, this.cookie); + if (!url.includes('//')) url = `${this.account.endpoint || 'https://cpc.csgrandeur.cn'}${url}`; + const req = superagent.post(url) + .set('Cookie', this.cookie) + .set('X-Requested-With', 'XMLHttpRequest') + .set('User-Agent', userAgent) + .type('form'); + if (this.account.proxy) return req.proxy(this.account.proxy); + return req; + } + + get loggedIn() { + return this.get('/').then(({ text: html }) => !html + .includes('