0

I have the following old parse2 code that I need to upgrade to parse4. I have the following snippet of original code: EDIT: realized it was using old request (requestLib). I have replaced that with axios and now am showing my changes::

var query = new Parse.Query(request.params.documentType);
query.equalTo('objectId', request.params.documentObjectId);
return query.first({ useMasterKey: true })
    .then(function (result) {

        if (!result) { return Promise.error('Sorry, this document is not available to be sent.'); }
        documentObject = result;

        return result
    })
    .then(function(result){

        if (useNewHTMLEmail) {
            if (p.type === undefined) {
                return console.log("type property must be defined for HTML template")
            }

            return Parse.Cloud.run("getEmail", {documentId: request.params.documentObjectId, type: p.type, text: baseMessage, documentType: p.documentType, customFields: p.customFields })
                .then(function(result) {
                    baseMessage = result;
                    return true;
                })
        }
        else {
            return Promise.resolve();
        }

    })
    .then(function (result) {

        if (p.appendPDF == true && documentObject.get('pdf') !== undefined) {

            var download = function (uri, filename, callback) {
                requestLib.head(uri, function (err, res, body) {
                    console.log('content-type:', res.headers['content-type']);
                    console.log('content-length:', res.headers['content-length']);

                    requestLib(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
                });
            };

            var url = documentObject.get('pdf').url();
            var parts = url.split("/");
            var lastSegment = parts.pop() || parts.pop();
            var promise = new Parse.Promise();
            download(url, lastSegment, function () {

                file = fs.readFileSync(lastSegment);
                promise.resolve(result);
            });
            return promise;
        }
        else {
            return Promise.resolve(result);
        }

    })

So far I have made the following changes:

var query = new Parse.Query(request.params.documentType);
query.equalTo('objectId', request.params.documentObjectId);
documentObject = await query.first({ useMasterKey: true });
if (documentObject === undefined){
    throw new Error("Bad document in sendMail");
}

if (useNewHTMLEmail) {
    if (p.type === undefined) {
        throw new Error("type property must be defined for HTML template")
    }

    baseMessage = await  Parse.Cloud.run("getEmail", {documentId: request.params.documentObjectId, type: p.type, text: baseMessage, documentType: p.documentType, customFields: p.customFields })

}

The next section is where I get confused using callbacks and async await. Here is my attempt with Axios:

var url = documentObject.get('pdf').url();
    var parts = url.split("/");
    var lastSegment = parts.pop() || parts.pop();

    axios({
        method: 'get',
        url: url,
        responseType:'stream'
    })
        .then(res => {
            res.data.pipe(fs.createWriteStream(lastSegment));
        })
        .catch(err => console.log(err));

How do I translate this portion now:

var promise = new Parse.Promise();
    download(url, lastSegment, function () {

        file = fs.readFileSync(lastSegment);
        promise.resolve(result);
    });

EDIT: Why doesn't this pass through:

    var writeStream = fs.createWriteStream(lastSegment);

    await new Promise(async (resolve) => {
        const response = await axios({
            method: "GET",
            url: url,
            responseType: "stream"
        });
        response.data.pipe(writeStream);
        writeStream.on('error', function (err) {
            console.log(err);
        });
    });

    file =  fs.readFileSync(lastSegment); <=== never gets executed.

Thanks

jimijon
  • 2,046
  • 1
  • 20
  • 39
  • You should remove your `else { return; }` entirely. In the context of a `Promise.then(...)` chain, it's used to keep going, but here, you really just want to execute what's in the next `then`s – blex Jun 22 '20 at 19:22
  • Where are `documentObject` and `baseMessage` declared? – Bergi Jun 22 '20 at 19:24

2 Answers2

2

What do I replace Promise.resolve() with?

Nothing. The return Promise.resolve() does nothing in a then callback, in fact it could have been omitted even there.

Or, the "return promise"?

You'll need to construct and await a new Promise for the download. But you'd probably want to modernise that function as well, getting rid of the readFileSync and altogether replacing requestLib with something that returns a promise instead of a stream.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • got any recommendations... I would prefer to modernize everything. hence the project to go from parse2 to parse4 – jimijon Jun 22 '20 at 20:42
  • I can't recommend anything since I don't know what your original `requestLib` does. – Bergi Jun 22 '20 at 21:08
  • well that was a good hint. I inherited this project. It turns out that is old request npm, so I am now adding axios to replace it. – jimijon Jun 22 '20 at 21:54
  • Yeah, axios, request-promise, something fetch-api-based, whatever suits you :-) – Bergi Jun 22 '20 at 21:57
  • can you look at my edit.. I am now trying to figure out how to handle the "file = fs.readFileSync(lastSegment); " where does that go? – jimijon Jun 22 '20 at 21:59
  • I wouldn't do that at all, writing the response to the HTTP request into a file and then reading it back - why not just read the response in a buffer directly? But if you really need it in the filesystem, you can `pipeline` it there, wait for that to finish, and use `readFile` to read it back asynchronously. Use `util.promisify` and `await` them. Btw, also for your axios request you should use `await` rather than `then`. – Bergi Jun 23 '20 at 08:55
  • please review my last edit on the bottom... why doesn't it pass through? thanks – jimijon Jun 23 '20 at 16:39
  • @jimijon Because you never call `resolve`. Also [you shouldn't pass an `async function` as the executor to `new Promise`](https://stackoverflow.com/q/43036229/1048572) - move the `const response = await axios({…});` outside of the promise that waits for the stream. – Bergi Jun 23 '20 at 16:42
0

This worked:

var writeStream = fs.createWriteStream(lastSegment);

    console.log("start axios");
    const response = await axios({
        method: "GET",
        url: url,
        responseType: "stream"
    });

    response.data.pipe(writeStream);
    writeStream.on('error', function (err) {
        console.log(err);
    });

    file =  fs.readFileSync(lastSegment);
jimijon
  • 2,046
  • 1
  • 20
  • 39