diff --git a/remote_judger/src/daemon.ts b/remote_judger/src/daemon.ts
index 0e88968..bfa52c5 100644
--- a/remote_judger/src/daemon.ts
+++ b/remote_judger/src/daemon.ts
@@ -7,6 +7,7 @@ import * as TIME from './utils/time';
import { apply } from './vjudge';
import path from 'path';
import child from 'child_process';
+import htmlspecialchars from './utils/htmlspecialchars';
proxy(superagent);
@@ -146,7 +147,8 @@ export default async function daemon(config: UOJConfig) {
config.remote_problem_id,
config.answer_language,
code,
- judge_time
+ judge_time,
+ config
);
} catch (err) {
await request('/submit', {
@@ -157,7 +159,7 @@ export default async function daemon(config: UOJConfig) {
status: 'Judged',
score: 0,
error: 'Judgment Failed',
- details: `No details.`,
+ details: `${htmlspecialchars(err.message)}`,
}),
judge_time,
});
diff --git a/remote_judger/src/providers/atcoder.ts b/remote_judger/src/providers/atcoder.ts
index f96bde7..757de3a 100644
--- a/remote_judger/src/providers/atcoder.ts
+++ b/remote_judger/src/providers/atcoder.ts
@@ -73,6 +73,10 @@ export default class AtcoderProvider implements IBasicProvider {
this.account.endpoint ||= 'https://atcoder.jp';
}
+ static constructFromAccountData(data) {
+ throw new Error('Method not implemented.');
+ }
+
cookie: string[] = ['language=en'];
csrf: string;
diff --git a/remote_judger/src/providers/codeforces.ts b/remote_judger/src/providers/codeforces.ts
index 1131c4b..76eb301 100644
--- a/remote_judger/src/providers/codeforces.ts
+++ b/remote_judger/src/providers/codeforces.ts
@@ -87,6 +87,10 @@ export default class CodeforcesProvider implements IBasicProvider {
this.account.endpoint ||= 'https://codeforces.com';
}
+ static constructFromAccountData(data) {
+ throw new Error('Method not implemented.');
+ }
+
cookie: string[] = [];
csrf: string;
diff --git a/remote_judger/src/providers/loj.ts b/remote_judger/src/providers/loj.ts
index cd79213..793b319 100644
--- a/remote_judger/src/providers/loj.ts
+++ b/remote_judger/src/providers/loj.ts
@@ -156,6 +156,10 @@ export default class LibreojProvider implements IBasicProvider {
this.account.endpoint ||= 'https://api.loj.ac.cn/api';
}
+ static constructFromAccountData(data) {
+ throw new Error('Method not implemented.');
+ }
+
get(url: string) {
logger.debug('get', url);
if (!url.includes('//')) url = `${this.account.endpoint}${url}`;
diff --git a/remote_judger/src/providers/uoj.ts b/remote_judger/src/providers/uoj.ts
index eafe22b..a7ae179 100644
--- a/remote_judger/src/providers/uoj.ts
+++ b/remote_judger/src/providers/uoj.ts
@@ -99,6 +99,10 @@ export default class UOJProvider implements IBasicProvider {
if (account.cookie) this.cookie = account.cookie;
}
+ static constructFromAccountData(data) {
+ throw new Error('Method not implemented.');
+ }
+
cookie: string[] = [];
csrf: string;
diff --git a/remote_judger/src/vjudge.ts b/remote_judger/src/vjudge.ts
index 20aab01..dda6303 100644
--- a/remote_judger/src/vjudge.ts
+++ b/remote_judger/src/vjudge.ts
@@ -8,11 +8,7 @@ const logger = new Logger('vjudge');
class AccountService {
api: IBasicProvider;
- constructor(
- public Provider: BasicProvider,
- public account: RemoteAccount,
- private request: any
- ) {
+ constructor(public Provider: BasicProvider, public account: RemoteAccount) {
this.api = new Provider(account);
this.main().catch(e =>
logger.error(`Error occured in ${account.type}/${account.handle}`, e)
@@ -24,7 +20,81 @@ class AccountService {
problem_id: string,
language: string,
code: string,
- judge_time: string
+ next,
+ end
+ ) {
+ try {
+ const rid = await this.api.submitProblem(
+ problem_id,
+ language,
+ code,
+ id,
+ next,
+ end
+ );
+
+ if (!rid) return;
+
+ await this.api.waitForSubmission(problem_id, rid, next, end);
+ } catch (e) {
+ logger.error(e);
+
+ await end({ error: true, status: 'Judgment Failed', message: e.message });
+ }
+ }
+
+ async login() {
+ const login = await this.api.ensureLogin();
+ if (login === true) {
+ logger.info(`${this.account.type}/${this.account.handle}: logged in`);
+ return true;
+ }
+ logger.warn(
+ `${this.account.type}/${this.account.handle}: login fail`,
+ login || ''
+ );
+ return false;
+ }
+
+ async main() {
+ const res = await this.login();
+ if (!res) return;
+ setInterval(() => this.login(), Time.hour);
+ }
+}
+
+class VJudge {
+ private p_imports: Record = {};
+ private providers: Record = {};
+
+ constructor(private request: any) {}
+
+ async importProvider(type: string) {
+ if (this.p_imports[type]) throw new Error(`duplicate provider ${type}`);
+ const provider = await import(`./providers/${type}`);
+
+ this.p_imports[type] = provider.default;
+ }
+
+ async addProvider(type: string) {
+ if (this.p_imports[type]) throw new Error(`duplicate provider ${type}`);
+ const provider = await import(`./providers/${type}`);
+ const account = provider.getAccountInfoFromEnv();
+
+ if (!account) throw new Error(`no account info for ${type}`);
+
+ this.p_imports[type] = provider.default;
+ this.providers[type] = new AccountService(provider.default, account);
+ }
+
+ async judge(
+ id: number,
+ type: string,
+ problem_id: string,
+ language: string,
+ code: string,
+ judge_time: string,
+ config
) {
const next = async payload => {
return await this.request('/submit', {
@@ -77,75 +147,51 @@ class AccountService {
});
};
- try {
- const rid = await this.api.submitProblem(
+ if (!config.remote_submit_type || config.remote_submit_type == 'bot') {
+ if (!this.providers[type]) throw new Error(`No provider ${type}`);
+
+ await this.providers[type].judge(
+ id,
problem_id,
language,
code,
- id,
next,
end
);
+ } else if (config.remote_submit_type == 'my') {
+ if (!this.p_imports[type]) throw new Error(`No provider ${type}`);
- if (!rid) return;
+ try {
+ const provider = this.p_imports[type].constructFromAccountData(
+ JSON.parse(config.remote_account_data)
+ );
- await this.api.waitForSubmission(problem_id, rid, next, end);
- } catch (e) {
- logger.error(e);
- await end({ error: true, status: 'Judgment Failed', message: e.message });
+ const rid = await provider.submitProblem(
+ problem_id,
+ language,
+ code,
+ id,
+ next,
+ end
+ );
+
+ if (!rid) return;
+
+ await provider.waitForSubmission(problem_id, rid, next, end);
+ } catch (e) {
+ logger.error(e);
+
+ await end({
+ error: true,
+ status: 'Judgment Failed',
+ message: e.message,
+ });
+ }
}
- }
- async login() {
- const login = await this.api.ensureLogin();
- if (login === true) {
- logger.info(`${this.account.type}/${this.account.handle}: logged in`);
- return true;
- }
- logger.warn(
- `${this.account.type}/${this.account.handle}: login fail`,
- login || ''
+ throw new Error(
+ 'Unsupported remote submit type: ' + config.remote_submit_type
);
- return false;
- }
-
- async main() {
- const res = await this.login();
- if (!res) return;
- setInterval(() => this.login(), Time.hour);
- }
-}
-
-class VJudge {
- private providers: Record = {};
-
- constructor(private request: any) {}
-
- async addProvider(type: string) {
- if (this.providers[type]) throw new Error(`duplicate provider ${type}`);
- const provider = await import(`./providers/${type}`);
- const account = provider.getAccountInfoFromEnv();
-
- if (!account) throw new Error(`no account info for ${type}`);
-
- this.providers[type] = new AccountService(
- provider.default,
- account,
- this.request
- );
- }
-
- async judge(
- id: number,
- type: string,
- problem_id: string,
- language: string,
- code: string,
- judge_time: string
- ) {
- if (!this.providers[type]) throw new Error(`no provider ${type}`);
-
- await this.providers[type].judge(id, problem_id, language, code, judge_time);
}
}