Skip to content

Commit 0b93d97

Browse files
committed
added server source code
1 parent c80107e commit 0b93d97

File tree

6 files changed

+120
-0
lines changed

6 files changed

+120
-0
lines changed

src/server/deno.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import worker from './worker.js';
2+
3+
Deno.serve(worker.fetch);

src/server/deno.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"deploy": {
3+
"project": "652c6edb-dacd-440a-845e-8ea175eddd31",
4+
"exclude": [
5+
"**/node_modules"
6+
],
7+
"include": [],
8+
"entrypoint": "deno.js"
9+
}
10+
}

src/server/deploy.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
deployctl deploy --prod
3+
npx wrangler deploy

src/server/worker.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
function cleanError(s) {
2+
return s.match(/<h1>(.*)<\/h1>/)?.[1] || s;
3+
}
4+
5+
function cleanAnswer(s) {
6+
return s.match(/<article><p>([^.]*\.)/)?.[1] || s;
7+
}
8+
9+
function cleanQuestion(s) {
10+
return s.match(/(?<=<p>Your puzzle answer was <code>).*?(?=<\/code>)/g) || [];
11+
}
12+
13+
async function downloadContent(url, session, postPayload) {
14+
const headers = { Cookie: `session=${session}` };
15+
const options = { headers };
16+
if (postPayload) {
17+
Object.assign(options, {
18+
body: postPayload,
19+
method: 'POST',
20+
});
21+
Object.assign(options.headers, {
22+
'content-type': 'application/x-www-form-urlencoded',
23+
});
24+
}
25+
const response = await fetch(url, options);
26+
if (response.status >= 400) {
27+
throw new Error(
28+
[
29+
`Failed to download from ${url} (${response.status})`,
30+
`Description: ${cleanError(await response.text())}`,
31+
].join('\n'),
32+
);
33+
}
34+
return await response.text();
35+
}
36+
37+
async function getDayAnswer(year, day, session) {
38+
const url = `https://adventofcode.com/${+year}/day/${+day}`;
39+
return cleanQuestion(await downloadContent(url, session));
40+
}
41+
42+
async function getDayInput(year, day, session) {
43+
const url = `https://adventofcode.com/${+year}/day/${+day}/input`;
44+
return await downloadContent(url, session);
45+
}
46+
47+
async function submitDayAnswer(year, day, session, level, answer) {
48+
const url = `https://adventofcode.com/${+year}/day/${+day}/answer`;
49+
const postPayload = `level=${level}&answer=${encodeURIComponent(answer)}`;
50+
return cleanAnswer(await downloadContent(url, session, postPayload));
51+
}
52+
53+
async function respond(fn) {
54+
try {
55+
const body = await fn();
56+
return new Response(
57+
typeof body === 'string' ? body : JSON.stringify(body),
58+
{
59+
status: 200,
60+
headers: { 'Access-Control-Allow-Origin': '*' },
61+
},
62+
);
63+
} catch (e) {
64+
return new Response(e.toString(), {
65+
status: 500,
66+
headers: { 'Access-Control-Allow-Origin': '*' },
67+
});
68+
}
69+
}
70+
71+
export default {
72+
async fetch(req) {
73+
let match;
74+
const session = new URL(req.url).searchParams.get('session');
75+
match = new URLPattern({ pathname: '/input/:year/:day' }).exec(req.url);
76+
if (req.method === 'GET' && match) {
77+
const { year, day } = match.pathname.groups;
78+
return respond(() => getDayInput(year, day, session));
79+
}
80+
match = new URLPattern({ pathname: '/question/:year/:day' }).exec(req.url);
81+
if (req.method === 'GET' && match) {
82+
const { year, day } = match.pathname.groups;
83+
return respond(() => getDayAnswer(year, day, session));
84+
}
85+
match = new URLPattern({ pathname: '/answer/:year/:day' }).exec(req.url);
86+
if (req.method === 'POST' && match) {
87+
const { year, day } = match.pathname.groups;
88+
const formData = await req.formData();
89+
const level = formData.get('level');
90+
const answer = formData.get('answer');
91+
return respond(() => submitDayAnswer(year, day, session, level, answer));
92+
}
93+
return new Response('Not found', { status: 404 });
94+
},
95+
};

src/server/wrangler.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#:schema node_modules/wrangler/config-schema.json
2+
name = "aoc"
3+
main = "worker.js"
4+
compatibility_date = "2024-10-22"
5+
compatibility_flags = ["nodejs_compat"]
6+
7+
[observability]
8+
enabled = true

src/utils/urls.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ export const imports = {
2323
};
2424

2525
// export const aocSolverServer = 'https://www.wix.com/_serverless/adventofcode';
26+
// export const aocSolverServer = 'https://aoc.shahar-talmi.workers.dev';
2627
export const aocSolverServer = 'https://aoc.deno.dev';

0 commit comments

Comments
 (0)