-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(refactor): extract cache to middleware (#156)
* chore(refactor): extract the cache logic to middleware * chore: rename middleware to reflect route * chore: remove bluebird, in profit of built-in promise class * chore: add tests for useProxyCache middleware * chore: instrument the ipfs gateway cache layer * chore: instrument the hit/miss ratio and cache size * chore: fix remaining merge conflict
- Loading branch information
Showing
6 changed files
with
109 additions
and
30 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { capture } from '@snapshot-labs/snapshot-sentry'; | ||
import { MAX } from '../utils'; | ||
import { get, set } from '../aws'; | ||
import { ipfsGatewaysCacheHitCount, ipfsGatewaysCacheSize } from '../metrics'; | ||
|
||
/** | ||
* This middleware serves a cache if it exists, else it will process the controller | ||
* and caches its results if it's less than 1MB | ||
*/ | ||
export default async function useProxyCache(req, res, next) { | ||
const { cid } = req.params; | ||
|
||
const cache = await get(cid); | ||
if (cache) { | ||
const cachedSize = Buffer.from(JSON.stringify(cache)).length; | ||
ipfsGatewaysCacheHitCount.inc({ status: 'HIT' }); | ||
ipfsGatewaysCacheSize.inc({ status: 'HIT' }, cachedSize); | ||
return res.json(cache); | ||
} | ||
|
||
const oldJson = res.json; | ||
res.json = async body => { | ||
res.locals.body = body; | ||
|
||
if (res.statusCode === 200 && body) { | ||
try { | ||
const size = Buffer.from(JSON.stringify(body)).length; | ||
if (size <= MAX) { | ||
ipfsGatewaysCacheHitCount.inc({ status: 'MISS' }); | ||
ipfsGatewaysCacheSize.inc({ status: 'MISS' }, size); | ||
await set(cid, body); | ||
} | ||
} catch (e) { | ||
capture(e); | ||
} | ||
} | ||
|
||
return oldJson.call(res, body); | ||
}; | ||
|
||
next(); | ||
} |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,57 @@ | ||
import request from 'supertest'; | ||
import { set, get, remove } from '../../src/aws'; | ||
|
||
const HOST = `http://localhost:${process.env.PORT || 3003}`; | ||
|
||
describe('GET /ipfs/*', () => { | ||
describe('GET /ipfs/:cid', () => { | ||
describe('when the IPFS cid exists', () => { | ||
it('returns a JSON file', async () => { | ||
const response = await request(HOST).get( | ||
'/ipfs/bafkreib5epjzumf3omr7rth5mtcsz4ugcoh3ut4d46hx5xhwm4b3pqr2vi' | ||
); | ||
const cid = 'bafkreib5epjzumf3omr7rth5mtcsz4ugcoh3ut4d46hx5xhwm4b3pqr2vi'; | ||
const path = `/ipfs/${cid}`; | ||
const content = { status: 'OK' }; | ||
|
||
afterEach(async () => { | ||
await remove(cid); | ||
}); | ||
|
||
describe('when the file is cached', () => { | ||
const cachedContent = { status: 'CACHED' }; | ||
|
||
it('returns the cache file', async () => { | ||
await set(cid, cachedContent); | ||
const response = await request(HOST).get(path); | ||
|
||
expect(response.statusCode).toBe(200); | ||
expect(response.body).toEqual({ status: 'OK' }); | ||
expect(response.body).toEqual(cachedContent); | ||
expect(response.statusCode).toBe(200); | ||
expect(response.headers['content-type']).toBe('application/json; charset=utf-8'); | ||
expect(await get(cid)).toEqual(cachedContent); | ||
}); | ||
}); | ||
|
||
it('returns a 400 error when not a JSON file', async () => { | ||
describe('when the file is not cached', () => { | ||
it('returns the file and caches it', async () => { | ||
const response = await request(HOST).get(path); | ||
|
||
expect(response.body).toEqual(content); | ||
expect(response.statusCode).toBe(200); | ||
expect(response.headers['content-type']).toBe('application/json; charset=utf-8'); | ||
expect(await get(cid)).toEqual(response.body); | ||
}); | ||
}); | ||
|
||
it('returns a 415 error when not a JSON file', async () => { | ||
const response = await request(HOST).get( | ||
'/ipfs/bafybeie2x4ptheqskiauhfz4w4pbq7o6742oupitganczhjanvffp2spti' | ||
); | ||
|
||
expect(response.statusCode).toBe(400); | ||
}, 15e3); | ||
expect(response.statusCode).toBe(415); | ||
}, 30e3); | ||
}); | ||
|
||
describe('when the IPFS cid does not exist', () => { | ||
it('returns a 400 error', async () => { | ||
const response = await request(HOST).get('/ipfs/test'); | ||
|
||
expect(response.statusCode).toBe(400); | ||
}); | ||
}, 30e3); | ||
}); | ||
}); |
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