mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
vjudge: use BasicFetcher (#496)
This commit is contained in:
1 parent
eff22e1506
commit
3d3a5480e3
10 files changed
+118
-218
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
"name": "@hydrooj/vjudge",
|
"name": "@hydrooj/vjudge",
|
||||||
"version": "1.7.3",
|
"version": "1.7.3",
|
||||||
"description": "Submit problems to remote oj",
|
"description": "Submit problems to remote oj",
|
||||||
"main": "package.json",
|
"main": "src/model.ts",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
"author": "undefined",
|
"author": "undefined",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
@@ -10,12 +10,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hydrooj/utils": "workspace:*",
|
"@hydrooj/utils": "workspace:*",
|
||||||
"jsdom": "^21.0.0",
|
"jsdom": "^21.0.0",
|
||||||
"superagent": "^8.0.6",
|
|
||||||
"superagent-proxy": "^3.0.0"
|
"superagent-proxy": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jsdom": "^20.0.1",
|
"@types/jsdom": "^20.0.1",
|
||||||
"@types/superagent": "^4.1.16",
|
|
||||||
"@types/superagent-proxy": "^3.0.0"
|
"@types/superagent-proxy": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { DOMWindow, JSDOM } from 'jsdom';
|
||||||
|
import proxy from 'superagent-proxy';
|
||||||
|
import { Logger } from '@hydrooj/utils';
|
||||||
|
import { superagent } from 'hydrooj';
|
||||||
|
import { RemoteAccount } from './interface';
|
||||||
|
|
||||||
|
proxy(superagent);
|
||||||
|
|
||||||
|
interface FetchOptions {
|
||||||
|
headers?: { [key: string]: string };
|
||||||
|
post?: Omit<FetchOptions, 'get' | 'post'>
|
||||||
|
get?: Omit<FetchOptions, 'get' | 'post'>
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BasicFetcher {
|
||||||
|
cookie: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public account: RemoteAccount, private defaultEndpoint: string,
|
||||||
|
private formType: 'form' | 'json', public logger: Logger,
|
||||||
|
public fetchOptions: FetchOptions = {},
|
||||||
|
) {
|
||||||
|
if (account.cookie) this.cookie = account.cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(url: string) {
|
||||||
|
this.logger.debug('get', url);
|
||||||
|
url = new URL(url, this.account.endpoint || this.defaultEndpoint).toString();
|
||||||
|
let req = superagent.get(url).set('Cookie', this.cookie);
|
||||||
|
if (this.fetchOptions.headers) req = req.set(this.fetchOptions.headers);
|
||||||
|
if (this.fetchOptions.get?.headers) req = req.set(this.fetchOptions.get.headers);
|
||||||
|
return this.account.proxy ? req.proxy(this.account.proxy) : req;
|
||||||
|
}
|
||||||
|
|
||||||
|
async html(url: string) {
|
||||||
|
const { text: html } = await this.get(url);
|
||||||
|
const $dom = new JSDOM(html);
|
||||||
|
$dom.window.html = html;
|
||||||
|
return $dom.window as DOMWindow & { html: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
post(url: string) {
|
||||||
|
this.logger.debug('post', url, this.cookie);
|
||||||
|
url = new URL(url, this.account.endpoint || this.defaultEndpoint).toString();
|
||||||
|
let req = superagent.post(url).set('Cookie', this.cookie).type(this.formType);
|
||||||
|
if (this.fetchOptions.headers) req = req.set(this.fetchOptions.headers);
|
||||||
|
if (this.fetchOptions.post?.headers) req = req.set(this.fetchOptions.post.headers);
|
||||||
|
return this.account.proxy ? req.proxy(this.account.proxy) : req;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
ProblemModel, RecordModel, Service, sleep, STATUS, TaskModel, Time,
|
ProblemModel, RecordModel, Service, sleep, STATUS, TaskModel, Time,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
import { BasicProvider, IBasicProvider, RemoteAccount } from './interface';
|
import { BasicProvider, IBasicProvider, RemoteAccount } from './interface';
|
||||||
import { getDifficulty } from './providers/codeforces';
|
|
||||||
import providers from './providers/index';
|
import providers from './providers/index';
|
||||||
|
|
||||||
const coll = db.collection('vjudge');
|
const coll = db.collection('vjudge');
|
||||||
@@ -45,7 +44,10 @@ class AccountService {
|
|||||||
await next({ status: STATUS.STATUS_JUDGING, message: `ID = ${rid}` });
|
await next({ status: STATUS.STATUS_JUDGING, message: `ID = ${rid}` });
|
||||||
await this.api.waitForSubmission(rid, next, end);
|
await this.api.waitForSubmission(rid, next, end);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (process.env.DEV) logger.error(e);
|
if (process.env.DEV) {
|
||||||
|
logger.error(e);
|
||||||
|
if (e.response) console.error(e.response);
|
||||||
|
}
|
||||||
end({ status: STATUS.STATUS_SYSTEM_ERROR, message: e.message });
|
end({ status: STATUS.STATUS_SYSTEM_ERROR, message: e.message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,24 +125,11 @@ class AccountService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare module 'hydrooj' {
|
declare module 'hydrooj' {
|
||||||
interface Model {
|
|
||||||
vjudge: VJudgeModel;
|
|
||||||
}
|
|
||||||
interface Context {
|
interface Context {
|
||||||
vjudge: VJudgeService;
|
vjudge: VJudgeService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VJudgeModel {
|
|
||||||
static async fixCodeforcesDifficulty(domainId = 'codeforces') {
|
|
||||||
const pdocs = await ProblemModel.getMulti(domainId, {}).toArray();
|
|
||||||
for (const pdoc of pdocs) {
|
|
||||||
await ProblemModel.edit(domainId, pdoc.docId, { difficulty: getDifficulty(pdoc.tag) });
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VJudgeService extends Service {
|
class VJudgeService extends Service {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
super(ctx, 'vjudge', false);
|
super(ctx, 'vjudge', false);
|
||||||
@@ -153,8 +142,9 @@ class VJudgeService extends Service {
|
|||||||
this.accounts = await coll.find().toArray();
|
this.accounts = await coll.find().toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
addProvider(type: string, provider: BasicProvider) {
|
addProvider(type: string, provider: BasicProvider, override = false) {
|
||||||
if (this.providers[type]) throw new Error(`duplicate provider ${type}`);
|
if (process.env.VJUDGE_DEBUG && process.env.VJUDGE_DEBUG !== type) return;
|
||||||
|
if (!override && this.providers[type]) throw new Error(`duplicate provider ${type}`);
|
||||||
this.providers[type] = provider;
|
this.providers[type] = provider;
|
||||||
for (const account of this.accounts.filter((a) => a.type === type)) {
|
for (const account of this.accounts.filter((a) => a.type === type)) {
|
||||||
if (account.enableOn && !account.enableOn.includes(os.hostname())) continue;
|
if (account.enableOn && !account.enableOn.includes(os.hostname())) continue;
|
||||||
@@ -166,8 +156,6 @@ class VJudgeService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.model.vjudge = VJudgeModel;
|
|
||||||
|
|
||||||
Context.service('vjudge', VJudgeService);
|
Context.service('vjudge', VJudgeService);
|
||||||
export const name = 'vjudge';
|
export const name = 'vjudge';
|
||||||
export async function apply(ctx: Context) {
|
export async function apply(ctx: Context) {
|
||||||
|
|||||||
@@ -2,15 +2,13 @@
|
|||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import superagent from 'superagent';
|
|
||||||
import proxy from 'superagent-proxy';
|
|
||||||
import {
|
import {
|
||||||
buildContent, Logger, SettingModel, sleep, STATUS,
|
buildContent, Logger, SettingModel, sleep, STATUS,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
import { normalize, VERDICT } from '../verdict';
|
import { normalize, VERDICT } from '../verdict';
|
||||||
|
|
||||||
proxy(superagent);
|
|
||||||
const logger = new Logger('remote/codeforces');
|
const logger = new Logger('remote/codeforces');
|
||||||
|
|
||||||
function parseProblemId(id: string) {
|
function parseProblemId(id: string) {
|
||||||
@@ -61,31 +59,13 @@ ${lines.map((i) => i.innerHTML).join('\n').trim()}
|
|||||||
\n`;
|
\n`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class CodeforcesProvider implements IBasicProvider {
|
export default class CodeforcesProvider extends BasicFetcher implements IBasicProvider {
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
if (account.cookie) this.cookie = account.cookie;
|
super(account, 'https://codeforces.com', 'form', logger);
|
||||||
this.account.endpoint ||= 'https://codeforces.com';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie: string[] = [];
|
|
||||||
csrf: string;
|
csrf: string;
|
||||||
|
|
||||||
get(url: string) {
|
|
||||||
logger.debug('get', url);
|
|
||||||
if (!url.includes('//')) url = `${this.account.endpoint}${url}`;
|
|
||||||
const req = superagent.get(url).set('Cookie', this.cookie);
|
|
||||||
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}${url}`;
|
|
||||||
const req = superagent.post(url).type('form').set('Cookie', this.cookie);
|
|
||||||
if (this.account.proxy) return req.proxy(this.account.proxy);
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCookie(target: string) {
|
getCookie(target: string) {
|
||||||
return this.cookie.find((i) => i.startsWith(`${target}=`))?.split('=')[1]?.split(';')[0];
|
return this.cookie.find((i) => i.startsWith(`${target}=`))?.split('=')[1]?.split(';')[0];
|
||||||
}
|
}
|
||||||
@@ -103,8 +83,7 @@ export default class CodeforcesProvider implements IBasicProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getCsrfToken(url: string) {
|
async getCsrfToken(url: string) {
|
||||||
const { text: html } = await this.get(url);
|
const { document, html } = await this.html(url);
|
||||||
const { window: { document } } = new JSDOM(html);
|
|
||||||
if (document.body.children.length < 2 && html.length < 512) {
|
if (document.body.children.length < 2 && html.length < 512) {
|
||||||
throw new Error(document.body.textContent);
|
throw new Error(document.body.textContent);
|
||||||
}
|
}
|
||||||
@@ -261,13 +240,12 @@ export default class CodeforcesProvider implements IBasicProvider {
|
|||||||
if (resync && page > 1) return [];
|
if (resync && page > 1) return [];
|
||||||
if (resync && listName.startsWith('GYM')) return [];
|
if (resync && listName.startsWith('GYM')) return [];
|
||||||
if (listName.startsWith('GYM') && page > 1) return [];
|
if (listName.startsWith('GYM') && page > 1) return [];
|
||||||
const res = await this.get(listName === 'main'
|
const { document } = await this.html(listName === 'main'
|
||||||
? `/problemset/page/${page}`
|
? `/problemset/page/${page}`
|
||||||
: listName === 'gym'
|
: listName === 'gym'
|
||||||
? `/gyms/page/${page}`
|
? `/gyms/page/${page}`
|
||||||
: `/gym/${listName.split('GYM')[1]}`,
|
: `/gym/${listName.split('GYM')[1]}`,
|
||||||
);
|
);
|
||||||
const { window: { document } } = new JSDOM(res.text);
|
|
||||||
if (['gym', 'main'].includes(listName)) {
|
if (['gym', 'main'].includes(listName)) {
|
||||||
const index = document.querySelector('.page-index.active').getAttribute('pageindex');
|
const index = document.querySelector('.page-index.active').getAttribute('pageindex');
|
||||||
if (index !== page.toString()) return [];
|
if (index !== page.toString()) return [];
|
||||||
@@ -330,10 +308,9 @@ export default class CodeforcesProvider implements IBasicProvider {
|
|||||||
end({ status: STATUS.STATUS_COMPILE_ERROR, message });
|
end({ status: STATUS.STATUS_COMPILE_ERROR, message });
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { text: status } = await this.get(type !== 'GYM'
|
const { document } = await this.html(type !== 'GYM'
|
||||||
? '/problemset/status?my=on'
|
? '/problemset/status?my=on'
|
||||||
: `/gym/${contestId}/my`);
|
: `/gym/${contestId}/my`);
|
||||||
const { window: { document } } = new JSDOM(status);
|
|
||||||
this.csrf = document.querySelector('meta[name="X-Csrf-Token"]').getAttribute('content');
|
this.csrf = document.querySelector('meta[name="X-Csrf-Token"]').getAttribute('content');
|
||||||
return document.querySelector('[data-submission-id]').getAttribute('data-submission-id');
|
return document.querySelector('[data-submission-id]').getAttribute('data-submission-id');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import * as superagent from 'superagent';
|
|
||||||
import proxy from 'superagent-proxy';
|
|
||||||
import { Logger, sleep, STATUS } from 'hydrooj';
|
import { Logger, sleep, STATUS } from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
|
|
||||||
proxy(superagent as any);
|
|
||||||
const logger = new Logger('remote/csgoj');
|
const logger = new Logger('remote/csgoj');
|
||||||
const statusDict = {
|
const statusDict = {
|
||||||
0: STATUS.STATUS_COMPILING,
|
0: STATUS.STATUS_COMPILING,
|
||||||
@@ -53,35 +51,15 @@ csgoj.3:
|
|||||||
|
|
||||||
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0';
|
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 {
|
export default class CSGOJProvider extends BasicFetcher implements IBasicProvider {
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
|
super(account, 'https://cpc.csgrandeur.cn', 'form', logger, {
|
||||||
|
headers: { 'User-Agent': userAgent },
|
||||||
|
post: { headers: { 'X-Requested-With': 'XMLHttpRequest' } },
|
||||||
|
});
|
||||||
if (account.cookie) this.cookie = account.cookie;
|
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() {
|
get loggedIn() {
|
||||||
return this.get('/').then(({ text: html }) => !html
|
return this.get('/').then(({ text: html }) => !html
|
||||||
.includes('<form id="login_form" class="form-signin" method="post" action="/csgoj/user/login_ajax">'));
|
.includes('<form id="login_form" class="form-signin" method="post" action="/csgoj/user/login_ajax">'));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defaultsDeep } from 'lodash';
|
|
||||||
import {
|
import {
|
||||||
SettingModel, sleep, STATUS, superagent,
|
_, Logger, SettingModel, sleep, STATUS,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
import { VERDICT } from '../verdict';
|
import { VERDICT } from '../verdict';
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ import { VERDICT } from '../verdict';
|
|||||||
|
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36';
|
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36';
|
||||||
|
const logger = new Logger('vjudge/hustoj');
|
||||||
|
|
||||||
interface HustOJRemoteConfig {
|
interface HustOJRemoteConfig {
|
||||||
login?: {
|
login?: {
|
||||||
@@ -83,33 +84,30 @@ function isProcessing(t: string) {
|
|||||||
return [STATUS.STATUS_WAITING, STATUS.STATUS_COMPILING, STATUS.STATUS_JUDGING].includes(VERDICT[t]);
|
return [STATUS.STATUS_WAITING, STATUS.STATUS_COMPILING, STATUS.STATUS_JUDGING].includes(VERDICT[t]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HUSTOJ implements IBasicProvider {
|
export class HUSTOJ extends BasicFetcher implements IBasicProvider {
|
||||||
cookie: string[] = [];
|
config: HustOJRemoteConfig;
|
||||||
config = { ...defaultConfig };
|
|
||||||
state = {
|
state = {
|
||||||
username: '',
|
username: '',
|
||||||
pid: '',
|
pid: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
defaultsDeep(this.config, account);
|
const config = _.defaultsDeep({ ...defaultConfig }, account);
|
||||||
|
super(account, '', 'form', logger, {
|
||||||
|
post: {
|
||||||
|
headers: {
|
||||||
|
Referer: config.server,
|
||||||
|
'User-Agent': UA,
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.config = config;
|
||||||
this.updateConfig();
|
this.updateConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateConfig() { }
|
updateConfig() { }
|
||||||
|
|
||||||
get(url: string) {
|
|
||||||
return superagent.get(url).set('Cookie', this.cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
post(url: string, data: Record<string, any>) {
|
|
||||||
return superagent.post(url)
|
|
||||||
.set('Cookie', this.cookie).send(data).type('form')
|
|
||||||
.set('Referer', this.config.server)
|
|
||||||
.set('User-Agent', UA)
|
|
||||||
.set('Accept', 'application/json');
|
|
||||||
}
|
|
||||||
|
|
||||||
getProblem() {
|
getProblem() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -120,7 +118,7 @@ export class HUSTOJ implements IBasicProvider {
|
|||||||
|
|
||||||
async login(username: string, password: string) {
|
async login(username: string, password: string) {
|
||||||
this.cookie = [];
|
this.cookie = [];
|
||||||
const res = await this.post(this.config.login[0], {
|
const res = await this.post(this.config.login[0]).send({
|
||||||
[this.config.login.usernameField]: username,
|
[this.config.login.usernameField]: username,
|
||||||
[this.config.login.passwordField]: password,
|
[this.config.login.passwordField]: password,
|
||||||
...this.config.login.extra,
|
...this.config.login.extra,
|
||||||
@@ -143,7 +141,7 @@ export class HUSTOJ implements IBasicProvider {
|
|||||||
if (typeof comment === 'string') code = `${comment} ${msg}\n${code}`;
|
if (typeof comment === 'string') code = `${comment} ${msg}\n${code}`;
|
||||||
else if (comment instanceof Array) code = `${comment[0]} ${msg} ${comment[1]}\n${code}`;
|
else if (comment instanceof Array) code = `${comment[0]} ${msg} ${comment[1]}\n${code}`;
|
||||||
}
|
}
|
||||||
const res = await this.post(this.config.submit.endpoint, {
|
const res = await this.post(this.config.submit.endpoint).send({
|
||||||
[this.config.submit.idField]: id,
|
[this.config.submit.idField]: id,
|
||||||
[this.config.submit.langField]: langId,
|
[this.config.submit.langField]: langId,
|
||||||
[this.config.submit.codeField]: code,
|
[this.config.submit.codeField]: code,
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { JSDOM } from 'jsdom';
|
|
||||||
import superagent from 'superagent';
|
|
||||||
import proxy from 'superagent-proxy';
|
|
||||||
import {
|
import {
|
||||||
_, Logger, SettingModel, sleep, STATUS,
|
_, Logger, SettingModel, sleep, STATUS,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
|
|
||||||
proxy(superagent);
|
|
||||||
const logger = new Logger('remote/luogu');
|
const logger = new Logger('remote/luogu');
|
||||||
|
|
||||||
const STATUS_MAP = [
|
const STATUS_MAP = [
|
||||||
@@ -33,43 +30,24 @@ const UA = [
|
|||||||
`Vjudge/${global.Hydro.version.vjudge}`,
|
`Vjudge/${global.Hydro.version.vjudge}`,
|
||||||
].join(' ');
|
].join(' ');
|
||||||
|
|
||||||
export default class LuoguProvider implements IBasicProvider {
|
export default class LuoguProvider extends BasicFetcher implements IBasicProvider {
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
if (account.cookie) this.cookie = account.cookie;
|
super(account, 'https://www.luogu.com.cn', 'json', logger, {
|
||||||
|
headers: { 'User-Agent': UA },
|
||||||
|
post: {
|
||||||
|
headers: {
|
||||||
|
'x-requested-with': 'XMLHttpRequest',
|
||||||
|
origin: 'https://www.luogu.com.cn',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
setInterval(() => this.getCsrfToken('/user/setting'), 5 * 60 * 1000);
|
setInterval(() => this.getCsrfToken('/user/setting'), 5 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie: string[] = [];
|
|
||||||
csrf: string;
|
|
||||||
|
|
||||||
get(url: string) {
|
|
||||||
logger.debug('get', url);
|
|
||||||
if (!url.includes('//')) url = `${this.account.endpoint || 'https://www.luogu.com.cn'}${url}`;
|
|
||||||
const req = superagent.get(url)
|
|
||||||
.set('Cookie', this.cookie)
|
|
||||||
.set('User-Agent', UA);
|
|
||||||
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://www.luogu.com.cn'}${url}`;
|
|
||||||
const req = superagent.post(url)
|
|
||||||
.set('Cookie', this.cookie)
|
|
||||||
.set('x-csrf-token', this.csrf)
|
|
||||||
.set('User-Agent', UA)
|
|
||||||
.set('x-requested-with', 'XMLHttpRequest')
|
|
||||||
.set('origin', 'https://www.luogu.com.cn');
|
|
||||||
if (this.account.proxy) return req.proxy(this.account.proxy);
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCsrfToken(url: string) {
|
async getCsrfToken(url: string) {
|
||||||
const { text: html } = await this.get(url);
|
const csrf = (await this.html(url)).document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||||
const $dom = new JSDOM(html);
|
logger.info('csrf-token=', csrf);
|
||||||
this.csrf = $dom.window.document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
// this.fetchOptions.post.headers['x-csrf-token'] = csrf;
|
||||||
logger.info('csrf-token=', this.csrf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get loggedIn() {
|
get loggedIn() {
|
||||||
@@ -86,14 +64,8 @@ export default class LuoguProvider implements IBasicProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProblem(id: string) {
|
async getProblem() {
|
||||||
return {
|
return null;
|
||||||
title: id,
|
|
||||||
data: {},
|
|
||||||
files: {},
|
|
||||||
tag: [],
|
|
||||||
content: '',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async listProblem() {
|
async listProblem() {
|
||||||
@@ -109,6 +81,7 @@ export default class LuoguProvider implements IBasicProvider {
|
|||||||
}
|
}
|
||||||
if (!lang.startsWith('luogu.')) {
|
if (!lang.startsWith('luogu.')) {
|
||||||
end({ status: STATUS.STATUS_COMPILE_ERROR, message: `Language not supported: ${lang}` });
|
end({ status: STATUS.STATUS_COMPILE_ERROR, message: `Language not supported: ${lang}` });
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
if (comment) {
|
if (comment) {
|
||||||
const msg = `Hydro submission #${info.rid}@${new Date().toLocaleString()}`;
|
const msg = `Hydro submission #${info.rid}@${new Date().toLocaleString()}`;
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import * as superagent from 'superagent';
|
|
||||||
import proxy from 'superagent-proxy';
|
|
||||||
import {
|
import {
|
||||||
htmlEncode, Logger, parseMemoryMB, parseTimeMS, SettingModel, sleep, STATUS,
|
htmlEncode, Logger, parseMemoryMB, parseTimeMS, SettingModel, sleep, STATUS,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
import { VERDICT } from '../verdict';
|
import { VERDICT } from '../verdict';
|
||||||
|
|
||||||
proxy(superagent as any);
|
|
||||||
const logger = new Logger('remote/poj');
|
const logger = new Logger('remote/poj');
|
||||||
|
|
||||||
/* langs
|
/* langs
|
||||||
@@ -59,27 +57,9 @@ const langs = {
|
|||||||
'zh-CN': 'zh',
|
'zh-CN': 'zh',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class POJProvider implements IBasicProvider {
|
export default class POJProvider extends BasicFetcher implements IBasicProvider {
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
if (account.cookie) this.cookie = account.cookie;
|
super(account, 'http://poj.org', 'form', logger);
|
||||||
}
|
|
||||||
|
|
||||||
cookie: string[] = [];
|
|
||||||
|
|
||||||
get(url: string) {
|
|
||||||
logger.debug('get', url);
|
|
||||||
if (!url.startsWith('http')) url = new URL(url, this.account.endpoint || 'http://poj.org').toString();
|
|
||||||
const req = superagent.get(url).set('Cookie', this.cookie);
|
|
||||||
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 || 'http://poj.org'}${url}`;
|
|
||||||
const req = superagent.post(url).set('Cookie', this.cookie).type('form');
|
|
||||||
if (this.account.proxy) return req.proxy(this.account.proxy);
|
|
||||||
return req;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCsrfToken(url: string) {
|
async getCsrfToken(url: string) {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import superagent from 'superagent';
|
|
||||||
import proxy from 'superagent-proxy';
|
|
||||||
import {
|
import {
|
||||||
Logger, parseMemoryMB, SettingModel, sleep, STATUS,
|
Logger, parseMemoryMB, SettingModel, sleep, STATUS,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
|
|
||||||
proxy(superagent);
|
|
||||||
const logger = new Logger('spoj');
|
const logger = new Logger('spoj');
|
||||||
|
|
||||||
const VERDICT = {
|
const VERDICT = {
|
||||||
@@ -19,27 +17,9 @@ const VERDICT = {
|
|||||||
15: STATUS.STATUS_ACCEPTED,
|
15: STATUS.STATUS_ACCEPTED,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SPOJProvider implements IBasicProvider {
|
export default class SPOJProvider extends BasicFetcher implements IBasicProvider {
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
if (account.cookie) this.cookie = account.cookie;
|
super(account, 'https://www.spoj.com', 'form', logger);
|
||||||
}
|
|
||||||
|
|
||||||
cookie: string[] = [];
|
|
||||||
|
|
||||||
get(url: string) {
|
|
||||||
logger.debug('get', url);
|
|
||||||
if (!url.includes('//')) url = `${this.account.endpoint || 'https://www.spoj.com'}${url}`;
|
|
||||||
const req = superagent.get(url).set('Cookie', this.cookie);
|
|
||||||
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://www.spoj.com'}${url}`;
|
|
||||||
const req = superagent.post(url).type('form').set('Cookie', this.cookie);
|
|
||||||
if (this.account.proxy) return req.proxy(this.account.proxy);
|
|
||||||
return req;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get loggedIn() {
|
get loggedIn() {
|
||||||
@@ -70,8 +50,7 @@ export default class SPOJProvider implements IBasicProvider {
|
|||||||
|
|
||||||
async getProblem(id: string) {
|
async getProblem(id: string) {
|
||||||
logger.info(id);
|
logger.info(id);
|
||||||
const { text } = await this.get(`/problems/${id}/`);
|
const { document } = await this.html(`/problems/${id}/`);
|
||||||
const { window: { document } } = new JSDOM(text);
|
|
||||||
const files = {};
|
const files = {};
|
||||||
document.querySelector('#problem-body').querySelectorAll('img[src]').forEach((ele) => {
|
document.querySelector('#problem-body').querySelectorAll('img[src]').forEach((ele) => {
|
||||||
const src = ele.getAttribute('src');
|
const src = ele.getAttribute('src');
|
||||||
@@ -83,9 +62,8 @@ export default class SPOJProvider implements IBasicProvider {
|
|||||||
ele.setAttribute('src', `file://${fid}.png`);
|
ele.setAttribute('src', `file://${fid}.png`);
|
||||||
});
|
});
|
||||||
const meta = document.querySelector('#problem-meta').children[1];
|
const meta = document.querySelector('#problem-meta').children[1];
|
||||||
const { text: submit } = await this.get(`/submit/${id}/`);
|
const window = await this.html(`/submit/${id}/`);
|
||||||
const $dom = new JSDOM(submit);
|
const langs = Array.from(window.document.querySelector('#lang').querySelectorAll('option'))
|
||||||
const langs = Array.from($dom.window.document.querySelector('#lang').querySelectorAll('option'))
|
|
||||||
.map((i) => `spoj.${i.getAttribute('value')}`);
|
.map((i) => `spoj.${i.getAttribute('value')}`);
|
||||||
let time = meta.children[2].children[1].innerHTML.trim().toLowerCase();
|
let time = meta.children[2].children[1].innerHTML.trim().toLowerCase();
|
||||||
if (time.includes('-')) time = time.split('-')[1];
|
if (time.includes('-')) time = time.split('-')[1];
|
||||||
@@ -109,8 +87,7 @@ langs: ${JSON.stringify(langs)}`),
|
|||||||
|
|
||||||
async listProblem(page: number, resync = false) {
|
async listProblem(page: number, resync = false) {
|
||||||
if (resync) return [];
|
if (resync) return [];
|
||||||
const res = await this.get(`/problems/classical/sort=0,start=${page * 50 - 50}`);
|
const { document } = await this.html(`/problems/classical/sort=0,start=${page * 50 - 50}`);
|
||||||
const { window: { document } } = new JSDOM(res.text);
|
|
||||||
const index = document.querySelector('ul.pagination').querySelector('li.active').children[0].innerHTML.trim();
|
const index = document.querySelector('ul.pagination').querySelector('li.active').children[0].innerHTML.trim();
|
||||||
if (index !== page.toString()) return [];
|
if (index !== page.toString()) return [];
|
||||||
return Array.from(document.querySelectorAll('td[align=left]')).map((i) => i.children[0].getAttribute('href').split('/problems/')[1]);
|
return Array.from(document.querySelectorAll('td[align=left]')).map((i) => i.children[0].getAttribute('href').split('/problems/')[1]);
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import * as superagent from 'superagent';
|
|
||||||
import proxy from 'superagent-proxy';
|
|
||||||
import {
|
import {
|
||||||
Logger, parseMemoryMB, parseTimeMS, SettingModel, sleep, STATUS,
|
Logger, parseMemoryMB, parseTimeMS, SettingModel, sleep, STATUS,
|
||||||
} from 'hydrooj';
|
} from 'hydrooj';
|
||||||
|
import { BasicFetcher } from '../fetch';
|
||||||
import { IBasicProvider, RemoteAccount } from '../interface';
|
import { IBasicProvider, RemoteAccount } from '../interface';
|
||||||
import { VERDICT } from '../verdict';
|
import { VERDICT } from '../verdict';
|
||||||
|
|
||||||
proxy(superagent as any);
|
|
||||||
const logger = new Logger('remote/uoj');
|
const logger = new Logger('remote/uoj');
|
||||||
const MAPPING = {
|
const MAPPING = {
|
||||||
一: 1,
|
一: 1,
|
||||||
@@ -24,30 +22,13 @@ const MAPPING = {
|
|||||||
十: 10,
|
十: 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class UOJProvider implements IBasicProvider {
|
export default class UOJProvider extends BasicFetcher implements IBasicProvider {
|
||||||
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
constructor(public account: RemoteAccount, private save: (data: any) => Promise<void>) {
|
||||||
if (account.cookie) this.cookie = account.cookie;
|
super(account, 'https://uoj.ac', 'form', logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie: string[] = [];
|
|
||||||
csrf: string;
|
csrf: string;
|
||||||
|
|
||||||
get(url: string) {
|
|
||||||
logger.debug('get', url);
|
|
||||||
if (!url.includes('//')) url = `${this.account.endpoint || 'https://uoj.ac'}${url}`;
|
|
||||||
const req = superagent.get(url).set('Cookie', this.cookie);
|
|
||||||
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://uoj.ac'}${url}`;
|
|
||||||
const req = superagent.post(url).set('Cookie', this.cookie).type('form');
|
|
||||||
if (this.account.proxy) return req.proxy(this.account.proxy);
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCsrfToken(url: string) {
|
async getCsrfToken(url: string) {
|
||||||
const { text: html, header } = await this.get(url);
|
const { text: html, header } = await this.get(url);
|
||||||
if (header['set-cookie']) {
|
if (header['set-cookie']) {
|
||||||
|
|||||||
Reference in new issue
Block a user