Skip to content

Commit 66005ea

Browse files
Merge pull request #236 from beakerandjake/feature/223-submit-command-update-output-text-from-parsing-adventofcodecom-responses
Feature/223 submit command update output text from parsing adventofcodecom responses
2 parents 86b38e6 + 6b60ddb commit 66005ea

25 files changed

+1031
-1058
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
### Fixed
10+
- Fix submission response parsing. Now handles more server responses with better output to the user. ([#223](https://github.com/beakerandjake/advent-of-code-runner/issues/223))
11+
### Changed
12+
- Remove dependencies: dom-serializer, domutils, htmlparser2
913

1014
## [1.5.0] - 2023-11-16
1115
### Added

package-lock.json

Lines changed: 0 additions & 132 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,8 @@
3737
"chalk": "^5.2.0",
3838
"commander": "^11.1.0",
3939
"date-fns": "^2.29.3",
40-
"dom-serializer": "^2.0.0",
41-
"domutils": "^3.0.1",
4240
"dotenv": "^16.0.3",
4341
"fs-extra": "^11.1.0",
44-
"htmlparser2": "^8.0.1",
4542
"ora": "^6.1.2",
4643
"table": "^6.8.1",
4744
"terminal-link": "^3.0.0",

src/api/api.js

Lines changed: 24 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { getConfigValue } from '../config.js';
2+
import {
3+
EmptyResponseError,
4+
InternalServerError,
5+
NotAuthorizedError,
6+
PuzzleNotFoundError,
7+
} from '../errors/apiErrors.js';
28
import { sizeOfStringInKb } from '../formatting.js';
39
import { logger } from '../logger.js';
4-
import {
5-
extractTextContentOfMain,
6-
parseResponseMessage,
7-
sanitizeMessage,
8-
} from './parseSubmissionResponse.js';
910
import { puzzleAnswerUrl, puzzleInputUrl } from './urls.js';
1011
/**
1112
* Creates a headers object which can be passed to fetch.
@@ -23,46 +24,33 @@ const getHeaders = (authenticationToken) => ({
2324
* @param {Number} day - The day of the puzzle.
2425
* @param {Promise<String>} authenticationToken - Token to authenticate with aoc.
2526
*/
26-
export const downloadInput = async (year, day, authenticationToken) => {
27+
export const getInput = async (year, day, authenticationToken) => {
2728
logger.debug('downloading input file for year: %s, day: %s', year, day);
28-
2929
if (!authenticationToken) {
30-
throw new Error(
31-
'Authentication Token is required to query advent of code.'
32-
);
30+
throw new NotAuthorizedError();
3331
}
3432

35-
// query api
3633
const url = puzzleInputUrl(year, day);
3734
logger.debug('querying url for input: %s', url);
3835
const response = await fetch(url, {
3936
headers: getHeaders(authenticationToken),
4037
});
4138

42-
// bad request, authentication failed.
4339
if (response.status === 400) {
44-
throw new Error('Authentication failed, double check authentication token');
40+
throw new NotAuthorizedError();
4541
}
46-
// not found, invalid day or year.
4742
if (response.status === 404) {
48-
throw new Error('That year/day combination could not be found');
43+
throw new PuzzleNotFoundError(year, day);
4944
}
50-
// handle all other error status codes
5145
if (!response.ok) {
52-
throw new Error(
53-
`Unexpected server error while downloading input file, error: ${response.status} - ${response.statusText}`
54-
);
46+
throw new InternalServerError(response.status, response.statusText);
5547
}
5648

57-
// expect text of response is the input.
5849
const text = await response.text();
59-
50+
logger.debug('downloaded: %s', sizeOfStringInKb(text));
6051
if (!text) {
61-
throw new Error('Advent of code returned empty input');
52+
throw new EmptyResponseError();
6253
}
63-
64-
logger.debug('downloaded: %s', sizeOfStringInKb(text));
65-
6654
return text;
6755
};
6856

@@ -74,22 +62,19 @@ export const downloadInput = async (year, day, authenticationToken) => {
7462
* @param {String|Number} solution - The solution to test.
7563
* @param {String} authenticationToken - Token to authenticate with aoc.
7664
*/
77-
export const submitSolution = async (
65+
export const postAnswer = async (
7866
year,
7967
day,
8068
level,
8169
solution,
8270
authenticationToken
8371
) => {
84-
logger.debug('submitting solution to advent of code', { year, day, level });
72+
logger.debug('posting answer to advent of code', { year, day, level });
8573

8674
if (!authenticationToken) {
87-
throw new Error(
88-
'Authentication Token is required to query advent of code.'
89-
);
75+
throw new NotAuthorizedError();
9076
}
9177

92-
// post to api
9378
const url = puzzleAnswerUrl(year, day);
9479
logger.debug('posting to url: %s', url);
9580
const response = await fetch(url, {
@@ -101,34 +86,20 @@ export const submitSolution = async (
10186
body: `level=${level}&answer=${solution}`,
10287
});
10388

104-
// bad request, authentication failed.
105-
// as of writing advent returns a 302 to redirect the user to the puzzle page on fail
106-
// but check 400 too just incase.
89+
// server can sometimes redirect (302) back to puzzle page if auth fails.
10790
if (response.status === 400 || response.status === 302) {
108-
throw new Error('Authentication failed, double check authentication token');
91+
throw new NotAuthorizedError();
10992
}
110-
// not found, invalid day or year.
11193
if (response.status === 404) {
112-
throw new Error('That year/day combination could not be found');
94+
throw new PuzzleNotFoundError(year, day);
11395
}
114-
// bail on any other type of http error
11596
if (!response.ok) {
116-
throw new Error(
117-
`Unexpected server error while posting solution, error: ${response.status} - ${response.statusText}`
118-
);
97+
throw new InternalServerError(response.status, response.statusText);
11998
}
12099

121-
// advent of code doesn't return status codes, we have to parse the html.
122-
// grab the text content of the <main> element which contains the message we need.
123-
const responseMessage = sanitizeMessage(
124-
extractTextContentOfMain(await response.text())
125-
);
126-
127-
if (!responseMessage) {
128-
throw new Error('Unable get message from advent of code response.');
100+
const text = await response.text();
101+
if (!text) {
102+
throw new EmptyResponseError();
129103
}
130-
131-
// the content of the message tells us what happened
132-
// parse this message to determine the submission result.
133-
return parseResponseMessage(responseMessage);
104+
return text;
134105
};

src/api/index.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,26 @@ import { logger } from '../logger.js';
88
* Decorates the api methods with rate limiting.
99
* @param {Object} module - The imported api to decorate.
1010
*/
11-
const decorateApiWithRateLimiting = ({ downloadInput, submitSolution }) => {
11+
const decorateApiWithRateLimiting = ({ getInput, postAnswer }) => {
1212
logger.debug('decorating api with rate limiting');
1313
return {
14-
downloadInput: rateLimitDecorator(
15-
downloadInput,
16-
rateLimitedActions.downloadInput,
14+
getInput: rateLimitDecorator(
15+
getInput,
16+
rateLimitedActions.getInput,
1717
'Timeout period for downloading an input file has not expired.'
1818
),
19-
submitSolution: rateLimitDecorator(
20-
submitSolution,
21-
rateLimitedActions.submitAnswer,
19+
postAnswer: rateLimitDecorator(
20+
postAnswer,
21+
rateLimitedActions.postAnswer,
2222
'Timeout period for submitting an answer has not expired.'
2323
),
2424
};
2525
};
2626

2727
const useMockApi = getConfigValue('aoc.mockApi.enabled');
2828

29-
const { downloadInput, submitSolution } = useMockApi
29+
const { getInput, postAnswer } = useMockApi
3030
? await import('./mockApi.js')
3131
: decorateApiWithRateLimiting(await import('./api.js'));
3232

33-
export { downloadInput, submitSolution };
33+
export { getInput, postAnswer };

0 commit comments

Comments
 (0)