Last active
April 8, 2022 01:18
-
-
Save dbani-dev/d78d08da0a7b5214d5b3f78082721932 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PollingReports { | |
constructor( | |
dataProviderId, | |
siteSelections, | |
values, | |
pollingInterval, | |
pollingMaxAttempts | |
) { | |
super(); | |
this.dataProviderId = dataProviderId; | |
this.siteSelections = siteSelections; | |
this.values = values; | |
this.cancelledPolling = false; | |
this.pollingInterval = pollingInterval; | |
this.pollingMaxAttempts = pollingMaxAttempts; | |
} | |
poll = async ({ fn, validate, interval, maxAttempts = 10 }) => { | |
const sleep = (ms) => { | |
return new Promise( | |
(resolve) => (this.pollingTimeout = setTimeout(resolve, ms)) | |
); | |
}; | |
for (let attempts = 0; attempts < maxAttempts; attempts++) { | |
try { | |
const result = await fn(); | |
if (validate(result)) { | |
return result; | |
} | |
} catch (err) { | |
throw new Error(`function error: ${err.message}`); | |
} | |
await sleep(interval); | |
} | |
throw new Error("polling: exceeded max attempts"); | |
}; | |
requestDataFromS3 = async (signedDataUrl) => { | |
try { | |
if (!this.cancelledPolling) { | |
this.requestSignedPromise = fetch(signedDataUrl, { method: "GET" }); | |
const requestSigned = await this.requestSignedPromise; | |
logInfo(`polling: signed url`, { requestSigned }); | |
if (requestSigned.status === 200) { | |
return requestSigned.json(); | |
} else { | |
throw new Error("Getting data from S3 failed"); | |
} | |
} | |
} catch (err) { | |
throw err; | |
} | |
}; | |
requestAdd = async () => { | |
try { | |
if (!this.cancelledPolling) { | |
const waitForToken = await window.pmpGetAuthToken(); | |
this.requestAddPromise = window.api.post( | |
"api", | |
"reportrequest/addrequest", | |
{ | |
body: { | |
requestType: "report", | |
format: "data", // "data", "csv" etc | |
parameters: { | |
dataProviderId: this.dataProviderId, | |
siteSelections: this.siteSelections, | |
parameters: this.values, | |
}, | |
}, | |
} | |
); | |
return await this.requestAddPromise; | |
} | |
} catch (err) { | |
throw err; | |
} | |
}; | |
requestStatus = async (requestId) => { | |
try { | |
const status = async () => { | |
if (!this.cancelledPolling) { | |
try { | |
this.requestStatusPromise = window.api.get( | |
"api", | |
`reportrequest/getrequeststatus?id=${requestId}` | |
); | |
const requestStatus = await this.requestStatusPromise; | |
console.log({ requestStatus }); | |
if (requestStatus.signedDataUrl) { | |
return { | |
status: requestStatus.status, | |
signedDataUrl: requestStatus.signedDataUrl, | |
}; | |
} else { | |
return { | |
status: requestStatus.status, | |
}; | |
} | |
} catch (err) { | |
throw err; | |
} | |
} | |
}; | |
const validate = (result) => { | |
logInfo(`polling: status`, { status: result.status }); | |
if (!this.cancelledPolling && result.status === "Success") { | |
return true; | |
} | |
return false; | |
}; | |
return this.poll({ | |
fn: status, | |
validate: validate, | |
interval: this.pollingInterval, | |
maxAttempts: this.pollingMaxAttempts, | |
}); | |
} catch (err) { | |
throw err; | |
} | |
}; | |
startPolling = async () => { | |
try { | |
logSuccess(`polling: start`, { | |
values: this.values, | |
siteSelections: this.siteSelections, | |
dataProviderId: this.dataProviderId, | |
}); | |
const requestAdd = await this.requestAdd(); | |
const requestStatus = await this.requestStatus(requestAdd.id); | |
const requestSigned = await this.requestDataFromS3( | |
requestStatus.signedDataUrl | |
); | |
return requestSigned; | |
} catch (err) { | |
throw err; | |
} | |
}; | |
cancelPolling = () => { | |
this.cancelledPolling = true; | |
if (this.requestAddPromise) { | |
window.api.cancel(this.requestAddPromise, "promise cancelled"); | |
} | |
if (this.requestStatusPromise) { | |
window.api.cancel(this.requestStatusPromise, "promise cancelled"); | |
} | |
if (this.requestSignedPromise) { | |
window.api.cancel(this.requestSignedPromise, "promise cancelled"); | |
} | |
if (this.pollTimeout) { | |
clearTimeout(this.pollTimeout); | |
} | |
}; | |
} | |
// test | |
// ERROR: thrown: "Exceeded timeout of 5000 ms for a test. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test." | |
// Timers don't seem to play well with promises | |
describe("Polling Reports", () => { | |
it("polling cancelled", async () => { | |
jest.useFakeTimers(); | |
const polling = new PollingReports( | |
"###", | |
[ | |
{ | |
accountNumber: "###", | |
siteId: null, | |
meterDeviceIds: [], | |
name: "1 Ardrossan Road", | |
text: "1 Ardrossan Road", | |
type: "account", | |
display: true, | |
iconlink: "", | |
}, | |
], | |
{ | |
fromDate: "15/12/2021", | |
toDate: "15/3/2022", | |
aggregate: "2", | |
detailedData: false, | |
}, | |
100, // pollingInterval | |
4 // maxAttempts | |
); | |
// requestAdd | |
window.api.post.mockResolvedValue({ | |
id: "###", | |
}); | |
// requestStatus | |
window.api.get | |
.mockResolvedValueOnce({ | |
status: "Requested", | |
}) | |
.mockResolvedValueOnce({ | |
status: "Requested", | |
}) | |
.mockResolvedValueOnce({ | |
status: "Success", | |
signedDataUrl: "http://", | |
}); | |
// requestSigned | |
fetch.mockResponseOnce(JSON.stringify({ data: "12345" })); | |
await polling.startPolling(); | |
jest.advanceTimersByTime(100); | |
expect(window.api.post).toHaveBeenCalledTimes(1); | |
expect(window.api.get).toHaveBeenCalledTimes(1); | |
expect(fetch).toHaveBeenCalledTimes(0); | |
jest.advanceTimersByTime(200); | |
expect(window.api.post).toHaveBeenCalledTimes(1); | |
expect(window.api.get).toHaveBeenCalledTimes(2); | |
expect(fetch).toHaveBeenCalledTimes(0); | |
polling.cancelPolling(); | |
expect(window.api.post).toHaveBeenCalledTimes(1); | |
expect(window.api.get).toHaveBeenCalledTimes(2); | |
expect(fetch).toHaveBeenCalledTimes(0); | |
jest.useRealTimers(); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment