Skip to content

Commit 1d9ca71

Browse files
committed
replaced datatable with Simple-DataTables (written in vanilla Js) and some minor fixes
1 parent 0fe2bcc commit 1d9ca71

File tree

12 files changed

+326
-251
lines changed

12 files changed

+326
-251
lines changed

controllers/rankingsController.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ exports.search = async function (req, res) {
7575
page: 1,
7676
totalPages: 1,
7777
searchResult: true,
78-
title: `Search | ${_id} | Leetcode Rating Predictor`,
78+
title: `Search | ${req.params.contestSlug} | Leetcode Rating Predictor`,
7979
});
80-
} catch (error) {
80+
} catch (err) {
8181
console.error(err);
8282
res.sendStatus(500);
8383
}

main.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if (process.env.WEB == true) {
3333
app.set("view engine", "ejs");
3434
app.set("views", __dirname + "/views");
3535
app.set("layout", "layouts/layout");
36+
app.set("layout extractScripts", true);
3637
app.use(expressLayouts);
3738
app.use(bodyParser.urlencoded({ extended: true }));
3839
app.use(express.static("public"));

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
},
88
"main": "server.js",
99
"scripts": {
10-
"start": "node main.js --max_old_space_size=1024",
11-
"dev": "nodemon --max_old_space_size=1024 --trace-warnings main.js",
10+
"start": "node main.js --max_old_space_size=1024 --trace-warnings",
11+
"dev": "nodemon --max_old_space_size=1024 --trace-warnings main.js",
1212
"buildAddon": "npm run build --prefix ./services/predict-addon/"
1313
},
1414
"keywords": [],

public/stylesheets/main.css

+36-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
body{
2-
color:#333;
1+
body {
2+
margin: 0;
3+
color: rgba(0, 0, 0, 0.65);
4+
font-size: 14px;
5+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
6+
font-variant: tabular-nums;
7+
line-height: 1.5;
8+
background-color: #fff;
9+
-webkit-font-feature-settings: 'tnum';
10+
font-feature-settings: 'tnum';
311
}
412

513
#forkMe {
@@ -11,17 +19,18 @@ body{
1119
text-align: center;
1220
text-decoration: none;
1321
letter-spacing: .06em;
14-
background-color: #455a64;
22+
background-color: #1890ff;
1523
padding: 0.5em 5em 0.4em 5em;
1624
text-shadow: 0 0 0.75em #444;
17-
box-shadow: 0 0 0.5em rgba(0,0,0,0.5);
18-
transform: rotate(45deg) scale(0.75,1);
25+
box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.5);
26+
transform: rotate(45deg) scale(0.75, 1);
1927
font: bold 16px/1.2em Arial, Sans-Serif;
2028
-webkit-text-shadow: 0 0 0.75em #444;
21-
-webkit-box-shadow: 0 0 0.5em rgba(0,0,0,0.5);
22-
-webkit-transform: rotate(45deg) scale(0.75,1);
23-
z-index:10;
29+
-webkit-box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.5);
30+
-webkit-transform: rotate(45deg) scale(0.75, 1);
31+
z-index: 10;
2432
}
33+
2534
#forkMe:before {
2635
content: '';
2736
top: 0;
@@ -32,9 +41,18 @@ body{
3241
margin: -0.3em -5em;
3342
transform: scale(0.7);
3443
-webkit-transform: scale(0.7);
35-
border: 2px rgba(255,255,255,0.7) dashed;
44+
border: 2px rgba(255, 255, 255, 0.7) dashed;
45+
}
46+
47+
@media only screen and (max-width: 600px) {
48+
#forkMe {
49+
font-size: small;
50+
}
51+
}
52+
53+
#forkMe:hover {
54+
opacity: 0.9;
3655
}
37-
#forkMe:hover {opacity: 0.9;}
3856

3957
a {
4058
color: #1890ff;
@@ -47,16 +65,20 @@ a {
4765
transition: color 0.3s;
4866
-webkit-text-decoration-skip: objects;
4967
}
50-
.btn-primary{
68+
69+
.btn-primary {
5170
background-color: #337ab7 !important;
5271
border-color: #337ab7 !important;
53-
color:white !important;
72+
color: white !important;
5473
}
55-
.bg-primary{
74+
75+
.bg-primary {
5676
background-color: #337ab7 !important;
5777
color: white !important;
5878
}
59-
.btn-primary:focus, .btn-primary:active {
79+
80+
.btn-primary:focus,
81+
.btn-primary:active {
6082
background-color: #337ab7 !important;
6183
border-color: #337ab7 !important;
6284
box-shadow: 0 0 0 0.25rem rgb(102 151 193) !important;

public/stylesheets/tablestyle.css

+37-34
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,52 @@
44
white-space: nowrap;
55
overflow: hidden;
66
}
7-
7+
88
.card {
99
border-radius: .5rem;
1010
}
11-
11+
1212
.table-scroll {
1313
border-radius: .5rem;
1414
}
15-
15+
1616
.table-scroll table thead th {
1717
font-size: 1.25rem;
1818
}
19-
.pagination > li > a
20-
{
21-
background-color: white;
22-
color: #000000;
19+
20+
.pagination>li>a {
21+
background-color: white;
22+
color: #000000;
2323
}
24-
25-
.pagination > li > a:focus,
26-
.pagination > li > a:hover,
27-
.pagination > li > span:focus,
28-
.pagination > li > span:hover
29-
{
30-
color: #5a5a5a;
31-
background-color: #eee;
32-
border-color: #ddd;
24+
25+
.pagination>li>a:focus,
26+
.pagination>li>a:hover,
27+
.pagination>li>span:focus,
28+
.pagination>li>span:hover {
29+
color: #5a5a5a;
30+
background-color: #eee;
31+
border-color: #ddd;
3332
}
34-
35-
.pagination > .active > a
36-
{
37-
color: #000000;
38-
background-color: #337ab7 !important;
39-
border: solid 1px #337ab7 !important;
33+
34+
.pagination>.active>a {
35+
color: #000000;
36+
background-color: #337ab7 !important;
37+
border: solid 1px #337ab7 !important;
4038
}
41-
42-
.pagination > .active > a:hover
43-
{
44-
background-color: #4c85b8 !important;
45-
border: solid 1px #4c85b8;
39+
40+
.pagination>.active>a:hover {
41+
background-color: #4c85b8 !important;
42+
border: solid 1px #4c85b8;
4643
}
47-
table,tbody, td, tfoot, th, thead, tr{
48-
border-style:none !important;
44+
45+
table,
46+
tbody,
47+
td,
48+
tfoot,
49+
th,
50+
thead,
51+
tr {
52+
border-style: none !important;
4953
}
5054

5155
table {
@@ -54,11 +58,10 @@
5458
}
5559

5660
.table thead th {
57-
border-bottom: 2px solid #6685a5 !important;
61+
border-bottom: 2px solid #6685a5 !important;
5862
}
59-
.dataTables_filter{
63+
64+
.dataTables_filter {
6065
margin-bottom: 1em !important;
6166
padding: 1px;
62-
}
63-
64-
67+
}

services/contests.js

+14-10
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ const fetchContestRankings = async function (contestSlug) {
1111
if (contest.rankings_fetched) {
1212
return [contest, null];
1313
}
14-
14+
contest.rankings = [];
1515
console.log(`fetching ${contestSlug} ...`);
1616
let resp = await fetch(
1717
`https://leetcode.com/contest/api/ranking/${contestSlug}/?region=global`
1818
);
1919
resp = await resp.json();
20-
let pages = Math.floor(resp.user_num / 25);
20+
let pages = Math.ceil(resp.user_num / 25);
2121
let all_rankings = [];
2222
let failed = [];
2323
let lastPage = Math.MAX_SAFE_INTEGER;
@@ -29,7 +29,7 @@ const fetchContestRankings = async function (contestSlug) {
2929
if (pageNo > lastPage) {
3030
return;
3131
}
32-
console.log(`Fetching rankings (${contestSlug}): page: ${pageNo}`);
32+
// console.log(`Fetching rankings (${contestSlug}): page: ${pageNo}`);
3333
try {
3434
let res = await fetch(
3535
`https://leetcode.com/contest/api/ranking/${contestSlug}/?pagination=${pageNo}&region=global`
@@ -75,10 +75,10 @@ const fetchContestRankings = async function (contestSlug) {
7575
`Fetched rankings (${contestSlug} page: ${pageNo})`
7676
);
7777
} catch (err) {
78-
console.log(
79-
`Failed to fetch rankings (${contestSlug} page: ${pageNo})`,
80-
err.message
81-
);
78+
// console.log(
79+
// `Failed to fetch rankings (${contestSlug} page: ${pageNo})`,
80+
// err.message
81+
// );
8282
if (retries > 0) {
8383
await fetchPageRankings(pageNo, retries - 1);
8484
} else if (throwError) {
@@ -101,13 +101,17 @@ const fetchContestRankings = async function (contestSlug) {
101101
for (let i = 0; i < failed.length; i++) {
102102
await fetchPageRankings(failed[i], maxRetries, true);
103103
}
104-
104+
console.log(`(${contestSlug}) Rankings fetched from leetcode!`);
105105
all_rankings.sort((a, b) => (a.rank > b.rank ? 1 : -1));
106+
106107
contest.rankings = all_rankings;
107108
contest.rankings_fetched = true;
108109
contest.user_num = all_rankings.length;
109-
await contest.update();
110-
console.log(`Updated Rankings in ${contestSlug}.`);
110+
console.time(`Saving rankings in db (${contestSlug})`);
111+
await contest.save();
112+
console.timeEnd(`Saving rankings in db (${contestSlug})`);
113+
console.log(`Updated rankings in db (${contestSlug}).`);
114+
111115
return [contest, null];
112116
} catch (err) {
113117
return [null, err];

services/job-queues/contestPredictionQueue.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
const Queue = require("bull");
2+
const Contest = require("../../models/contest");
23
const { predict } = require("../predict");
34
const opts = require("../redis");
45
const { updateUsers } = require("../users");
56

67
opts.lockDuration = 30 * 60 * 1000; // 30 minutes
8+
opts.maxStalledCount = 0;
79

810
const predictQueue = new Queue("Predictions", opts);
911
predictQueue.process("predictRatings", async (job, done) => {
10-
console.log("Processing job: ", job.id);
11-
const err = await predict(job);
12-
if (err) {
13-
console.error(err);
12+
try {
13+
console.log(`Processing ${job.name} job: ${job.id}`);
14+
const contest = await Contest.findById(job.data.contestSlug, {
15+
ratings_predicted: 1,
16+
});
17+
if (contest && contest.ratings_predicted) {
18+
done(null, { message: "skipped (already predicted)" });
19+
return;
20+
}
21+
const err = await predict(job);
22+
if (err) {
23+
console.error(err);
24+
done(err);
25+
}
26+
done(null, { message: "DONE" });
27+
} catch (err) {
1428
done(err);
1529
}
16-
done();
1730
});
1831

1932
predictQueue.process("updateUserData", async (job, done) => {

services/job-queues/jobScheduler.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ scheduler.process("contestScheduler", async (job, done) => {
2929
attempts: 5,
3030
delay: getRemainingTime(contest.endTime) + 10 * 1000,
3131
backoff: 10000,
32+
priority: 1,
3233
}
3334
);
3435
cnt++;

services/users.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ const getContestParticipantsData = async (contest) => {
321321
await Promise.all(promises);
322322
console.info(
323323
`users fetched: ${i + limit} (${getPercentage(
324-
Math.min(i + limit, total),
324+
Math.min(i + limit, failedRanks.length),
325325
total
326326
)}%)`
327327
);
@@ -345,8 +345,10 @@ const getContestParticipantsData = async (contest) => {
345345
console.log("Unable to fetch these ranks: ", failed);
346346
return [];
347347
}
348-
contest.users_fetched = true;
349-
await contest.save();
348+
await Contest.updateOne(
349+
{ _id: contest._id },
350+
{ $set: { users_fetched: true } }
351+
);
350352
return result;
351353
} catch (err) {
352354
console.error(err);
@@ -369,9 +371,9 @@ const updateUsers = async (job) => {
369371
const total = users.length;
370372

371373
const failed = [];
372-
const totalSuccess = 0;
374+
let totalSuccess = 0;
373375
const fetchUserHelper = async (user) => {
374-
const [data_region, username] = users[i]._id.split("/");
376+
const [data_region, username] = user._id.split("/");
375377
const [result, err] = await fetchUserInfo(username, data_region);
376378
if (err) {
377379
failed.push(user);
@@ -380,13 +382,14 @@ const updateUsers = async (job) => {
380382
}
381383
};
382384

383-
for (let i = 0; i < total; i++) {
385+
for (let i = 0; i < total; i += rateLimit) {
384386
let promises = [];
385387
for (let j = 0; j < rateLimit && i + j < total; j++) {
386388
if (
387389
Date.now() - users[i + j].lastUpdated <
388390
12 * 60 * 60 * 1000
389391
) {
392+
totalSuccess++;
390393
continue;
391394
}
392395
promises.push(fetchUserHelper(users[i + j]));
@@ -407,5 +410,4 @@ const updateUsers = async (job) => {
407410
};
408411

409412
exports.getContestParticipantsData = getContestParticipantsData;
410-
exports.fetchUserInfo = fetchUserInfo;
411413
exports.updateUsers = updateUsers;

0 commit comments

Comments
 (0)