@eik/core 1.3.46 → 1.3.48
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/CHANGELOG.md +14 -0
- package/lib/main.js +18 -3
- package/lib/sinks/test.js +20 -19
- package/package.json +4 -2
- package/lib/sinks/fs.js +0 -263
- package/lib/sinks/mem.js +0 -210
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.3.48](https://github.com/eik-lib/core/compare/v1.3.47...v1.3.48) (2024-07-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* migrate to using sink modules ([0101d50](https://github.com/eik-lib/core/commit/0101d502365e304baa5e5583e13c29ca7b345b67))
|
|
7
|
+
|
|
8
|
+
## [1.3.47](https://github.com/eik-lib/core/compare/v1.3.46...v1.3.47) (2024-07-06)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **deps:** update dependency rimraf to v5.0.8 ([daf2655](https://github.com/eik-lib/core/commit/daf26550d1d38d1b715c78213cde885e272a3893))
|
|
14
|
+
|
|
1
15
|
## [1.3.46](https://github.com/eik-lib/core/compare/v1.3.45...v1.3.46) (2024-07-03)
|
|
2
16
|
|
|
3
17
|
|
package/lib/main.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import FS from '@eik/sink-file-system';
|
|
2
|
+
import MEM from '@eik/sink-memory';
|
|
3
|
+
|
|
1
4
|
import VersionsGet from './handlers/versions.get.js';
|
|
2
5
|
import AliasPost from './handlers/alias.post.js';
|
|
3
6
|
import AliasPut from './handlers/alias.put.js';
|
|
@@ -11,8 +14,6 @@ import MapGet from './handlers/map.get.js';
|
|
|
11
14
|
import MapPut from './handlers/map.put.js';
|
|
12
15
|
|
|
13
16
|
import TEST from './sinks/test.js';
|
|
14
|
-
import MEM from './sinks/mem.js';
|
|
15
|
-
import FS from './sinks/fs.js';
|
|
16
17
|
|
|
17
18
|
import HealthCheck from './utils/healthcheck.js';
|
|
18
19
|
import globals from './utils/globals.js';
|
|
@@ -31,9 +32,23 @@ const http = {
|
|
|
31
32
|
MapPut,
|
|
32
33
|
};
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated The built-in sinks will be removed in a future version of core.
|
|
37
|
+
* Install the sink you want as a dependency and pass it as an option when constructing the Service.
|
|
38
|
+
* Ex: sink.MEM is replaced by eik/sink-memory. sink.FS is replaced by eik/sink-file-system.
|
|
39
|
+
*/
|
|
34
40
|
const sink = {
|
|
41
|
+
/**
|
|
42
|
+
* @deprecated Import eik/sink-memory or implement your own and pass it to the Service instead.
|
|
43
|
+
*/
|
|
35
44
|
TEST,
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated Import eik/sink-memory and pass it to the Service instead
|
|
47
|
+
*/
|
|
36
48
|
MEM,
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated Import eik/sink-file-system and pass it to the Service instead
|
|
51
|
+
*/
|
|
37
52
|
FS,
|
|
38
53
|
};
|
|
39
54
|
|
|
@@ -49,4 +64,4 @@ export default {
|
|
|
49
64
|
http,
|
|
50
65
|
sink,
|
|
51
66
|
prop,
|
|
52
|
-
}
|
|
67
|
+
};
|
package/lib/sinks/test.js
CHANGED
|
@@ -9,7 +9,10 @@ import Entry from './mem-entry.js';
|
|
|
9
9
|
|
|
10
10
|
const DEFAULT_ROOT_PATH = '/eik';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Use eik/sink-memory or implement your own. This class will be removed in a future version of core.
|
|
14
|
+
*/
|
|
15
|
+
export default class SinkTest extends Sink {
|
|
13
16
|
constructor({ rootPath = DEFAULT_ROOT_PATH } = {}) {
|
|
14
17
|
super();
|
|
15
18
|
this._rootPath = rootPath;
|
|
@@ -134,10 +137,10 @@ const SinkTest = class SinkTest extends Sink {
|
|
|
134
137
|
|
|
135
138
|
this._state.set(pathname, entry);
|
|
136
139
|
|
|
137
|
-
this._counter.inc({ labels: {
|
|
138
|
-
success: true,
|
|
139
|
-
access: true,
|
|
140
|
-
operation
|
|
140
|
+
this._counter.inc({ labels: {
|
|
141
|
+
success: true,
|
|
142
|
+
access: true,
|
|
143
|
+
operation
|
|
141
144
|
} });
|
|
142
145
|
});
|
|
143
146
|
|
|
@@ -189,10 +192,10 @@ const SinkTest = class SinkTest extends Sink {
|
|
|
189
192
|
});
|
|
190
193
|
|
|
191
194
|
file.stream.on('end', () => {
|
|
192
|
-
this._counter.inc({ labels: {
|
|
193
|
-
success: true,
|
|
194
|
-
access: true,
|
|
195
|
-
operation
|
|
195
|
+
this._counter.inc({ labels: {
|
|
196
|
+
success: true,
|
|
197
|
+
access: true,
|
|
198
|
+
operation
|
|
196
199
|
} });
|
|
197
200
|
});
|
|
198
201
|
|
|
@@ -227,10 +230,10 @@ const SinkTest = class SinkTest extends Sink {
|
|
|
227
230
|
}
|
|
228
231
|
});
|
|
229
232
|
|
|
230
|
-
this._counter.inc({ labels: {
|
|
231
|
-
success: true,
|
|
232
|
-
access: true,
|
|
233
|
-
operation
|
|
233
|
+
this._counter.inc({ labels: {
|
|
234
|
+
success: true,
|
|
235
|
+
access: true,
|
|
236
|
+
operation
|
|
234
237
|
} });
|
|
235
238
|
|
|
236
239
|
resolve();
|
|
@@ -257,10 +260,10 @@ const SinkTest = class SinkTest extends Sink {
|
|
|
257
260
|
return;
|
|
258
261
|
}
|
|
259
262
|
|
|
260
|
-
this._counter.inc({ labels: {
|
|
261
|
-
success: true,
|
|
262
|
-
access: true,
|
|
263
|
-
operation
|
|
263
|
+
this._counter.inc({ labels: {
|
|
264
|
+
success: true,
|
|
265
|
+
access: true,
|
|
266
|
+
operation
|
|
264
267
|
} });
|
|
265
268
|
|
|
266
269
|
if (this._state.has(pathname)) {
|
|
@@ -276,5 +279,3 @@ const SinkTest = class SinkTest extends Sink {
|
|
|
276
279
|
return 'SinkTest';
|
|
277
280
|
}
|
|
278
281
|
}
|
|
279
|
-
|
|
280
|
-
export default SinkTest;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eik/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.48",
|
|
4
4
|
"description": "Core server package",
|
|
5
5
|
"main": "lib/main.js",
|
|
6
6
|
"type": "module",
|
|
@@ -21,13 +21,15 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@eik/common": "3.0.1",
|
|
23
23
|
"@eik/sink": "1.2.1",
|
|
24
|
+
"@eik/sink-file-system": "1.0.1",
|
|
25
|
+
"@eik/sink-memory": "1.1.1",
|
|
24
26
|
"@metrics/client": "2.5.2",
|
|
25
27
|
"abslog": "2.4.4",
|
|
26
28
|
"busboy": "1.6.0",
|
|
27
29
|
"http-errors": "2.0.0",
|
|
28
30
|
"mime": "3.0.0",
|
|
29
31
|
"original-url": "1.2.3",
|
|
30
|
-
"rimraf": "5.0.
|
|
32
|
+
"rimraf": "5.0.8",
|
|
31
33
|
"semver": "7.6.2",
|
|
32
34
|
"ssri": "10.0.6",
|
|
33
35
|
"tar": "6.2.1",
|
package/lib/sinks/fs.js
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { ReadFile } from '@eik/common';
|
|
2
|
-
import { rimraf } from 'rimraf';
|
|
3
|
-
import Metrics from '@metrics/client';
|
|
4
|
-
import Sink from '@eik/sink';
|
|
5
|
-
import mime from 'mime';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import fs from 'node:fs';
|
|
8
|
-
|
|
9
|
-
import { etagFromFsStat } from '../utils/utils.js';
|
|
10
|
-
import conf from '../utils/defaults.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A sink for persisting files to local file system
|
|
14
|
-
*
|
|
15
|
-
* @class SinkFS
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const SinkFS = class SinkFS extends Sink {
|
|
19
|
-
constructor(config = {}) {
|
|
20
|
-
super();
|
|
21
|
-
this._config = { ...conf, ...config};
|
|
22
|
-
this._metrics = new Metrics();
|
|
23
|
-
this._counter = this._metrics.counter({
|
|
24
|
-
name: 'eik_core_sink_fs',
|
|
25
|
-
description: 'Counter measuring access to the file system storage sink',
|
|
26
|
-
labels: {
|
|
27
|
-
operation: 'n/a',
|
|
28
|
-
success: false,
|
|
29
|
-
access: false,
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get metrics() {
|
|
35
|
-
return this._metrics;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
write(filePath, contentType) {
|
|
39
|
-
return new Promise((resolve, reject) => {
|
|
40
|
-
const operation = 'write';
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
super.constructor.validateFilePath(filePath);
|
|
44
|
-
super.constructor.validateContentType(contentType);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
this._counter.inc({ labels: { operation } });
|
|
47
|
-
reject(error);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const pathname = path.join(this._config.sinkFsRootPath, filePath);
|
|
52
|
-
|
|
53
|
-
if (pathname.indexOf(this._config.sinkFsRootPath) !== 0) {
|
|
54
|
-
this._counter.inc({ labels: { operation } });
|
|
55
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const dir = path.dirname(pathname);
|
|
60
|
-
|
|
61
|
-
fs.mkdir(
|
|
62
|
-
dir,
|
|
63
|
-
{
|
|
64
|
-
recursive: true,
|
|
65
|
-
},
|
|
66
|
-
error => {
|
|
67
|
-
if (error) {
|
|
68
|
-
this._counter.inc({ labels: { access: true, operation } });
|
|
69
|
-
reject(
|
|
70
|
-
new Error(`Could not create directory - ${dir}`),
|
|
71
|
-
);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const stream = fs.createWriteStream(pathname, {
|
|
76
|
-
autoClose: true,
|
|
77
|
-
emitClose: true,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
this._counter.inc({ labels: {
|
|
81
|
-
success: true,
|
|
82
|
-
access: true,
|
|
83
|
-
operation
|
|
84
|
-
} });
|
|
85
|
-
|
|
86
|
-
resolve(stream);
|
|
87
|
-
},
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
read(filePath) {
|
|
93
|
-
return new Promise((resolve, reject) => {
|
|
94
|
-
const operation = 'read';
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
super.constructor.validateFilePath(filePath);
|
|
98
|
-
} catch (error) {
|
|
99
|
-
this._counter.inc({ labels: { operation } });
|
|
100
|
-
reject(error);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const pathname = path.join(this._config.sinkFsRootPath, filePath);
|
|
105
|
-
|
|
106
|
-
if (pathname.indexOf(this._config.sinkFsRootPath) !== 0) {
|
|
107
|
-
this._counter.inc({ labels: { operation } });
|
|
108
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const closeFd = fd => {
|
|
113
|
-
fs.close(fd, (error) => {
|
|
114
|
-
if (error) {
|
|
115
|
-
this._counter.inc({ labels: {
|
|
116
|
-
access: true,
|
|
117
|
-
operation
|
|
118
|
-
} });
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
this._counter.inc({ labels: {
|
|
122
|
-
success: true,
|
|
123
|
-
access: true,
|
|
124
|
-
operation
|
|
125
|
-
} });
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
fs.open(pathname, 'r', (error, fd) => {
|
|
130
|
-
if (error) {
|
|
131
|
-
this._counter.inc({ labels: {
|
|
132
|
-
access: true,
|
|
133
|
-
operation
|
|
134
|
-
} });
|
|
135
|
-
reject(error);
|
|
136
|
-
return;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
fs.fstat(fd, (err, stat) => {
|
|
140
|
-
if (err) {
|
|
141
|
-
closeFd(fd);
|
|
142
|
-
reject(err);
|
|
143
|
-
return;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
if (!stat.isFile()) {
|
|
147
|
-
closeFd(fd);
|
|
148
|
-
reject(new Error(`Not a file - ${pathname}`));
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const mimeType = mime.getType(pathname) || 'application/octet-stream';
|
|
153
|
-
const etag = etagFromFsStat(stat);
|
|
154
|
-
|
|
155
|
-
const obj = new ReadFile({
|
|
156
|
-
mimeType,
|
|
157
|
-
etag,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
obj.stream = fs.createReadStream(pathname, {
|
|
161
|
-
autoClose: true,
|
|
162
|
-
fd,
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
obj.stream.on('error', () => {
|
|
166
|
-
this._counter.inc({ labels: {
|
|
167
|
-
access: true,
|
|
168
|
-
operation
|
|
169
|
-
} });
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
obj.stream.on('end', () => {
|
|
173
|
-
this._counter.inc({ labels: {
|
|
174
|
-
success: true,
|
|
175
|
-
access: true,
|
|
176
|
-
operation
|
|
177
|
-
} });
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
resolve(obj);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
delete(filePath) {
|
|
188
|
-
return new Promise((resolve, reject) => {
|
|
189
|
-
const operation = 'delete';
|
|
190
|
-
|
|
191
|
-
try {
|
|
192
|
-
super.constructor.validateFilePath(filePath);
|
|
193
|
-
} catch (error) {
|
|
194
|
-
this._counter.inc({ labels: { operation } });
|
|
195
|
-
reject(error);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const pathname = path.join(this._config.sinkFsRootPath, filePath);
|
|
200
|
-
|
|
201
|
-
if (pathname.indexOf(this._config.sinkFsRootPath) !== 0) {
|
|
202
|
-
this._counter.inc({ labels: { operation } });
|
|
203
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
rimraf(pathname).then(() => {
|
|
208
|
-
this._counter.inc({ labels: {
|
|
209
|
-
success: true,
|
|
210
|
-
access: true,
|
|
211
|
-
operation
|
|
212
|
-
} });
|
|
213
|
-
resolve();
|
|
214
|
-
}).catch((error) => {
|
|
215
|
-
this._counter.inc({ labels: { access: true, operation } });
|
|
216
|
-
reject(error);
|
|
217
|
-
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
exist(filePath) {
|
|
223
|
-
return new Promise((resolve, reject) => {
|
|
224
|
-
const operation = 'exist';
|
|
225
|
-
|
|
226
|
-
try {
|
|
227
|
-
super.constructor.validateFilePath(filePath);
|
|
228
|
-
} catch (error) {
|
|
229
|
-
this._counter.inc({ labels: { operation } });
|
|
230
|
-
reject(error);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const pathname = path.join(this._config.sinkFsRootPath, filePath);
|
|
235
|
-
|
|
236
|
-
if (pathname.indexOf(this._config.sinkFsRootPath) !== 0) {
|
|
237
|
-
this._counter.inc({ labels: { operation } });
|
|
238
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
fs.stat(pathname, (error, stat) => {
|
|
243
|
-
this._counter.inc({ labels: { success: true, access: true, operation } });
|
|
244
|
-
|
|
245
|
-
if (stat && stat.isFile()) {
|
|
246
|
-
resolve();
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (error) {
|
|
251
|
-
reject(error);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
reject();
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
get [Symbol.toStringTag]() {
|
|
260
|
-
return 'SinkFS';
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
export default SinkFS;
|
package/lib/sinks/mem.js
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { Writable, Readable } from 'node:stream';
|
|
2
|
-
import { ReadFile } from '@eik/common';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import Metrics from '@metrics/client';
|
|
5
|
-
import Sink from '@eik/sink';
|
|
6
|
-
|
|
7
|
-
import Entry from './mem-entry.js';
|
|
8
|
-
|
|
9
|
-
const DEFAULT_ROOT_PATH = '/eik';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A sink for persisting files to memory
|
|
13
|
-
*
|
|
14
|
-
* @class SinkMem
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const SinkMem = class SinkMem extends Sink {
|
|
18
|
-
constructor({ rootPath = DEFAULT_ROOT_PATH } = {}) {
|
|
19
|
-
super();
|
|
20
|
-
this._rootPath = rootPath;
|
|
21
|
-
this._metrics = new Metrics();
|
|
22
|
-
this._counter = this._metrics.counter({
|
|
23
|
-
name: 'eik_core_sink_mem',
|
|
24
|
-
description: 'Counter measuring access to the in memory storage sink',
|
|
25
|
-
labels: {
|
|
26
|
-
operation: 'n/a',
|
|
27
|
-
success: false,
|
|
28
|
-
access: false,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
this._state = new Map();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get metrics() {
|
|
35
|
-
return this._metrics;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
write(filePath, contentType) {
|
|
39
|
-
return new Promise((resolve, reject) => {
|
|
40
|
-
const operation = 'write';
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
super.constructor.validateFilePath(filePath);
|
|
44
|
-
super.constructor.validateContentType(contentType);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
this._counter.inc({ labels: { operation } });
|
|
47
|
-
reject(error);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const pathname = join(this._rootPath, filePath);
|
|
52
|
-
|
|
53
|
-
if (pathname.indexOf(this._rootPath) !== 0) {
|
|
54
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
55
|
-
this._counter.inc({ labels: { operation } });
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const payload = [];
|
|
60
|
-
const stream = new Writable({
|
|
61
|
-
write(chunk, encoding, cb) {
|
|
62
|
-
payload.push(chunk);
|
|
63
|
-
cb();
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
stream.on('finish', () => {
|
|
68
|
-
const entry = new Entry({
|
|
69
|
-
mimeType: contentType,
|
|
70
|
-
payload
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
this._state.set(pathname, entry);
|
|
74
|
-
|
|
75
|
-
this._counter.inc({ labels: {
|
|
76
|
-
success: true,
|
|
77
|
-
access: true,
|
|
78
|
-
operation
|
|
79
|
-
} });
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
resolve(stream);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
read(filePath) {
|
|
87
|
-
return new Promise((resolve, reject) => {
|
|
88
|
-
const operation = 'read';
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
super.constructor.validateFilePath(filePath);
|
|
92
|
-
} catch (error) {
|
|
93
|
-
this._counter.inc({ labels: { operation } });
|
|
94
|
-
reject(error);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const pathname = join(this._rootPath, filePath);
|
|
99
|
-
|
|
100
|
-
if (pathname.indexOf(this._rootPath) !== 0) {
|
|
101
|
-
this._counter.inc({ labels: { operation } });
|
|
102
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const entry = this._state.get(pathname);
|
|
107
|
-
const payload = entry.payload || [];
|
|
108
|
-
const obj = new ReadFile( {
|
|
109
|
-
mimeType: entry.mimeType,
|
|
110
|
-
etag: entry.hash,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
obj.stream = new Readable({
|
|
114
|
-
read() {
|
|
115
|
-
payload.forEach(item => {
|
|
116
|
-
this.push(item);
|
|
117
|
-
});
|
|
118
|
-
this.push(null);
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
obj.stream.on('end', () => {
|
|
123
|
-
this._counter.inc({ labels: {
|
|
124
|
-
success: true,
|
|
125
|
-
access: true,
|
|
126
|
-
operation
|
|
127
|
-
} });
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
resolve(obj);
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
delete(filePath) {
|
|
135
|
-
return new Promise((resolve, reject) => {
|
|
136
|
-
const operation = 'delete';
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
super.constructor.validateFilePath(filePath);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
this._counter.inc({ labels: { operation } });
|
|
142
|
-
reject(error);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const pathname = join(this._rootPath, filePath);
|
|
147
|
-
|
|
148
|
-
if (pathname.indexOf(this._rootPath) !== 0) {
|
|
149
|
-
this._counter.inc({ labels: { operation } });
|
|
150
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Delete recursively
|
|
155
|
-
Array.from(this._state.keys()).forEach((key) => {
|
|
156
|
-
if (key.startsWith(pathname)) {
|
|
157
|
-
this._state.delete(key);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
this._counter.inc({ labels: {
|
|
162
|
-
success: true,
|
|
163
|
-
access: true,
|
|
164
|
-
operation
|
|
165
|
-
} });
|
|
166
|
-
|
|
167
|
-
resolve();
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
exist(filePath) {
|
|
172
|
-
return new Promise((resolve, reject) => {
|
|
173
|
-
const operation = 'exist';
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
super.constructor.validateFilePath(filePath);
|
|
177
|
-
} catch (error) {
|
|
178
|
-
this._counter.inc({ labels: { operation } });
|
|
179
|
-
reject(error);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const pathname = join(this._rootPath, filePath);
|
|
184
|
-
|
|
185
|
-
if (pathname.indexOf(this._rootPath) !== 0) {
|
|
186
|
-
this._counter.inc({ labels: { operation } });
|
|
187
|
-
reject(new Error(`Directory traversal - ${filePath}`));
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
this._counter.inc({ labels: {
|
|
192
|
-
success: true,
|
|
193
|
-
access: true,
|
|
194
|
-
operation
|
|
195
|
-
} });
|
|
196
|
-
|
|
197
|
-
if (this._state.has(pathname)) {
|
|
198
|
-
resolve();
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
reject(new Error('File does not exist'));
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
get [Symbol.toStringTag]() {
|
|
207
|
-
return 'SinkMEM';
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
export default SinkMem;
|