-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace callbacks with promises #12
base: master
Are you sure you want to change the base?
Changes from 5 commits
e4ccff5
378d48b
a7af150
e2df1b5
edc7249
98423e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
'use strict'; | ||
|
||
// TODO: this file should be removed and `fs.promises` used instead | ||
// when support for Node.js 8 is dropped | ||
|
||
const fs = require('fs'); | ||
const { promisify } = require('util'); | ||
|
||
const { iter } = require('@metarhia/common'); | ||
|
||
const list = [ | ||
'readFile', | ||
'writeFile', | ||
'unlink', | ||
'rename', | ||
'stat', | ||
'access', | ||
'mkdir', | ||
'rmdir', | ||
'readdir', | ||
]; | ||
|
||
if (fs.promises) { | ||
module.exports = fs.promises; | ||
} else { | ||
module.exports = iter(list).collectWith( | ||
{}, | ||
(obj, name) => (obj[name] = promisify(fs[name])) | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const fs = require('./fs'); | ||
const path = require('path'); | ||
const crypto = require('crypto'); | ||
const { crc32 } = require('crc'); | ||
const util = require('util'); | ||
const common = require('@metarhia/common'); | ||
const { zip, gzip } = require('compressing'); | ||
const metasync = require('metasync'); | ||
|
||
const CHECKSUM = 'CRC32'; | ||
const DEDUP_HASH = 'SHA256'; | ||
|
@@ -28,32 +29,6 @@ const FS_EXT = 'f'; | |
|
||
const getFilepath = (...parts) => `${path.join(...parts)}.${FS_EXT}`; | ||
|
||
const rmdirp = (dir, cb) => { | ||
fs.stat(dir, (err, stats) => { | ||
if (err) { | ||
if (err.code === 'ENOENT') cb(null); | ||
else cb(err); | ||
return; | ||
} | ||
|
||
if (stats.isDirectory()) { | ||
fs.readdir(dir, (err, files) => { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
files = files.map(file => path.join(dir, file)); | ||
metasync.each(files, rmdirp, err => { | ||
if (err) cb(err); | ||
else fs.rmdir(dir, cb); | ||
}); | ||
}); | ||
} else { | ||
fs.unlink(dir, cb); | ||
} | ||
}); | ||
}; | ||
|
||
const computeHash = (data, checksum) => { | ||
const hasher = hashers[checksum]; | ||
if (!hasher) { | ||
|
@@ -68,45 +43,40 @@ const getDataStats = (data, checksum, dedupHash) => ({ | |
size: Buffer.byteLength(data), | ||
}); | ||
|
||
const compress = (file, minCompressSize, compression, cb) => { | ||
fs.stat(file, (err, stats) => { | ||
if (err || stats.size <= minCompressSize) { | ||
cb(err, false); | ||
return; | ||
} | ||
const filec = file + 'z'; | ||
const compressor = compressors[compression]; | ||
if (!compressor) { | ||
throw new Error(`Unknown compression type ${compression} specified`); | ||
} | ||
compressor | ||
.compressFile(file, filec) | ||
.then(() => | ||
fs.rename(filec, file, err => { | ||
if (err) cb(err, false); | ||
else cb(null, true); | ||
}) | ||
) | ||
.catch(err => cb(err, false)); | ||
}); | ||
const compress = async (file, minCompressSize, compression) => { | ||
const compressor = compressors[compression]; | ||
lundibundi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!compressor) { | ||
throw new Error(`Unknown compression type ${compression} specified`); | ||
} | ||
|
||
const stats = await fs.stat(file); | ||
if (stats.size <= minCompressSize) return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated to this PR, but: Now that I think of it, wouldn't this lead for the user of Filestorage to a need to keep a map of compressed/uncompressed files? Because without such map if someone calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea was that metadata including file name, hash sum, deduplication hash, compression type etc. will be stored in the DB. I don't see a problem with the need for such a map since you already have to store files compression types somewhere. |
||
|
||
const filec = file + 'z'; | ||
await compressor.compressFile(file, filec); | ||
await fs.rename(filec, file); | ||
return true; | ||
}; | ||
|
||
const uncompress = (file, opts, cb) => { | ||
fs.access(file, err => { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
const compressor = compressors[opts.compression]; | ||
if (!compressor) { | ||
throw new Error(`Unknown compression type ${opts.compression} specified`); | ||
} | ||
const uncompress = async (file, opts) => { | ||
const compressor = compressors[opts.compression]; | ||
if (!compressor) { | ||
throw new Error(`Unknown compression type ${opts.compression} specified`); | ||
} | ||
|
||
if (opts.compression === 'GZIP') { | ||
const memoryStream = new common.MemoryWritable(); | ||
compressor.uncompress(file, memoryStream); | ||
return memoryStream.getData(opts.encoding); | ||
} | ||
|
||
return new Promise((resolve, reject) => { | ||
const buffers = []; | ||
new compressor.UncompressStream({ source: file }) | ||
.on('error', cb) | ||
.on('finish', () => { | ||
if (opts.encoding) cb(null, buffers.join()); | ||
else cb(null, Buffer.concat(buffers)); | ||
.once('error', reject) | ||
.once('finish', () => { | ||
if (opts.encoding) resolve(buffers.join('')); | ||
else resolve(Buffer.concat(buffers)); | ||
}) | ||
.on('entry', (header, stream, next) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that this will work with gzip stream, since it doesn't emit
Also, I think, you should just use the newly added common.MemoryWritable here. |
||
if (opts.encoding) stream.setEncoding(opts.encoding); | ||
|
@@ -120,7 +90,7 @@ module.exports = { | |
getFilepath, | ||
computeHash, | ||
getDataStats, | ||
rmdirp, | ||
compress, | ||
uncompress, | ||
mkdirpPromise: util.promisify(common.mkdirp), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It returns a Promise, since it is an AsyncFunction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but we need to somehow specify what this promise resolves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SemenchenkoVitaliy we don't have a special syntax in
metadoc
for that, at the moment most of the projects just specify the return value asPromise
without providing any info on what value it resolves with (except for the function's description above), so I think you can either add some syntax for that inmetadoc
, or leave out the details on what this promise resolves with. But you still have to specify the correct return type, which isPromise
, notObject
.