|
1 | 1 | // @ts-check |
2 | | -import { downloadImage, fit, identify, resize } from '../lib/image'; |
3 | | -import mime from 'mime-types'; |
4 | | -import URL from 'url'; |
5 | | - |
6 | | -const SUPPORTED_ACTIONS = ['fit', 'resize', 'identify']; |
7 | | -const SUPPORTED_MIMETYPES = ['image/gif', 'image/png', 'image/jpeg', 'image/webp', 'image/svg+xml']; |
8 | | -const ONE_YEAR = 31557600000; |
| 2 | +import CacheFactory from "../image/cache/factory"; |
| 3 | +import ActionFactory from "../image/action/factory"; |
9 | 4 |
|
10 | 5 | const asyncMiddleware = fn => (req, res, next) => { |
11 | 6 | Promise.resolve(fn(req, res, next)).catch(next); |
12 | 7 | }; |
13 | 8 |
|
14 | 9 | export default ({ config, db }) => |
15 | | - asyncMiddleware(async (req, res, body) => { |
| 10 | + asyncMiddleware(async (req, res, next) => { |
16 | 11 | if (!(req.method == 'GET')) { |
17 | 12 | res.set('Allow', 'GET'); |
18 | 13 | return res.status(405).send('Method Not Allowed'); |
19 | 14 | } |
| 15 | + const cacheFactory = new CacheFactory(config, req) |
20 | 16 |
|
21 | 17 | req.socket.setMaxListeners(config.imageable.maxListeners || 50); |
22 | | - |
23 | | - let width |
24 | | - let height |
25 | | - let action |
26 | | - let imgUrl |
27 | | - |
28 | | - if (req.query.url) { // url provided as the query param |
29 | | - imgUrl = decodeURIComponent(req.query.url) |
30 | | - width = parseInt(req.query.width) |
31 | | - height = parseInt(req.query.height) |
32 | | - action = req.query.action |
33 | | - } else { |
34 | | - let urlParts = req.url.split('/'); |
35 | | - width = parseInt(urlParts[1]); |
36 | | - height = parseInt(urlParts[2]); |
37 | | - action = urlParts[3]; |
38 | | - imgUrl = `${config[config.platform].imgUrl}/${urlParts.slice(4).join('/')}`; // full original image url |
39 | | - |
40 | | - if (urlParts.length < 4) { |
41 | | - return res.status(400).send({ |
42 | | - code: 400, |
43 | | - result: 'Please provide following parameters: /img/<width>/<height>/<action:fit,resize,identify>/<relative_url>' |
44 | | - }); |
45 | | - } |
46 | | - } |
47 | 18 |
|
| 19 | + let imageBuffer |
48 | 20 |
|
49 | | - if (isNaN(width) || isNaN(height) || !SUPPORTED_ACTIONS.includes(action)) { |
50 | | - return res.status(400).send({ |
51 | | - code: 400, |
52 | | - result: 'Please provide following parameters: /img/<width>/<height>/<action:fit,resize,identify>/<relative_url> OR ?url=&width=&height=&action=' |
53 | | - }); |
54 | | - } |
55 | | - |
56 | | - if (width > config.imageable.imageSizeLimit || width < 0 || height > config.imageable.imageSizeLimit || height < 0) { |
57 | | - return res.status(400).send({ |
58 | | - code: 400, |
59 | | - result: `Width and height must have a value between 0 and ${config.imageable.imageSizeLimit}` |
60 | | - }); |
61 | | - } |
62 | | - |
63 | | - if (!isImageSourceHostAllowed(imgUrl, config.imageable.whitelist)) { |
64 | | - return res.status(400).send({ |
65 | | - code: 400, |
66 | | - result: `Host is not allowed` |
67 | | - }); |
68 | | - } |
| 21 | + const actionFactory = new ActionFactory(req , res, next, config) |
| 22 | + const imageAction = actionFactory.getAdapter(config.imageable.action.type) |
| 23 | + imageAction.getOption() |
| 24 | + imageAction.validateOptions() |
| 25 | + imageAction.isImageSourceHostAllowed() |
| 26 | + imageAction.validateMIMEType() |
69 | 27 |
|
70 | | - const mimeType = mime.lookup(imgUrl); |
| 28 | + const cache = cacheFactory.getAdapter(config.imageable.caching.type) |
71 | 29 |
|
72 | | - if (mimeType === false || !SUPPORTED_MIMETYPES.includes(mimeType)) { |
73 | | - return res.status(400).send({ |
74 | | - code: 400, |
75 | | - result: 'Unsupported file type' |
76 | | - }); |
77 | | - } |
| 30 | + if (config.imageable.caching.active && await cache.check()) { |
| 31 | + await cache.getImageFromCache() |
| 32 | + imageBuffer = cache.image |
| 33 | + } else { |
| 34 | + await imageAction.prossesImage() |
78 | 35 |
|
79 | | - console.log(`[URL]: ${imgUrl} - [ACTION]: ${action} - [WIDTH]: ${width} - [HEIGHT]: ${height}`); |
| 36 | + if (config.imageable.caching.active) { |
| 37 | + cache.image = imageAction.imageBuffer |
| 38 | + await cache.save() |
| 39 | + } |
80 | 40 |
|
81 | | - let buffer; |
82 | | - try { |
83 | | - buffer = await downloadImage(imgUrl); |
84 | | - } catch (err) { |
85 | | - return res.status(400).send({ |
86 | | - code: 400, |
87 | | - result: `Unable to download the requested image ${imgUrl}` |
88 | | - }); |
| 41 | + imageBuffer = imageAction.imageBuffer |
89 | 42 | } |
90 | 43 |
|
91 | | - switch (action) { |
92 | | - case 'resize': |
93 | | - return res |
94 | | - .type(mimeType) |
95 | | - .set({ 'Cache-Control': `max-age=${ONE_YEAR}` }) |
96 | | - .send(await resize(buffer, width, height)); |
97 | | - case 'fit': |
98 | | - return res |
99 | | - .type(mimeType) |
100 | | - .set({ 'Cache-Control': `max-age=${ONE_YEAR}` }) |
101 | | - .send(await fit(buffer, width, height)); |
102 | | - case 'identify': |
103 | | - return res.set({ 'Cache-Control': `max-age=${ONE_YEAR}` }).send(await identify(buffer)); |
104 | | - default: |
105 | | - throw new Error('Unknown action'); |
106 | | - } |
| 44 | + return res |
| 45 | + .type(imageAction.mimeType) |
| 46 | + .set({ 'Cache-Control': `max-age=${imageAction.maxAgeForResponse}` }) |
| 47 | + .send(imageBuffer); |
107 | 48 | }); |
108 | | - |
109 | | -function _isUrlWhitelisted(url, whitelistType, defaultValue, whitelist) { |
110 | | - if (arguments.length != 4) throw new Error('params are not optional!'); |
111 | | - |
112 | | - if (whitelist && whitelist.hasOwnProperty(whitelistType)) { |
113 | | - const requestedHost = URL.parse(url).host; |
114 | | - const matches = whitelist[whitelistType].map(allowedHost => { |
115 | | - allowedHost = allowedHost instanceof RegExp ? allowedHost : new RegExp(allowedHost); |
116 | | - return !!requestedHost.match(allowedHost); |
117 | | - }); |
118 | | - |
119 | | - return matches.indexOf(true) > -1; |
120 | | - } else { |
121 | | - return defaultValue; |
122 | | - } |
123 | | -} |
124 | | - |
125 | | -function isImageSourceHostAllowed(url, whitelist) { |
126 | | - return _isUrlWhitelisted(url, 'allowedHosts', true, whitelist); |
127 | | -} |
0 commit comments