Refactor code and add comments
Fix eslint errors Move partNumbers object to a json file
This commit is contained in:
154
index.js
154
index.js
@ -1,6 +1,11 @@
|
|||||||
|
// Require npm packages.
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const commandLineArgs = require('command-line-args')
|
const commandLineArgs = require('command-line-args');
|
||||||
|
|
||||||
|
// Get partNumbers from json file.
|
||||||
|
const partNumbers = require('./partNumbers.json');
|
||||||
|
|
||||||
|
// Define command line args accepted.
|
||||||
const optionDefinitions = [
|
const optionDefinitions = [
|
||||||
{ name: 'carrier', type: String, defaultValue: 'TMOBILE' },
|
{ name: 'carrier', type: String, defaultValue: 'TMOBILE' },
|
||||||
{ name: 'model', type: String, defaultValue: 'x' },
|
{ name: 'model', type: String, defaultValue: 'x' },
|
||||||
@ -10,72 +15,119 @@ const optionDefinitions = [
|
|||||||
{ name: 'delay', type: Number, defaultValue: 30 },
|
{ name: 'delay', type: Number, defaultValue: 30 },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Parse command line args.
|
||||||
const options = commandLineArgs(optionDefinitions);
|
const options = commandLineArgs(optionDefinitions);
|
||||||
console.log(options);
|
|
||||||
|
|
||||||
const partNumbers = {
|
|
||||||
'x': {
|
|
||||||
'gray': {
|
|
||||||
'64': "",
|
|
||||||
'256': "MQAU2LL/A",
|
|
||||||
},
|
|
||||||
'silver': {
|
|
||||||
'64': "",
|
|
||||||
'256': "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'8': {
|
|
||||||
'gray': {
|
|
||||||
'64': "",
|
|
||||||
'256': "MQ932LL/A",
|
|
||||||
},
|
|
||||||
'silver': {
|
|
||||||
'64': "",
|
|
||||||
'256': "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Get part number for the specified device.
|
||||||
const partNumber = partNumbers[options.model][options.color][options.storage];
|
const partNumber = partNumbers[options.model][options.color][options.storage];
|
||||||
|
|
||||||
|
// Construct the endpoint url with the options selected.
|
||||||
const endpoint = `https://www.apple.com/shop/retail/pickup-message?pl=true&cppart=${options.carrier}/US&parts.0=${partNumber}&location=${options.zip}`;
|
const endpoint = `https://www.apple.com/shop/retail/pickup-message?pl=true&cppart=${options.carrier}/US&parts.0=${partNumber}&location=${options.zip}`;
|
||||||
// const endpoint = 'https://www.apple.com/shop/retail/pickup-message?pl=true&cppart=TMOBILE/US&parts.0=MQ932LL/A&location=Salem,%20NH';
|
|
||||||
|
|
||||||
let requestsMade = 0;
|
// Keep track of the last request time.
|
||||||
|
let lastRequestTimestamp = null;
|
||||||
|
|
||||||
makeRequest();
|
/**
|
||||||
|
* Update program status display
|
||||||
|
*
|
||||||
|
* @param {String} str The string that will be outputed.
|
||||||
|
*/
|
||||||
|
function updateStatus() {
|
||||||
|
if (lastRequestTimestamp === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function checkAvailability(data) {
|
const timeDelta = Date.now() - lastRequestTimestamp;
|
||||||
|
const timeInSeconds = Math.floor(timeDelta / 1000);
|
||||||
|
process.stdout.write(`Status: Device not available. Last request made ${timeInSeconds} seconds ago\r`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the returned data and find stores where the device is available
|
||||||
|
*
|
||||||
|
* @param {Object} data The api response.
|
||||||
|
* @return {Array} The array of stores where the devices is available.
|
||||||
|
*/
|
||||||
|
function processResponse(data) {
|
||||||
|
// Destructure the stores object out of the body.
|
||||||
const { stores } = data.body;
|
const { stores } = data.body;
|
||||||
|
|
||||||
const storesAvailable = stores.filter(store => {
|
// Filter out stores that do not have the device available.
|
||||||
const parts = Object.values(store.partsAvailability);
|
const storesAvailable = stores.filter((store) => {
|
||||||
const part = parts[0];
|
// Select the specified device partNumber.
|
||||||
const pickupDisplay = part.pickupDisplay;
|
const part = store.partsAvailability[partNumber];
|
||||||
const availability = pickupDisplay === 'available';
|
// Check that the pickupDisplay property says 'available'.
|
||||||
|
const availability = part.pickupDisplay === 'available';
|
||||||
|
// Return true if the device is available or else false.
|
||||||
return availability;
|
return availability;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (storesAvailable.length > 0) {
|
// Return an array of stores where the device is available.
|
||||||
console.log(`Available at ${storesAvailable.length} stores near you:`);
|
return storesAvailable;
|
||||||
console.log(storesAvailable.map(store => `${store.address.address} which is ${store.storeDistanceWithUnit} away`).reduce((msg,store) => `${msg}\n${store}`));
|
}
|
||||||
process.exit();
|
|
||||||
} else {
|
/**
|
||||||
displayResultInPlace("unavailable");
|
* Make a request to the endpoint and get list of stores available
|
||||||
|
*
|
||||||
|
* @return {Promise} A promise that should resolve to an array of stores available.
|
||||||
|
*/
|
||||||
|
function getStoresAvailable() {
|
||||||
|
// Update lastRequestTimestamp.
|
||||||
|
lastRequestTimestamp = Date.now();
|
||||||
|
|
||||||
|
return fetch(endpoint)
|
||||||
|
.then(stream => stream.json())
|
||||||
|
.catch(error => process.stderr.write('Fetch Error :-S', error))
|
||||||
|
.then(data => processResponse(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output list of stores where the device is avaliable.
|
||||||
|
*
|
||||||
|
* @param {Array} storesAvailable The array of stores where the device is avaliable.
|
||||||
|
*/
|
||||||
|
function displayStoresAvailable(storesAvailable) {
|
||||||
|
// Construct the output string by reducing the storesAvailable array into a string.
|
||||||
|
const storesAvailableStr = storesAvailable.reduce(
|
||||||
|
(result, store) =>
|
||||||
|
`${result}\n${store.address.address} which is ${store.storeDistanceWithUnit} away`,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Output the message.
|
||||||
|
process.stdout.write(`The device is currently available at ${storesAvailable.length} stores near you:`);
|
||||||
|
process.stdout.write(storesAvailableStr);
|
||||||
|
process.stdout.write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main program loop
|
||||||
|
*
|
||||||
|
* Continuously check for the device availability until it is available somewhere.
|
||||||
|
*/
|
||||||
|
async function requestLoop() {
|
||||||
|
// Fetch the storesAvailable array.
|
||||||
|
const storesAvailable = await getStoresAvailable();
|
||||||
|
|
||||||
|
if (storesAvailable.length === 0) {
|
||||||
|
// If the array is empty, update the status and after the
|
||||||
|
// specified options.delay amount of seconds, try again.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
makeRequest();
|
requestLoop();
|
||||||
requestsMade++;
|
|
||||||
}, options.delay * 1000);
|
}, options.delay * 1000);
|
||||||
|
} else {
|
||||||
|
// The device is available. Show that information to the user and exit the program.
|
||||||
|
displayStoresAvailable(storesAvailable);
|
||||||
|
process.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRequest() {
|
// Display program started message.
|
||||||
fetch(endpoint)
|
process.stdout.write('Starting program with the following settings:\n');
|
||||||
.then(stream => stream.json())
|
process.stdout.write(`${JSON.stringify(options, null, 2)}\n`);
|
||||||
.then(data => checkAvailability(data))
|
|
||||||
.catch(error => console.log('Fetch Error :-S', error));
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayResultInPlace(data) {
|
// Kick off program.
|
||||||
process.stdout.write(`${data} --- req: ${requestsMade}\r`);
|
setInterval(() => {
|
||||||
}
|
updateStatus();
|
||||||
|
}, 1000);
|
||||||
|
requestLoop();
|
||||||
|
22
partNumbers.json
Normal file
22
partNumbers.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"x": {
|
||||||
|
"gray": {
|
||||||
|
"64": "",
|
||||||
|
"256": "MQAU2LL/A"
|
||||||
|
},
|
||||||
|
"silver": {
|
||||||
|
"64": "",
|
||||||
|
"256": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"gray": {
|
||||||
|
"64": "",
|
||||||
|
"256": "MQ932LL/A"
|
||||||
|
},
|
||||||
|
"silver": {
|
||||||
|
"64": "",
|
||||||
|
"256": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user