1 | import IUrlFetcher from './IUrlFetcher'
|
2 |
|
3 | import { NetworkError } from './errors'
|
4 | import persist from 'node-persist'
|
5 | import got from 'got'
|
6 |
|
7 | export const REQUEST_CACHE_DIR = '/tmp/dockter-request-cache'
|
8 | let REQUEST_CACHE_INITIALISED = false
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | export default class CachingUrlFetcher implements IUrlFetcher {
|
14 | |
15 |
|
16 |
|
17 | async fetchUrl (url: string, options: any = { json: true }): Promise<any> {
|
18 | let value = await CachingUrlFetcher.getFromCache(url)
|
19 | if (value) return value
|
20 |
|
21 | try {
|
22 | const response = await got(url, options)
|
23 | value = response.body
|
24 | } catch (error) {
|
25 | if (error.statusCode === 404) {
|
26 | value = null
|
27 | } else if (['ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN', 'DEPTH_ZERO_SELF_SIGNED_CERT'].includes(error.code)) {
|
28 |
|
29 | throw new NetworkError(`There was a problem fetching ${url} (${error.code}). Are you connected to the internet?`)
|
30 | } else {
|
31 | throw error
|
32 | }
|
33 | }
|
34 |
|
35 | await CachingUrlFetcher.setToCache(url, value)
|
36 |
|
37 | return value
|
38 | }
|
39 |
|
40 | |
41 |
|
42 |
|
43 |
|
44 | static async getFromCache (url: string): Promise<any> {
|
45 | if (!REQUEST_CACHE_INITIALISED) {
|
46 | await persist.init({
|
47 | dir: REQUEST_CACHE_DIR,
|
48 | ttl: 60 * 60 * 1000
|
49 | })
|
50 | REQUEST_CACHE_INITIALISED = true
|
51 | }
|
52 |
|
53 | try {
|
54 | return await persist.getItem(url)
|
55 | } catch (error) {
|
56 | if (error.message.includes('does not look like a valid storage file')) {
|
57 |
|
58 |
|
59 |
|
60 | return null
|
61 | } else {
|
62 | throw error
|
63 | }
|
64 | }
|
65 | }
|
66 |
|
67 | |
68 |
|
69 |
|
70 | static async setToCache (url: string, value: any): Promise<void> {
|
71 | await persist.setItem(url, value)
|
72 | }
|
73 | }
|