Skip to content

Commit 0665bc1

Browse files
committed
fix(backup): Fixed weirdness with streams
refs: TryGhost/Toolbox#334 refs: #468 - the old streams wiring didn't handle the 404 error - my previous attempt at changing the stream code hung on success instead - this is more modern code, but works on node 12 for both the success and failure case
1 parent fa46ccf commit 0665bc1

File tree

2 files changed

+35
-33
lines changed

2 files changed

+35
-33
lines changed

lib/tasks/import/api.js

+30-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ const semver = require('semver');
55
const FormData = require('form-data');
66
const {Cookie} = require('tough-cookie');
77

8+
const {promisify} = require('util');
9+
const stream = require('stream');
10+
const pipeline = promisify(stream.pipeline);
11+
const fsp = require('fs').promises;
12+
813
const {SystemError} = require('../../errors');
914

1015
const bases = {
@@ -15,6 +20,16 @@ const bases = {
1520
5: '/ghost/api/admin'
1621
};
1722

23+
function streamFile(url, options, filePath) {
24+
return pipeline(
25+
got.stream(url, {...options}),
26+
fs.createWriteStream(filePath)
27+
).catch((err) => {
28+
fsp.unlink(filePath);
29+
throw err;
30+
});
31+
}
32+
1833
function getBaseUrl(version, url) {
1934
const basePath = bases[semver.major(version)];
2035

@@ -128,26 +143,27 @@ async function runImport(version, url, auth, exportFile) {
128143

129144
async function downloadContentExport(version, url, auth, outputFile) {
130145
const authOpts = await getAuthOpts(version, url, auth);
146+
let endpoint = '/db/';
131147

132-
await new Promise((resolve, reject) => {
133-
const ws = fs.createWriteStream(outputFile);
134-
const resp = got.stream('/db/', {...authOpts}).pipe(ws);
135-
136-
resp.on('finish', () => resolve()).on('error', reject);
137-
});
148+
await streamFile(endpoint, authOpts, outputFile);
138149
}
139150

140151
async function downloadMembersExport(version, url, auth, outputFile) {
141152
const authOpts = await getAuthOpts(version, url, auth);
153+
let endpoint = '/members/upload/';
142154

143-
await new Promise((resolve, reject) => {
144-
const ws = fs.createWriteStream(outputFile);
145-
got
146-
.stream('/members/upload/', {...authOpts})
147-
.on('finish', () => resolve())
148-
.on('error', reject)
149-
.pipe(ws);
150-
});
155+
if (semver.lt(version, '3.20.0')) {
156+
endpoint = '/members/csv/';
157+
}
158+
159+
try {
160+
await streamFile(endpoint, authOpts, outputFile);
161+
} catch (error) {
162+
// Members endpoint may not exist, we can ignore this
163+
if (error.statusCode !== 404) {
164+
throw error;
165+
}
166+
}
151167
}
152168

153169
module.exports = {

lib/tasks/import/tasks.js

+5-19
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,6 @@ async function importTask(ui, instance, exportFile) {
4040
}], false);
4141
}
4242

43-
async function tryMembersDownload(version, url, authData, membersFile) {
44-
try {
45-
await downloadMembersExport(version, url, authData, membersFile);
46-
} catch (error) {
47-
// Members endpoint may not exist, we can ignore this
48-
if (!error.statusCode === 404) {
49-
throw error;
50-
}
51-
}
52-
}
53-
5443
async function exportTask(ui, instance, contentFile, membersFile) {
5544
const url = instance.config.get('url');
5645

@@ -61,14 +50,11 @@ async function exportTask(ui, instance, contentFile, membersFile) {
6150

6251
const authData = await ui.prompt(authPrompts);
6352

64-
return ui.listr([{
65-
title: 'Exporting content',
66-
task: () => downloadContentExport(instance.version, url, authData, contentFile)
67-
}, {
68-
title: 'Exporting members',
69-
task: () => tryMembersDownload(instance.version, url, authData, membersFile),
70-
enabled: () => !!membersFile
71-
}], false);
53+
await downloadContentExport(instance.version, url, authData, contentFile);
54+
55+
if (membersFile) {
56+
await downloadMembersExport(instance.version, url, authData, membersFile);
57+
}
7258
}
7359

7460
module.exports = {

0 commit comments

Comments
 (0)