Reputation: 10930
I'm trying to get permanent download URLs when I upload files to Firebase Storage (Google Cloud Storage) from Firebase Cloud Functions (Google Cloud Functions).
I tried setting predefinedAcl
to authenticatedRead
and to publicRead
. Both resulted in 403 (Forbidden)
errors when my app tried to download the files. This is from the documentation for CreateWriteStreamOptions. Here's the code:
const {Storage} = require('@google-cloud/storage');
const storage = new Storage({ projectId: 'languagetwo-cd94d' });
const myBucket = storage.bucket('languagetwo-cd94d.appspot.com');
var mp3Promise = new Promise(function(resolve, reject) {
let options = {
metadata: {
contentType: 'audio/mp3',
public: true
}
};
synthesizeParams.accept = 'audio/mp3';
var file = myBucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3');
textToSpeech.synthesize(synthesizeParams)
.then(function(audio) {
audio.pipe(file.createWriteStream(options));
})
.then(function() {
resolve('http://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3');
})
.catch(error => console.error(error));
});
That code executes without an error, writes the file to Storage, and passes the download URL to the next function. When I try to download the file with this URL:
http://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-Allison-Female-IBM/catbirds.mp3
I get this error:
<Error>
<Code>AccessDenied</Code>
<Message>Access denied.</Message>
<Details>
Anonymous caller does not have storage.objects.get access to languagetwo-cd94d.appspot.com/Audio/English/United_States-Allison-Female-IBM/catbirds.mp3.
</Details>
</Error>
Downloading the file from my app (as an authorized user) I get the 403 (Forbidden)
error message.
I've also tried this property, with the same result:
let options = {
metadata: {
contentType: 'audio/webm',
predefinedAcl: 'publicRead'
}
};
Moving on, I tried file.makePublic()
:
const {Storage} = require('@google-cloud/storage');
const storage = new Storage({ projectId: 'languagetwo-cd94d' });
const myBucket = storage.bucket('languagetwo-cd94d.appspot.com');
var mp3Promise = new Promise(function(resolve, reject) {
let options = {
metadata: {
contentType: 'audio/mp3'
}
};
synthesizeParams.accept = 'audio/mp3';
var file = myBucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3');
textToSpeech.synthesize(synthesizeParams)
.then(function(audio) {
audio.pipe(file.createWriteStream(options));
})
.then(function() {
file.makePublic()
.then(function(data) {
console.log(data)
resolve('http://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3');
})
.catch(error => console.error(error));
})
.catch(error => console.error(error));
});
This code didn't even execute. It crashed at file.makePublic()
and the error message was
{ Error: No such object: languagetwo-cd94d.appspot.com/Audio/English/United_States-Allison-Female-IBM/warblers.mp3
I'm not sure what this error means. My guess is that file.createWriteStream()
wrote to a file location, and then file.makePublic()
couldn't find that file location.
I found the permissions for warblers.mp3
on the Cloud Storage Browser:
Upvotes: 2
Views: 2516
Reputation: 311
I've been struggling with the same issue for a while and in the end here is what solved it for me:
const stream = file.createWriteStream(options)
audio.pipe(stream)
stream.on('finish', () => {
// file APIs will now work
})
The problem is that audio.pipe(file.createWriteStream(options))
creates a stream that writes to the file asyncronously. At the moment when you are calling file.makePublic()
there is no guarantee that that write stream has completed.
Upvotes: 0
Reputation: 520
the first error is due the access permissions to the bucket, in the link you can find Identity and Access Management (IAM) instructions, there you can check the roles and permission to manage the bucket access.
The second error could be a consequence of the first one.
Please let me know if the information works for you.
Upvotes: 3
Reputation: 4195
You need to change options to this:
let options = {
public: true,
metadata: {
contentType: 'audio/mp3'
}
};
https://googleapis.dev/nodejs/storage/latest/global.html#CreateWriteStreamOptions
Upvotes: 1