1 | const { extname } = require('path');
|
2 | const Proto = require('uberproto');
|
3 | const errors = require('@feathersjs/errors');
|
4 |
|
5 | const {
|
6 | getBase64DataURI,
|
7 | parseDataURI
|
8 | } = require('dauria');
|
9 |
|
10 | const toBuffer = require('concat-stream');
|
11 | const mimeTypes = require('mime-types');
|
12 |
|
13 | const {
|
14 | fromBuffer,
|
15 | bufferToHash
|
16 | } = require('./util');
|
17 |
|
18 | class Service {
|
19 | constructor (options) {
|
20 | if (!options) {
|
21 | throw new Error('feathers-blob-store: constructor `options` must be provided');
|
22 | }
|
23 |
|
24 | if (!options.Model) {
|
25 | throw new Error('feathers-blob-store: constructor `options.Model` must be provided');
|
26 | }
|
27 |
|
28 | this.Model = options.Model;
|
29 | this.id = options.id || 'id';
|
30 | this.unique = options.unique || false;
|
31 | }
|
32 |
|
33 | extend (obj) {
|
34 | return Proto.extend(obj, this);
|
35 | }
|
36 |
|
37 | get (id, params = {}) {
|
38 | const ext = extname(id);
|
39 | const contentType = mimeTypes.lookup(ext);
|
40 |
|
41 | return new Promise((resolve, reject) => {
|
42 | this.Model.createReadStream({
|
43 | key: id,
|
44 | params: params.s3
|
45 | })
|
46 | .on('error', reject)
|
47 | .pipe(toBuffer(buffer => {
|
48 | const uri = getBase64DataURI(buffer, contentType);
|
49 |
|
50 | resolve({
|
51 | [this.id]: id,
|
52 | uri,
|
53 | size: buffer.length
|
54 | });
|
55 | }));
|
56 | });
|
57 | }
|
58 |
|
59 | create (body, params = {}) {
|
60 | let { id, uri, buffer, contentType } = body;
|
61 | if (uri) {
|
62 | const result = parseDataURI(uri);
|
63 | contentType = result.MIME;
|
64 | buffer = result.buffer;
|
65 | } else {
|
66 | uri = getBase64DataURI(buffer, contentType);
|
67 | }
|
68 | if (!uri || !buffer || !contentType) {
|
69 | throw new errors.BadRequest('Buffer or URI with valid content type must be provided to create a blob');
|
70 | }
|
71 | const hash = bufferToHash(buffer);
|
72 | const ext = mimeTypes.extension(contentType);
|
73 |
|
74 | id = id || `${hash}.${( this.unique ? (Math.random() * Date.now() * 500): '')}.${ext}`;
|
75 |
|
76 | return new Promise((resolve, reject) => {
|
77 | fromBuffer(buffer)
|
78 | .pipe(this.Model.createWriteStream({
|
79 | key: id,
|
80 | params: params.s3
|
81 | }, (error) =>
|
82 | error
|
83 | ? reject(error)
|
84 | : resolve({
|
85 | [this.id]: id,
|
86 | uri,
|
87 | size: buffer.length
|
88 | })
|
89 | ))
|
90 | .on('error', reject);
|
91 | });
|
92 | }
|
93 |
|
94 | remove (id) {
|
95 | return new Promise((resolve, reject) => {
|
96 | this.Model.remove({
|
97 | key: id
|
98 | }, error => error ? reject(error) : resolve({ [this.id]: id }));
|
99 | });
|
100 | }
|
101 | }
|
102 |
|
103 | module.exports = function init (options) {
|
104 | return new Service(options);
|
105 | };
|
106 |
|
107 | module.exports.Service = Service;
|