Skip to content

Commit 91e1db2

Browse files
committed
support fetch hydro
1 parent 50b1f5c commit 91e1db2

File tree

5 files changed

+113
-16
lines changed

5 files changed

+113
-16
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
"packages/*"
77
],
88
"scripts": {
9-
"start:client": "node -r ./register.js packages/server/index.ts --client --debug",
10-
"start:server": "node -r ./register.js packages/server/index.ts --debug",
9+
"dev:client": "node -r ./register.js packages/server/index.ts --client --debug",
10+
"dev:server": "node -r ./register.js packages/server/index.ts --debug",
1111
"lint": "eslint packages --ext js,ts,tsx,jsx",
12-
"build": "yarn build:ui:prod && node -r ./register.js build.ts",
12+
"build": "yarn build:ui && node -r ./register.js build.ts",
1313
"build:server": "node -r ./register.js build.ts",
14-
"build:pkg": "yarn build:ui:prod && node -r ./register.js build.ts && pkg dist/xcpc-tools.js --targets linux,macos,win --out-path dist/pkg"
14+
"build:pkg": "yarn build:ui && node -r ./register.js build.ts && pkg dist/xcpc-tools.js --targets linux,macos,win --out-path dist/pkg"
1515
},
1616
"devDependencies": {
1717
"@expo-google-fonts/noto-color-emoji": "^0.2.3",

packages/server/service/fetcher.ts

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { Context, Service } from 'cordis';
33
import superagent from 'superagent';
44
import { config } from '../config';
5-
import { Logger } from '../utils';
5+
import { Logger, mongoId } from '../utils';
66

77
const logger = new Logger('fetcher');
88
const fetch = (url: string, type: 'get' | 'post' = 'get') => superagent[type](new URL(url, config.server).toString())
@@ -11,10 +11,10 @@ export interface IBasicFetcher {
1111
contest: Record<string, any>
1212
cron(): Promise<void>
1313
contestInfo(): Promise<boolean>
14-
getToken?(username: string, password: string): Promise<void>
15-
teamInfo?(): Promise<void>
16-
balloonInfo?(all: boolean): Promise<void>
17-
setBalloonDone?(bid: string): Promise<void>
14+
getToken(username: string, password: string): Promise<void>
15+
teamInfo(): Promise<void>
16+
balloonInfo(all: boolean): Promise<void>
17+
setBalloonDone(bid: string): Promise<void>
1818
}
1919
class BasicFetcher extends Service implements IBasicFetcher {
2020
contest: any;
@@ -60,7 +60,7 @@ class BasicFetcher extends Service implements IBasicFetcher {
6060
}
6161
}
6262

63-
class DomJudgeFetcher extends BasicFetcher {
63+
class DOMjudgeFetcher extends BasicFetcher {
6464
async contestInfo() {
6565
let contest;
6666
if (!config.contestId) {
@@ -141,10 +141,96 @@ class DomJudgeFetcher extends BasicFetcher {
141141
}
142142
}
143143

144+
class HydroFetcher extends BasicFetcher {
145+
async contestInfo() {
146+
const ids = config.contestId.split('/');
147+
const [domainId, contestId] = ids.length === 2 ? ids : ['system', config.contestId];
148+
const { body } = await fetch(`/d/${domainId}/contest/${contestId}`);
149+
if (!body || !body.tdoc) {
150+
logger.error('Contest not found');
151+
return false;
152+
}
153+
const contest = body.tdoc;
154+
contest.freeze_time = contest.lockAt;
155+
const old = this?.contest?._id;
156+
this.contest = {
157+
info: contest, id: contest._id, name: contest.title, domainId,
158+
};
159+
logger.info(`Connected to ${contest.name}(id=${contest.id})`);
160+
return old === this.contest.id;
161+
}
162+
163+
async getToken(username, password) {
164+
const res = await fetch('/login', 'post').send({ uname: username, password, rememberme: 'on' })
165+
.redirects(0).ok((i) => i.status === 302);
166+
if (!res) throw new Error('Failed to get token');
167+
config.token = `Bearer ${res.header['set-cookie'][0].split(';')[0].split('=')[1]}`;
168+
}
169+
170+
async teamInfo() {
171+
const { body } = await fetch(`/d/${this.contest.domainId}/contest/${this.contest.id}/user`);
172+
if (!body || !body.length) return;
173+
const teams = body.tsdocs.filter((t) => body.udict[t.uid]).map((t) => (body.udict[t.uid]));
174+
for (const team of teams) {
175+
await this.ctx.db.teams.update({ id: team._id }, { $set: team }, { upsert: true });
176+
}
177+
logger.debug(`Found ${teams.length} teams`);
178+
}
179+
180+
async balloonInfo(all) {
181+
if (all) logger.info('Sync all balloons...');
182+
const { body } = await fetch(`/d/${this.contest.domainId}/contest/${this.contest.id}/balloon?todo=${all ? 'false' : 'true'}`);
183+
if (!body || !body.length) return;
184+
const balloons = body;
185+
for (const balloon of balloons) {
186+
const teamTotal = await this.ctx.db.balloon.find({ teamid: balloon.teamid, time: { $lt: (balloon.time * 1000).toFixed(0) } });
187+
const encourage = teamTotal.length < (config.freezeEncourage ?? 0);
188+
const totalDict = {};
189+
for (const t of teamTotal) {
190+
totalDict[t.problem] = t.contestproblem;
191+
}
192+
const shouldPrint = this.contest.info.freeze_time ? (balloon.time * 1000) < this.contest.info.freeze_time || encourage : true;
193+
if (!shouldPrint && !balloon.done) await this.setBalloonDone(balloon.balloonid);
194+
const contestproblem = {
195+
id: String.fromCharCode(this.contest.pids.indexOf(balloon.pid) + 65),
196+
name: body.pdict[balloon.pid].title,
197+
rgb: this.contest.balloon[balloon.pid].color,
198+
color: this.contest.balloon[balloon.pid].name,
199+
};
200+
await this.ctx.db.balloon.update({ balloonid: balloon.balloonid }, {
201+
$set: {
202+
balloonid: balloon._id,
203+
time: mongoId(balloon._id).timestamp,
204+
problem: contestproblem.id,
205+
contestproblem,
206+
team: body.udict[balloon.uid].displayName,
207+
teamid: balloon.uid,
208+
location: body.udict[balloon.uid].studentId,
209+
affiliation: body.udict[balloon.uid].school,
210+
awards: balloon.first ? 'First of Problem' : (
211+
this.contest.info.freeze_time && (balloon.time * 1000) > this.contest.info.freeze_time
212+
&& encourage ? 'Encourage Balloon' : ''
213+
),
214+
done: balloon.sent,
215+
total: totalDict,
216+
printDone: balloon.done ? 1 : 0,
217+
shouldPrint,
218+
},
219+
}, { upsert: true });
220+
}
221+
logger.debug(`Found ${balloons.length} balloons`);
222+
}
223+
224+
async setBalloonDone(bid) {
225+
await fetch(`/d/${this.contest.domainId}/contest/${this.contest.id}/balloon`, 'post').send({ balloon: bid });
226+
logger.debug(`Balloon ${bid} set done`);
227+
}
228+
}
229+
144230
const fetcherList = {
145231
server: BasicFetcher,
146-
domjudge: DomJudgeFetcher,
147-
hydro: BasicFetcher, // TODO: HydroFetcher
232+
domjudge: DOMjudgeFetcher,
233+
hydro: HydroFetcher,
148234
};
149235

150236
export async function apply(ctx) {

packages/server/utils/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ export function sleep(timeout: number) {
8484
});
8585
}
8686

87+
// https://github.com/andrasq/node-mongoid-js/blob/master/mongoid.js
88+
export function mongoId(idstring: string) {
89+
if (typeof idstring !== 'string') idstring = String(idstring);
90+
return {
91+
timestamp: parseInt(idstring.slice(0, 0 + 8), 16),
92+
machineid: parseInt(idstring.slice(8, 8 + 6), 16),
93+
pid: parseInt(idstring.slice(14, 14 + 4), 16),
94+
sequence: parseInt(idstring.slice(18, 18 + 6), 16),
95+
};
96+
}
97+
8798
export * as fs from 'fs-extra';
8899
export * as yaml from 'js-yaml';
89100
export { Logger };

packages/ui/build.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ logger.info('Building...');
101101
(async () => {
102102
if (dev) {
103103
const server = new WebpackDevServer({
104-
port: 8890,
104+
port: 8080,
105105
compress: true,
106106
hot: true,
107107
server: 'http',
108108
allowedHosts: 'all',
109109
proxy: {
110110
context: (p) => p !== '/ws',
111-
target: process.env.TOOLS_API || 'http://localhost:8889',
111+
target: process.env.TOOLS_API || 'http://localhost:5283',
112112
},
113113
client: {
114114
webSocketURL: 'auto://0.0.0.0:0/ws',

packages/ui/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"author": "panda",
55
"main": "index.ts",
66
"scripts": {
7-
"build:ui:dev": "node -r @hydrooj/register build.ts --watch --dev",
8-
"build:ui:prod": "node -r @hydrooj/register build.ts --production"
7+
"dev:ui": "node -r @hydrooj/register build.ts --watch --dev",
8+
"build:ui": "node -r @hydrooj/register build.ts --production"
99
},
1010
"preferUnplugged": true,
1111
"devDependencies": {

0 commit comments

Comments
 (0)