const crypto = require('crypto'); const fse = require('fs-extra'); const isArrayBuffer = require('lodash/isArrayBuffer'); const isString = require('lodash/isString'); const path = require('path'); const toArrayBuffer = require('to-arraybuffer'); const PATH = 'attachments.noindex'; // getPath :: AbsolutePath -> AbsolutePath exports.getPath = (userDataPath) => { if (!isString(userDataPath)) { throw new TypeError('`userDataPath` must be a string'); } return path.join(userDataPath, PATH); }; // ensureDirectory :: AbsolutePath -> IO Unit exports.ensureDirectory = async (userDataPath) => { if (!isString(userDataPath)) { throw new TypeError('`userDataPath` must be a string'); } await fse.ensureDir(exports.getPath(userDataPath)); }; // readData :: AttachmentsPath -> // RelativePath -> // IO (Promise ArrayBuffer) exports.readData = (root) => { if (!isString(root)) { throw new TypeError('`root` must be a path'); } return async (relativePath) => { if (!isString(relativePath)) { throw new TypeError('`relativePath` must be a string'); } const absolutePath = path.join(root, relativePath); const buffer = await fse.readFile(absolutePath); return toArrayBuffer(buffer); }; }; // writeData :: AttachmentsPath -> // ArrayBuffer -> // IO (Promise RelativePath) exports.writeData = (root) => { if (!isString(root)) { throw new TypeError('`root` must be a path'); } return async (arrayBuffer) => { if (!isArrayBuffer(arrayBuffer)) { throw new TypeError('`arrayBuffer` must be an array buffer'); } const buffer = Buffer.from(arrayBuffer); const name = exports.createName(); const relativePath = exports.getRelativePath(name); const absolutePath = path.join(root, relativePath); await fse.ensureFile(absolutePath); await fse.writeFile(absolutePath, buffer); return relativePath; }; }; // deleteData :: AttachmentsPath -> IO Unit exports.deleteData = (root) => { if (!isString(root)) { throw new TypeError('`root` must be a path'); } return async (relativePath) => { if (!isString(relativePath)) { throw new TypeError('`relativePath` must be a string'); } const absolutePath = path.join(root, relativePath); await fse.remove(absolutePath); }; }; // createName :: Unit -> IO String exports.createName = () => { const buffer = crypto.randomBytes(32); return buffer.toString('hex'); }; // getRelativePath :: String -> IO Path exports.getRelativePath = (name) => { if (!isString(name)) { throw new TypeError('`name` must be a string'); } const prefix = name.slice(0, 2); return path.join(prefix, name); };