Get file buffer using Google Drive API and async/await - node.js

I'm trying to get the buffer of some drive pdf files so I can parse it and use the data.
I've managed to get the file names and id using async/await and a "drive.files.list" wrapped with promise. Now I need to use the file ids to get the buffer and then read it.
The function I need should return a promise that I can wait (using await) to be fulfilled to get a buffer. (My parser works fine when I get pdf buffer from website responses)
function getBuffer(drive, file) {
return new Promise((resolve, reject) => {
/////Google Auth
var jwToken = new google.auth.JWT(
key.client_email,
null,
key.private_key, ["https://www.googleapis.com/auth/drive"],
null
);
jwToken.authorize((authErr) => {
if (authErr) {
return reject([false, "Auth Error: " + authErr]);
}
});
drive.files.get({
auth: jwToken,
fileId: file.id,
alt: 'media',
supportsAllDrives: true
}, function (err, res) {
if (err) {
return reject('The API returned an error: ' + err);
};
console.log(res);
const buffer = res;
resolve(buffer);
});
});
}
And I use it this way:
var buffer = await getBuffer(drive,files[i]);
The output I get in "console.log(res)" is something like this:
...
��M�7�|�ı�[��Ξ�A����EBS]��P��r�����j�3�|�I.��i�+ϢKU���U�:[�═�,^߻t덲�v��=}'*8���ѻ��#ғ�s��No��-��q8E9�/f� �(�`�j'3
"╚�-��� ������[jp&��╚k��M��vy� In�:a�զ�OlN��u����6�n���q�/Y�i4�?&%��q�,��p╚.ZV&n�Ɨ��2G������X����Y
D],�ggb�&�N���G����NS�Lח\U�^R|_f<��f*�|��]�{�3�-P�~�CS��t��>g�Y��#�#7Wjۋ╗=�5�����#ջ���5]>}&v�╝═�wg��eV�^>�#�{��Ѿ��ޤ��>O�� z�?{8Ij�0╗B�.�Cjm�4������║��m�,╗�������O���fS��ӂcE��g�3(�G��}d^O������7����|�
H�N��;
{��x�bȠ�׮�i]=���~��=��ٟ<��C��
wi��'a�-��p═M�6o��ϴ��ve��+��'
...
And when I try to use the parser (pdf2json) I get this error:
"An error occurred while parsing the PDF: stream must have data"
Thanks in advance :D

You want to download a file from Google Drive.
You want to convert the downloaded data to the buffer.
You have already been able to download files from Google Drive using googleapis with Node.js.
If my understanding is correct, how about this modification? In this modification, the file is downloaded as the stream type and the data is converted to the buffer.
Modified script:
From:
drive.files.get({
auth: jwToken,
fileId: file.id,
alt: 'media',
supportsAllDrives: true
}, function (err, res) {
if (err) {
return reject('The API returned an error: ' + err);
};
console.log(res);
const buffer = res;
resolve(buffer);
});
To:
drive.files.get(
{
auth: jwToken,
fileId: file.id,
alt: "media",
supportsAllDrives: true
},
{ responseType: "stream" },
function(err, { data }) {
if (err) {
return reject("The API returned an error: " + err);
}
let buf = [];
data.on("data", function(e) {
buf.push(e);
});
data.on("end", function() {
const buffer = Buffer.concat(buf);
console.log(buffer);
// fs.writeFile("filename", buffer, err => console.log(err)); // For testing
resolve(buffer);
});
}
);
Note:
As a test case, I could confirm that when buffer is saved to a file using fs.writeFile("filename", buffer, err => console.log(err));, the downloaded file can be created.
Reference:
google-api-nodejs-client
If I misunderstood your question and this was not the direction you want, I apologize.

Related

how to set up node js server to handle resumable file downloads

After i upload a file to my google drive, i am saving the information about it in the database and when someone wants to download that particular file, the only information needed to be provided is the id of the saved file in the database.
The sample code below is working very well but the only problem is that when there is an internet connection problem the file downloading process is terminated and when the user try to assume the download, the file download will start afresh.
Note: When requesting a file from google drive, i can also provide ranges but i don't know how to know when the client is requesting for a partial file so that i can include them in the request. My english is bad but i hope my question is understood
app.get("/download", async (req, res) => {
try {
const fileId = req.query.file;
if (!fileId) return res.status(400).json({ msg: "file is needed" });
const file = await File.findById(fileId);
if (!file) return res.status(404).json({ msg: "not found" });
const title = file.title
.replace(/[-&\/\\#, +()$~%.'":*?<>{}]/g, " ")
.trim();
const ext = file.file_type == "audio" ? ".mp3" : ".mp4";
const resp = await drive.files.get(
{
fileId: file.file_id,
alt: "media",
},
{ responseType: "stream" }
);
res.set({
"Content-Length": file.file_size,
"Content-Disposition": `attachment; filename=${title}${ext}`,
});
resp.data.pipe(res);
} catch (error) {
console.log(error.message);
res.status(500).send("something went wrong");
}
})

Google drive API downloading file nodejs

Im trying to get the contents of a file using the google drive API v3 in node.js.
I read in this documentation I get a stream back from drive.files.get({fileId, alt: 'media'})but that isn't the case. I get a promise back.
https://developers.google.com/drive/api/v3/manage-downloads
Can someone tell me how I can get a stream from that method?
I believe your goal and situation as follows.
You want to retrieve the steam type from the method of drive.files.get.
You want to achieve this using googleapis with Node.js.
You have already done the authorization process for using Drive API.
For this, how about this answer? In this case, please use responseType. Ref
Pattern 1:
In this pattern, the file is downloaded as the stream type and it is saved as a file.
Sample script:
var dest = fs.createWriteStream("###"); // Please set the filename of the saved file.
drive.files.get(
{fileId: id, alt: "media"},
{responseType: "stream"},
(err, {data}) => {
if (err) {
console.log(err);
return;
}
data
.on("end", () => console.log("Done."))
.on("error", (err) => {
console.log(err);
return process.exit();
})
.pipe(dest);
}
);
Pattern 2:
In this pattern, the file is downloaded as the stream type and it is put to the buffer.
Sample script:
drive.files.get(
{fileId: id, alt: "media",},
{responseType: "stream"},
(err, { data }) => {
if (err) {
console.log(err);
return;
}
let buf = [];
data.on("data", (e) => buf.push(e));
data.on("end", () => {
const buffer = Buffer.concat(buf);
console.log(buffer);
});
}
);
Reference:
Google APIs Node.js Client

trying to convert docx into pdf on s3 using cloudconvert-api in nodejs

I am trying to convert docx file to pdf while uploading on s3 spaces using cloudconvert api in nodejs.
When I run my code, it is uploading docx file but the conversion is not happening and it is not giving any errors also.
I don't understand what i am doing wrong.
Here is my code bellow.
app.post('/upload/file', upload.single('file'), (req, res) => {
cloudconvert.createProcess(
{ inputformat: 'docx', outputformat: 'pdf' },
(err, process) => {
if (err) {
console.error(`CloudConvert Process creation failed: ${err}`)
} else {
process.start({
input: {
s3: {
accesskeyid: SPACES_ACCESS_KEY_ID,
secretaccesskey: SPACES_SECRET_ACCESS_KEY,
bucket: 'files'
}
},
file: req.file.key,
outputformat: 'pdf',
output: {
s3: {
accesskeyid: SPACES_ACCESS_KEY_ID,
secretaccesskey: SPACES_SECRET_ACCESS_KEY,
bucket: 'files'
}
}
}, (err, process) => {
if(err) return console.log(err.message)
console.log('process', process)
})
}
}
)
})
I am using multer to handle multipart form-data.
while I am trying to run the code it is not showing any errors and didn't convert the file into pdf.
Please let me know what I am doing wrong.
Thank you.
Hi I had the same issue and I am not an expert but something that you could do to fix the problem is put this code inside a promise, so you will wait until the conversion process finishes, here you could find an example
inputformat is the extension of your file
outputformat you desired extension
params the require parameters to process and save the file
return new Promise((resolve, reject) => {
response = cloudconvert.createProcess({inputformat: inputformat,
outputformat: outputformat},
function(error, process){
process.start(params, function(error, process) {
if (error){
reject({"status": "error" , "message": error})
} else {
process.wait(function(error, process){
if (error){
reject({status: "error", "error": error})
} else {
console.log(process.data.message)
resolve({"status": "ok" ,
"message": "process complete"})
}
});
}
});
});
});
hope this help you, the idea is that you can ensure you are getting and completing the conversion process

Node js to wait till the response comes

copy_deliverable_script_tomaster(args.Software_name.value,function(state){
res.end("added")
}
)
function copy_deliverable_script_tomaster(software_name,callback){
client.scp('./Temporary_software_files/folder/', {
host: 'ip',
username: 'centos',
privateKey: String(require("fs").readFileSync('./foreman_keypairs/coe-
central.pem')),
path: '/home/centos/Software_with_files/'+software_name
}, function(err,response) {
if(err){
console.log(err)
}
else{
console.log("after copy in master")
return callback(response);
}
})
}
I have used the above code, to copy large files to the remote machine.
Copying file continues in the remote machine, but the response("no content")comes before copy completes.
console.log("after copy in master"), will be printed only after the copy is completed.
Unable to get the response.
Instead of res.end use res.send("added"); or res.write('Added'); res.end();,
Because you have ended response without writing anything.
copy_deliverable_script_tomaster(args.Software_name.value, function (state) {
res.send("added")
})
You are not handling the error case. If you are not doing anything inside callback of client.scp then just pass the callback.
copy_deliverable_script_tomaster(args.Software_name.value, function (err,state) {
if(err) return res.status(400).send(err);
return res.send("some response")
})
function copy_deliverable_script_tomaster(software_name, callback) {
client.scp('./Temporary_software_files/folder/', {
host: 'ip',
username: 'centos',
privateKey: String(require("fs").readFileSync('./foreman_keypairs/coe-central.pem')),
path: '/home/centos/Software_with_files/' + software_name
}, callback)
}

Nodejs is not receiving any code from Flask app.

I am really new in node js and a little bit more experienced in flaks. I am trying to connect a nodejs backend with a flask api. Basically I am sending a file that was uploaded in the nodejs app for processing (converting to another format) to my flask app.
For sending the data I am using request. In this way:
app.post('/converttest', uploader.single('file'), function(req,res){
var file = req.file,
result = {
error: 0,
uploaded: []
};
flow.exec(
function() { // Read temp File
fs.readFile(file.path, this);
},
function(err, data) { // Upload file to S3
var formData = {
file: data,
};
requestPack.post({url:'http://127.0.0.1:5000/api/resource/converter', formData: formData});
},
function(err, httpResponse, body) { //Upload Callback
if (err) {
return console.error('upload failed:', err);
}
res.redirect('/console');
});
});
Then I am receiving the file for processing in the flask app, like:
#app.route('/api/resource/converter', methods = ['POST','GET'])
def converter_csv():
if request.method == 'POST':
f = request.form['file']
if not f:
abort(400)
print('-----Converting-------')
file = open("temp/converting.txt","w")
file.write(f)
#....conversion process...
# Finish the process
return Response(converted_file,status=200)
In my console for the localhost of the flask app, I am getting:
127.0.0.1 - - [09/Aug/2017 15:47:59] "POST /api/resource/converter HTTP/1.1" 200 -
However my nodejs app did not receive any response. It just got frozen.
I appreciate any orientation anyone can give me. Thanks.
I think flow.exec is not in proper order
router.post('/converttest', uploader.single('file'), function(req, res) {
var filePath = req.file.path;
fs.readFile(filePath, 'utf8', function(err, data) { //change format reading as required
try {
formData = {file:data}
requestPack.post({url:'http://127.0.0.1:5000/api/resource/converter', formData: formData});
} catch(err) {
return console.error('upload failed:', err);
res.redirect('/console')
}
fs.unlink(filePath);}); });
I ended up using requestify. Seems like they make it a little bit easier for beginners like me:
var requestify = require('requestify');
app.get('/convertupload', function(req,res){
res.render('pages/convertupload');
});
app.post('/converttest', uploader.single('file'), function(req,res){
var file = req.file,
result = {
error: 0,
uploaded: []
};
flow.exec(
function() { // Read temp File
fs.readFile(file.path,this);
},
function(err, data) { // Upload file to S3
var formData = {
file: data
};
requestify.post('http://127.0.0.1:5000/api/resource/converter', {
form: formData
})
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
console.log(response)
response.getBody();
});
res.redirect('/login');
});
});

Resources