12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- 'use strict';
- const fs = require('fs');
- const path = require('path');
- const { promisify } = require('util');
- const { cppdb } = require('../util');
- const fsAccess = promisify(fs.access);
- module.exports = async function backup(filename, options) {
- if (options == null) options = {};
- // Validate arguments
- if (typeof filename !== 'string') throw new TypeError('Expected first argument to be a string');
- if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
- // Interpret options
- filename = filename.trim();
- const attachedName = 'attached' in options ? options.attached : 'main';
- const handler = 'progress' in options ? options.progress : null;
- // Validate interpreted options
- if (!filename) throw new TypeError('Backup filename cannot be an empty string');
- if (filename === ':memory:') throw new TypeError('Invalid backup filename ":memory:"');
- if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
- if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
- if (handler != null && typeof handler !== 'function') throw new TypeError('Expected the "progress" option to be a function');
- // Make sure the specified directory exists
- await fsAccess(path.dirname(filename)).catch(() => {
- throw new TypeError('Cannot save backup because the directory does not exist');
- });
- const isNewFile = await fsAccess(filename).then(() => false, () => true);
- return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null);
- };
- const runBackup = (backup, handler) => {
- let rate = 0;
- let useDefault = true;
- return new Promise((resolve, reject) => {
- setImmediate(function step() {
- try {
- const progress = backup.transfer(rate);
- if (!progress.remainingPages) {
- backup.close();
- resolve(progress);
- return;
- }
- if (useDefault) {
- useDefault = false;
- rate = 100;
- }
- if (handler) {
- const ret = handler(progress);
- if (ret !== undefined) {
- if (typeof ret === 'number' && ret === ret) rate = Math.max(0, Math.min(0x7fffffff, Math.round(ret)));
- else throw new TypeError('Expected progress callback to return a number or undefined');
- }
- }
- setImmediate(step);
- } catch (err) {
- backup.close();
- reject(err);
- }
- });
- });
- };
|