@abtnode/blocklet-services 1.16.14-beta-9743e8e2 → 1.16.14-beta-c775fe49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/index.js +8 -3
- package/api/libs/error.svg +1 -0
- package/api/libs/image.js +235 -0
- package/api/routes/blocklet.js +11 -1
- package/api/services/image/index.js +61 -0
- package/build/asset-manifest.json +3 -3
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- package/build/static/js/{main.82cb8447.js → main.1a8e765b.js} +3 -3
- package/package.json +21 -19
- /package/build/static/js/{main.82cb8447.js.LICENSE.txt → main.1a8e765b.js.LICENSE.txt} +0 -0
package/api/index.js
CHANGED
|
@@ -30,6 +30,7 @@ const BlockletEventsNotifier = require('./services/notification/blocklet-events-
|
|
|
30
30
|
const { init: initAuth } = require('./services/auth');
|
|
31
31
|
const { init: initDashboard } = require('./services/dashboard');
|
|
32
32
|
const StaticService = require('./services/static');
|
|
33
|
+
const initImageService = require('./services/image');
|
|
33
34
|
const StudioService = require('./services/studio');
|
|
34
35
|
const AnalyticService = require('./services/analytics');
|
|
35
36
|
const createEnvRoutes = require('./routes/env');
|
|
@@ -89,6 +90,7 @@ module.exports = function createServer(node, serverOptions = {}) {
|
|
|
89
90
|
const { middlewares: authMiddlewares, routes: authRoutes, ensureWsUser } = initAuth({ node, options });
|
|
90
91
|
const notificationService = initNotification({ node });
|
|
91
92
|
const relayService = initRelay({ node });
|
|
93
|
+
const imageService = initImageService({ node });
|
|
92
94
|
const dashboardService = initDashboard({ node, ensureWsUser });
|
|
93
95
|
|
|
94
96
|
// Proxy engine
|
|
@@ -303,9 +305,12 @@ module.exports = function createServer(node, serverOptions = {}) {
|
|
|
303
305
|
try {
|
|
304
306
|
const { target } = await ensureProxyUrl(req);
|
|
305
307
|
if (target) {
|
|
306
|
-
|
|
307
|
-
target
|
|
308
|
-
|
|
308
|
+
if (imageService.isImageAccepted(req) && imageService.isImageRequest(req)) {
|
|
309
|
+
req.target = target; // for internal use
|
|
310
|
+
imageService.processImage(req, res);
|
|
311
|
+
} else {
|
|
312
|
+
proxy.safeWeb(req, res, { target });
|
|
313
|
+
}
|
|
309
314
|
} else {
|
|
310
315
|
throw new Error('empty proxy target');
|
|
311
316
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200" viewBox="0 0 300 200"><rect width="100%" height="100%" fill="#DDDDDD"/><path fill="#999999" d="M112.5 94.58q0 5.4-1.79 10.01-1.78 4.61-5.05 7.97-3.26 3.37-7.85 5.26-4.59 1.88-10.2 1.88-5.58 0-10.17-1.88-4.59-1.89-7.87-5.26-3.28-3.36-5.08-7.97-1.8-4.61-1.8-10.01 0-5.41 1.8-10.02 1.8-4.6 5.08-7.97 3.28-3.36 7.87-5.25 4.59-1.89 10.17-1.89 3.74 0 7.04.87 3.29.87 6.05 2.45 2.75 1.58 4.94 3.84 2.2 2.26 3.73 5.05 1.53 2.79 2.33 6.05t.8 6.87Zm-9.35 0q0-4.05-1.09-7.26t-3.1-5.46q-2-2.24-4.88-3.43-2.87-1.19-6.47-1.19-3.61 0-6.48 1.19-2.87 1.19-4.9 3.43-2.02 2.25-3.11 5.46-1.08 3.21-1.08 7.26 0 4.04 1.08 7.26 1.09 3.21 3.11 5.44 2.03 2.22 4.9 3.41 2.87 1.19 6.48 1.19 3.6 0 6.47-1.19 2.88-1.19 4.88-3.41 2.01-2.23 3.1-5.44 1.09-3.22 1.09-7.26Zm31.51-10.85q3.88 0 7.06 1.26 3.18 1.26 5.44 3.57 2.26 2.31 3.48 5.64 1.23 3.34 1.23 7.45 0 4.15-1.23 7.48-1.22 3.33-3.48 5.68-2.26 2.34-5.44 3.6-3.18 1.26-7.06 1.26-3.91 0-7.1-1.26-3.2-1.26-5.46-3.6-2.26-2.35-3.5-5.68-1.24-3.33-1.24-7.48 0-4.11 1.24-7.45 1.24-3.33 3.5-5.64 2.26-2.31 5.46-3.57 3.19-1.26 7.1-1.26Zm0 29.48q4.36 0 6.45-2.92 2.09-2.93 2.09-8.57 0-5.65-2.09-8.6-2.09-2.96-6.45-2.96-4.42 0-6.54 2.97-2.13 2.98-2.13 8.59 0 5.61 2.13 8.55 2.12 2.94 6.54 2.94Zm32.03-18.73v15.64q1.43 1.73 3.11 2.44 1.69.72 3.66.72 1.9 0 3.43-.72 1.53-.71 2.6-2.17t1.65-3.69q.58-2.23.58-5.25 0-3.06-.49-5.19-.5-2.12-1.41-3.45-.92-1.33-2.23-1.94-1.31-.61-2.98-.61-2.61 0-4.45 1.1-1.84 1.11-3.47 3.12Zm-1.12-8.67.68 3.23q2.14-2.42 4.86-3.91 2.72-1.5 6.39-1.5 2.86 0 5.22 1.19 2.37 1.19 4.08 3.45 1.72 2.26 2.66 5.58.93 3.31.93 7.6 0 3.91-1.05 7.24-1.06 3.33-3.01 5.78-1.96 2.45-4.73 3.82-2.77 1.38-6.2 1.38-2.93 0-5-.9-2.08-.9-3.71-2.5v14.28h-8.4V84.28h5.14q1.63 0 2.14 1.53Zm54.54 2.24-1.91 3.03q-.34.54-.71.76-.38.22-.95.22-.62 0-1.31-.34-.7-.34-1.62-.76-.92-.43-2.09-.77t-2.77-.34q-2.48 0-3.89 1.06-1.41 1.05-1.41 2.75 0 1.12.73 1.89.73.76 1.93 1.34 1.21.58 2.74 1.04 1.53.46 3.11 1 1.58.54 3.11 1.24 1.53.7 2.74 1.77 1.21 1.07 1.94 2.57.73 1.49.73 3.6 0 2.52-.9 4.64-.9 2.13-2.67 3.67-1.77 1.55-4.37 2.42-2.6.86-6 .86-1.8 0-3.52-.32t-3.3-.9q-1.58-.58-2.92-1.36-1.34-.78-2.36-1.7l1.93-3.2q.38-.57.89-.88.51-.31 1.29-.31t1.48.45q.7.44 1.61.95.92.51 2.16.95 1.24.44 3.15.44 1.49 0 2.56-.36 1.08-.35 1.77-.93.7-.58 1.02-1.34.33-.77.33-1.58 0-1.23-.73-2.01-.74-.78-1.94-1.36-1.21-.58-2.76-1.04-1.54-.46-3.16-1-1.61-.54-3.16-1.27-1.55-.74-2.76-1.86-1.2-1.12-1.93-2.75t-.73-3.95q0-2.14.85-4.08.85-1.93 2.5-3.38 1.64-1.44 4.11-2.31 2.46-.87 5.69-.87 3.61 0 6.57 1.19 2.95 1.19 4.93 3.13ZM228.3 70h7.89v19.44q0 3.1-.31 6.07-.3 2.98-.78 6.31h-5.71q-.48-3.33-.78-6.31-.31-2.97-.31-6.07V70Zm-1.33 44.54q0-1.06.4-2.01.39-.95 1.08-1.63.7-.68 1.65-1.09.95-.41 2.04-.41 1.06 0 2.01.41.95.41 1.65 1.09.69.68 1.1 1.63.41.95.41 2.01 0 1.08-.41 2.02-.41.93-1.1 1.61-.7.68-1.65 1.08-.95.39-2.01.39-1.09 0-2.04-.39-.95-.4-1.65-1.08-.69-.68-1.08-1.61-.4-.94-.4-2.02Z"/></svg>
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// A simple image service based on sharp
|
|
2
|
+
// @link https://sharp.pixelplumbing.com/
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const sharp = require('sharp');
|
|
6
|
+
const { Joi } = require('@arcblock/validator');
|
|
7
|
+
const stringify = require('json-stable-stringify');
|
|
8
|
+
const md5 = require('@abtnode/util/lib/md5');
|
|
9
|
+
const formatError = require('@abtnode/util/lib/format-error');
|
|
10
|
+
|
|
11
|
+
const logger = require('@abtnode/logger')(require('../../../../package.json').name);
|
|
12
|
+
|
|
13
|
+
const errorImage = path.resolve(__dirname, './error.svg');
|
|
14
|
+
|
|
15
|
+
const FORMATS = ['png', 'jpeg', 'webp', 'avif', 'heif'];
|
|
16
|
+
const OPERATIONS = ['none', 'resize', 'crop'];
|
|
17
|
+
const QUALITIES = {
|
|
18
|
+
png: 100,
|
|
19
|
+
jpeg: 80,
|
|
20
|
+
webp: 80,
|
|
21
|
+
avif: 50,
|
|
22
|
+
heif: 50,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const EXTENSIONS = {
|
|
26
|
+
png: 'png',
|
|
27
|
+
jpeg: 'jpeg',
|
|
28
|
+
jpg: 'jpeg',
|
|
29
|
+
webp: 'webp',
|
|
30
|
+
avif: 'avif',
|
|
31
|
+
heif: 'heif',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const schema = Joi.object({
|
|
35
|
+
imageFilter: Joi.string()
|
|
36
|
+
.valid(...OPERATIONS)
|
|
37
|
+
.required(),
|
|
38
|
+
|
|
39
|
+
w: Joi.number().integer().min(1).max(2048).when('imageFilter', {
|
|
40
|
+
is: 'crop',
|
|
41
|
+
then: Joi.required(),
|
|
42
|
+
otherwise: Joi.optional(),
|
|
43
|
+
}),
|
|
44
|
+
h: Joi.number().integer().min(1).max(2048).when('imageFilter', {
|
|
45
|
+
is: 'crop',
|
|
46
|
+
then: Joi.required(),
|
|
47
|
+
otherwise: Joi.optional(),
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
q: Joi.number()
|
|
51
|
+
.integer()
|
|
52
|
+
.min(10)
|
|
53
|
+
.max(100)
|
|
54
|
+
.default((input) => {
|
|
55
|
+
if (input.f && QUALITIES[input.f]) {
|
|
56
|
+
return QUALITIES[input.f];
|
|
57
|
+
}
|
|
58
|
+
return 90;
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
p: Joi.number().valid(0, 1).optional().default(1), // progressive
|
|
62
|
+
g: Joi.number().valid(0, 1).optional().default(0), // greyscale
|
|
63
|
+
r: Joi.number().integer().valid(90, 180, 270).optional(), // rotate
|
|
64
|
+
s: Joi.number().integer().min(0).max(2000).optional(), // sharpen
|
|
65
|
+
b: Joi.number().integer().min(1).max(2000).optional(), // blur
|
|
66
|
+
a: Joi.number().valid(0, 1).optional().default(1), // alpha channel, transparency
|
|
67
|
+
n: Joi.number().valid(0, 1).optional().default(0), // negative
|
|
68
|
+
|
|
69
|
+
// image format
|
|
70
|
+
f: Joi.string()
|
|
71
|
+
.valid(...FORMATS)
|
|
72
|
+
.optional(),
|
|
73
|
+
|
|
74
|
+
// resize positions
|
|
75
|
+
m: Joi.string().valid('cover', 'contain', 'fill', 'inside', 'outside').optional().default('inside'),
|
|
76
|
+
|
|
77
|
+
// crop positions
|
|
78
|
+
t: Joi.number().integer().min(0).max(2048).optional().default(0),
|
|
79
|
+
l: Joi.number().integer().min(0).max(2048).optional().default(0),
|
|
80
|
+
|
|
81
|
+
e: Joi.number().valid(0, 1).optional().default(0), // return error
|
|
82
|
+
})
|
|
83
|
+
.or('w', 'h')
|
|
84
|
+
.rename('i', 'p')
|
|
85
|
+
.options({ stripUnknown: true, allowUnknown: true, noDefaults: false });
|
|
86
|
+
|
|
87
|
+
const isImageAccepted = (req) => {
|
|
88
|
+
return FORMATS.some((x) => req.accepts(`image/${x}`));
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const isImageRequest = (req) => {
|
|
92
|
+
if (req.method !== 'GET') {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (!req.query.imageFilter) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const { error, value } = schema.validate(req.query);
|
|
99
|
+
if (error) {
|
|
100
|
+
logger.warn('image service filter params invalid:', formatError(error));
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
req.imageFilter = value;
|
|
105
|
+
return true;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const tasks = {};
|
|
109
|
+
const processAndRespond = (req, res, cacheDir, getSrc) => {
|
|
110
|
+
if (fs.existsSync(cacheDir) === false) {
|
|
111
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const params = req.imageFilter;
|
|
115
|
+
const extension = path.extname(req.path).slice(1);
|
|
116
|
+
if (!extension && !params.f) {
|
|
117
|
+
res.status(400).send('Image filter failed: either extension or format must be specified');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const cacheKey = md5(stringify({ target: req.target, path: req.path, params }));
|
|
122
|
+
const destPath = path.join(cacheDir, `${cacheKey}.${params.f || extension}`);
|
|
123
|
+
if (fs.existsSync(destPath)) {
|
|
124
|
+
res.header('Content-Type', `image/${params.f || extension}`);
|
|
125
|
+
res.sendFile(destPath, { maxAge: '356d', immutable: true });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// do the convert
|
|
130
|
+
tasks[cacheKey] ??= getSrc(req)
|
|
131
|
+
.then(([src, ext]) => processImage(src, ext, destPath, params))
|
|
132
|
+
.finally(() => {
|
|
133
|
+
setTimeout(() => {
|
|
134
|
+
delete tasks[cacheKey];
|
|
135
|
+
}, 1000);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
tasks[cacheKey]
|
|
139
|
+
.then(() => {
|
|
140
|
+
logger.info('image filter succeed', { params, url: req.url, destPath });
|
|
141
|
+
res.header('Content-Type', `image/${params.f || extension}`);
|
|
142
|
+
res.sendFile(destPath, { maxAge: '356d', immutable: true });
|
|
143
|
+
})
|
|
144
|
+
.catch((err) => {
|
|
145
|
+
logger.error('image filter failed', { error: err, params, url: req.url });
|
|
146
|
+
if (params.e) {
|
|
147
|
+
res.status(500).send(`Image service error: ${err.message}`);
|
|
148
|
+
} else {
|
|
149
|
+
res.status(500);
|
|
150
|
+
res.sendFile(errorImage, { maxAge: '0' });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const processImage = (src, extension, dest, params) => {
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
157
|
+
const {
|
|
158
|
+
imageFilter,
|
|
159
|
+
w: width,
|
|
160
|
+
h: height,
|
|
161
|
+
t: top,
|
|
162
|
+
l: left,
|
|
163
|
+
q: quality,
|
|
164
|
+
f: format,
|
|
165
|
+
m: mode,
|
|
166
|
+
r: rotate,
|
|
167
|
+
p: progressive,
|
|
168
|
+
g: greyscale,
|
|
169
|
+
b: blur,
|
|
170
|
+
a: transparency,
|
|
171
|
+
n: negative,
|
|
172
|
+
s: sharpen,
|
|
173
|
+
} = params;
|
|
174
|
+
|
|
175
|
+
const dimensions = { top, left };
|
|
176
|
+
if (width) {
|
|
177
|
+
dimensions.width = width;
|
|
178
|
+
}
|
|
179
|
+
if (height) {
|
|
180
|
+
dimensions.height = height;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const pipeline = sharp().timeout({ seconds: 8 });
|
|
184
|
+
if (rotate) {
|
|
185
|
+
pipeline.rotate(rotate);
|
|
186
|
+
}
|
|
187
|
+
if (imageFilter === 'resize') {
|
|
188
|
+
pipeline.resize({ ...dimensions, fit: mode, withoutEnlargement: true });
|
|
189
|
+
}
|
|
190
|
+
if (imageFilter === 'crop') {
|
|
191
|
+
pipeline.extract(dimensions);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (sharpen) {
|
|
195
|
+
pipeline.sharpen(sharpen);
|
|
196
|
+
}
|
|
197
|
+
if (blur) {
|
|
198
|
+
pipeline.blur(blur);
|
|
199
|
+
}
|
|
200
|
+
if (greyscale) {
|
|
201
|
+
pipeline.greyscale();
|
|
202
|
+
}
|
|
203
|
+
if (transparency) {
|
|
204
|
+
pipeline.ensureAlpha();
|
|
205
|
+
} else {
|
|
206
|
+
pipeline.removeAlpha();
|
|
207
|
+
}
|
|
208
|
+
if (negative) {
|
|
209
|
+
pipeline.negate();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// output stream
|
|
213
|
+
const out = fs.createWriteStream(dest);
|
|
214
|
+
out.on('close', () => {
|
|
215
|
+
resolve(dest);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
out.on('error', (error) => {
|
|
219
|
+
reject(error);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
pipeline[format || EXTENSIONS[extension]]({ quality, progressive: !!progressive, force: true });
|
|
223
|
+
|
|
224
|
+
// run the pipeline
|
|
225
|
+
src.pipe(pipeline).pipe(out);
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
module.exports = {
|
|
230
|
+
isImageAccepted,
|
|
231
|
+
isImageRequest,
|
|
232
|
+
processAndRespond,
|
|
233
|
+
processImage,
|
|
234
|
+
EXTENSIONS,
|
|
235
|
+
};
|
package/api/routes/blocklet.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
3
4
|
const cloneDeep = require('lodash/cloneDeep');
|
|
4
5
|
const dayjs = require('@abtnode/util/lib/dayjs');
|
|
5
6
|
const JWT = require('@arcblock/jwt');
|
|
@@ -41,6 +42,7 @@ const { createDownloadLogStream } = require('@abtnode/core/lib/util/log');
|
|
|
41
42
|
const { BlockletStatus } = require('@blocklet/constant');
|
|
42
43
|
|
|
43
44
|
const { checkAdminPermission } = require('../middlewares/check-permission');
|
|
45
|
+
const { isImageAccepted, isImageRequest, processAndRespond } = require('../libs/image');
|
|
44
46
|
|
|
45
47
|
const polishBlocklet = (doc) => {
|
|
46
48
|
const res = cloneDeep(doc);
|
|
@@ -110,6 +112,7 @@ module.exports = {
|
|
|
110
112
|
cacheError
|
|
111
113
|
);
|
|
112
114
|
|
|
115
|
+
const cacheDir = path.join(node.dataDirs.cache, 'services', 'image');
|
|
113
116
|
server.get(`${prefix}${USER_AVATAR_PATH_PREFIX}/:fileName`, async (req, res) => {
|
|
114
117
|
const sendOptions = { maxAge: '1y' };
|
|
115
118
|
|
|
@@ -131,7 +134,14 @@ module.exports = {
|
|
|
131
134
|
return;
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
|
|
137
|
+
if (isImageAccepted(req) && isImageRequest(req)) {
|
|
138
|
+
const appDir = path.join(cacheDir, blocklet.appPid);
|
|
139
|
+
processAndRespond(req, res, appDir, () =>
|
|
140
|
+
Promise.resolve([fs.createReadStream(avatarFile), path.extname(avatarFile).slice(1)])
|
|
141
|
+
);
|
|
142
|
+
} else {
|
|
143
|
+
res.sendFile(avatarFile, sendOptions);
|
|
144
|
+
}
|
|
135
145
|
} catch (err) {
|
|
136
146
|
logger.error('failed to send user avatar', { fileName: req.params.fileName, error: err });
|
|
137
147
|
res.status(500).send(err.message);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// A simple image service based on sharp
|
|
2
|
+
// @link https://sharp.pixelplumbing.com/
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const logger = require('@abtnode/logger')(require('../../../package.json').name);
|
|
7
|
+
|
|
8
|
+
const { isImageAccepted, isImageRequest, processAndRespond, EXTENSIONS } = require('../../libs/image');
|
|
9
|
+
|
|
10
|
+
const createImageService = ({ node }) => {
|
|
11
|
+
const getUpstreamImage = (req) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const upstream = new URL(req.url, req.target);
|
|
14
|
+
http
|
|
15
|
+
.request(
|
|
16
|
+
{
|
|
17
|
+
hostname: upstream.hostname,
|
|
18
|
+
port: upstream.port || 80,
|
|
19
|
+
path: upstream.pathname + upstream.search,
|
|
20
|
+
method: req.method,
|
|
21
|
+
headers: req.headers,
|
|
22
|
+
},
|
|
23
|
+
(res) => {
|
|
24
|
+
logger.info('image service upstream response:', {
|
|
25
|
+
filter: req.imageFilter,
|
|
26
|
+
headers: res.headers,
|
|
27
|
+
status: res.statusCode,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const [type, extension] = (res.headers['content-type'] || '').split('/');
|
|
31
|
+
if (type !== 'image') {
|
|
32
|
+
reject(new Error('upstream response is not an image'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (extension !== EXTENSIONS[path.extname(req.path).slice(1)]) {
|
|
36
|
+
reject(new Error('upstream response type and file extension mismatch'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
resolve([res, extension]);
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
.on('error', reject)
|
|
44
|
+
.end();
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const cacheDir = path.join(node.dataDirs.cache, 'services', 'image');
|
|
49
|
+
const processImage = (req, res) => {
|
|
50
|
+
const appDir = path.join(cacheDir, req.getBlockletDid());
|
|
51
|
+
processAndRespond(req, res, appDir, getUpstreamImage);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
isImageAccepted,
|
|
56
|
+
isImageRequest,
|
|
57
|
+
processImage,
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
module.exports = createImageService;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "/.well-known/service/static/static/css/main.7ea79dc8.css",
|
|
4
|
-
"main.js": "/.well-known/service/static/static/js/main.
|
|
4
|
+
"main.js": "/.well-known/service/static/static/js/main.1a8e765b.js",
|
|
5
5
|
"static/js/4716.a1240199.chunk.js": "/.well-known/service/static/static/js/4716.a1240199.chunk.js",
|
|
6
6
|
"static/js/4359.5ed52fe3.chunk.js": "/.well-known/service/static/static/js/4359.5ed52fe3.chunk.js",
|
|
7
7
|
"static/js/1255.0e8a8a45.chunk.js": "/.well-known/service/static/static/js/1255.0e8a8a45.chunk.js",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"router-template-styles/styles.css": "/.well-known/service/static/router-template-styles/styles.css",
|
|
90
90
|
"index.html": "/.well-known/service/static/index.html",
|
|
91
91
|
"main.7ea79dc8.css.map": "/.well-known/service/static/static/css/main.7ea79dc8.css.map",
|
|
92
|
-
"main.
|
|
92
|
+
"main.1a8e765b.js.map": "/.well-known/service/static/static/js/main.1a8e765b.js.map",
|
|
93
93
|
"4716.a1240199.chunk.js.map": "/.well-known/service/static/static/js/4716.a1240199.chunk.js.map",
|
|
94
94
|
"4359.5ed52fe3.chunk.js.map": "/.well-known/service/static/static/js/4359.5ed52fe3.chunk.js.map",
|
|
95
95
|
"1255.0e8a8a45.chunk.js.map": "/.well-known/service/static/static/js/1255.0e8a8a45.chunk.js.map",
|
|
@@ -157,6 +157,6 @@
|
|
|
157
157
|
},
|
|
158
158
|
"entrypoints": [
|
|
159
159
|
"static/css/main.7ea79dc8.css",
|
|
160
|
-
"static/js/main.
|
|
160
|
+
"static/js/main.1a8e765b.js"
|
|
161
161
|
]
|
|
162
162
|
}
|
package/build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><link rel="manifest" href="/.well-known/service/manifest.json"/><script src="/.well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.well-known/service/static/static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><link rel="manifest" href="/.well-known/service/manifest.json"/><script src="/.well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.well-known/service/static/static/js/main.1a8e765b.js"></script><link href="/.well-known/service/static/static/css/main.7ea79dc8.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|