I found this documentation and this documentation about uploading files to Google Cloud Storage. I wrote this code:
const {Storage} = require('#google-cloud/storage')();
const projectId = 'myapp-cd94d';
const storage = new Storage({
projectId: projectId,
});
const bucketName = "myapp-cd94d.appspot.com";
const filename = { 'test': 'file'};
var serviceAccount = require("./serviceAccountKey.json")
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "myapp-cd94d.appspot.com"
});
var bucket = admin.storage().bucket();
await storage.bucket(bucketName).upload(filename, {
gzip: true,
metadata: {
cacheControl: 'no-cache',
},
});
console.log(`${filename} uploaded to ${bucketName}.`);
I tried to deploy the code and got this error message:
await storage.bucket(bucketName).upload(filename, {
^^^^^^^
SyntaxError: Unexpected identifier
Is there something wrong with my first line
const {Storage} = require('#google-cloud/storage')();
Why are there curly brackets around Storage? Am I supposed to replace {Storage} with something else?
Why are there curly brackets around Storage? Am I supposed to replace {Storage} with something else?
The curly braces around Storage indicate a deconstructing assignment. It allows you to extract multiple values from data stored in objects and Arrays. The example import from the documentation you shared (const {Storage} = require('#google-cloud/storage');) is correct.
The error message SyntaxError: Unexpected identifier is not saying that it didn't identify storage, it's saying that it didn't expect storage to be there. The error is due to await.
await can only be used in an async function. For example:
async function myAsyncFunction() {
let result = await lengthyFunction();
console.log(result);
}
myAsyncFunction();
Try wrapping the bucket upload call inside an async function to avoid the error when using await.
Related
I am making a Next.js app that has a page that connects to a REST API. The REST API simply spits out a raw .wasm (WebAssembly) file. I know that sounds atypical but it's 100% necessary for my app. I have this function which is supposed to fetch the .wasm file from the API:
const fetchedWasmWrapped = useCallback( async () => {
const endpoint = "/.netlify/functions" + "/decrypt?authSig="+JSON.stringify(props.props.authSig);
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/wasm',
},
};
const response = await fetch(endpoint, options);
const result = await response.text();
console.log(result);
setDecryptedWasm(result);
}, [props.props.authSig])
The function works. It DOES output the .wasm file but console.log(result) writes a bizarre string with a lot of symbols and empty characters. I believe the reason why result is all jumbled up is because I don't think WebAssembly is meant to be printed as a string. It's actually a blob. result is then read as a file later in my app but that fails and I'm assuming it's because the WebAssembly code was not imported as a blob but rather a string.
So how do I tell typescript that I want the ".wasm" code from response? I don't believe there a response.wasm() function so how do I do this?
The key is that you have to change const result = await response.text(); to const result = await response.blob();
This threw more errors in my vscode terminal because setDecryptedWasm was expecting a string. So change const [decryptedWasm, setDecryptedWasm] = useState(''); to const [decryptedWasm, setDecryptedWasm] = useState(new File([], ''));
And rather than setting decryptedWasm with setDecryptedWasm(result), do setDecryptedWasm(new File([result], 'myunityapp.wasm'));
I am trying to upload an image to Firebase Storage using Flutter Web. I have followed many tutorials online on how to go about this, but I end up with the same error.
This is my code for upload
pickImageFromGallery() async {
imageFile = await ImagePickerWeb.getImageInfo;
setState(() {
_image = imageFile!.fileName!;
});
}
Future<void> uploadFile(
MediaInfo mediaInfo, String ref, String fileName) async {
try {
String mimeType = mime(path.basename(mediaInfo.fileName!))!;
final String extension = extensionFromMime(mimeType)!;
var metadata = fb.UploadMetadata(
contentType: mimeType,
);
fb.StorageReference storageReference =
fb.storage().ref('images').child('$fileName.$extension');
fb.UploadTaskSnapshot uploadTaskSnapshot =
await storageReference.put(mediaInfo.data, metadata).future;
Uri imageUri = await uploadTaskSnapshot.ref.getDownloadURL();
setState(() {
_imageURL = imageUri.toString();
});
} catch (e) {
setState(() {
_imageURL = e.toString();
});
}
}
This is my Storage rules for public access
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
This is the error I get
FirebaseError: Firebase Storage: An unknown error occurred, please check the error payload for server response.
{
"error": {
"code": 404,
"message": "Not Found."
}
} (storage/unknown)
I have tried everything online that seems to be the solution, but there is no exact solution for this problem. Please help me figure out what may be the problem.
I am using Flutter Web, and the following packages:
firebase,
path,
image_picker_web,
mime_type
EDIT: Working Code
The problem seemed to be with the StorageReference. It worked once edited to the following:
fb.StorageReference storageReference = fb.storage().refFromURL('gs://storageBucket/').child('$fileName.$extension');
replace 'storageBucket' with your storageBucket name shown in Firebase Storage
I also experienced this, because i did not update the firebase storage rules to allow me to write to the database
I got the same error.
It happens when the path can't reach the bucket, which I found out means "404 not found". Check the bucket name in storageBucket in firebaseConfig. In my case, I was using Dotenv and left a space after the double quotes.
Dotenv was converting it to "" double quotation marks.
You can check the bucket name in the Firebase storage console. You don't need the "gs://" at the beginning or the "/" at the end. Just check the name. If you are using Dotenv, watch out for spaces.
I got this error because when I copied the REACT_APP_FIREBASE_STORAGE_BUCKET variables from the .env file used in my local environment to Netlify which is my hosting service, I included the quotation marks (that is, I entered 'my.secret.url' instead of my.secret.url.
I've started working with firebase storage and firebase functions recently. Right now I've been developing file upload from functions to storage .
I've got it working (upload is done and file appears on the storage section), yet, the image, stays like this forever (loading forever on the right side):
I though that it was an error from my code. Yet, if I open Google Cloud Platform - Storage, the image appears and I can open it and preview it.
In firebase storage, if I open the image (select on it and click open), it returns the following url: https://console.firebase.google.com/u/0/undefined
What may I been doing wrong? Here's the code I'm using:
function uploadImage() {
const newImageData = "data:image/png;base64,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"
var mimeTypes = require('mimetypes');
var image = newImageData,
mimeType = image.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/)![1],
fileName = 'test.' + mimeTypes.detectExtension(mimeType),
base64EncodedImageString = image.replace(/^data:image\/\w+;base64,/, ''),
imageBuffer = new Buffer(base64EncodedImageString, 'base64');
// Instantiate the GCP Storage instance
const { Storage } = require('#google-cloud/storage');
const googleCloudStorage = new Storage(firebaseSettings);
const bucket = googleCloudStorage.bucket('projectID.appspot.com');
var file = bucket.file(fileName);
return file.save(imageBuffer, {
metadata: { contentType: mimeType, cacheControl: "public, max-age=300" },
public: true,
validation: 'md5'
}, function (error: any) {
if (error) {
throw 'error';
}
return "https://storage.googleapis.com/share-expanses-dcc9f.appspot.com/" + fileName;
});
}
Thanks for the help
Haven't been able to test the solution given by Firebase, but here's the transcript of the response:
The problem that you are facing could be because of two reasons. The
first one is how you are uploading the files, via the Firebase
Console, using any Admin SDK, or via the gsutil command. If using the
Admin SDK option, the problem is a known issue where the required
metadata doesn’t exist, fortunately there is a workaround, you can try
this script to solve this issue.
Now, the second one is related to the network if you are using
comcast, please, try on a different network to see if this issue is
related to that.
When you save an image to firebase, you need to provide an access token in metadata : firebaseStorageDownloadTokens. It has to be an uuid.
More info can be found here : https://www.sentinelstand.com/article/guide-to-firebase-storage-download-urls-tokens
const { v4: uuid } = require("uuid")
function uploadImage() {
const newImageData = "data:image/png;base64,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"
var mimeTypes = require('mimetypes');
var image = newImageData,
mimeType = image.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/)![1],
fileName = 'test.' + mimeTypes.detectExtension(mimeType),
base64EncodedImageString = image.replace(/^data:image\/\w+;base64,/, ''),
imageBuffer = new Buffer(base64EncodedImageString, 'base64');
// Instantiate the GCP Storage instance
const { Storage } = require('#google-cloud/storage');
const googleCloudStorage = new Storage(firebaseSettings);
const bucket = googleCloudStorage.bucket('projectID.appspot.com');
var file = bucket.file(fileName);
return file.save(imageBuffer, {
metadata: {
contentType: mimeType,
cacheControl: "public,
max-age=300",
// THIS IS THE LINE YOU NEED TO ADD
firebaseStorageDownloadTokens: uuid(),
},
public: true,
validation: 'md5'
}, function (error: any) {
if (error) {
throw 'error';
}
return "https://storage.googleapis.com/share-expanses-dcc9f.appspot.com/" + fileName;
});
}
After that you'll need to click on "Create access token"
#jean-smaug answer is almost complete. Based on the page he linked (https://www.sentinelstand.com/article/guide-to-firebase-storage-download-urls-tokens), the only missing thing is to wrap the firebaseStorageDownloadTokens property inside a metadata object. I've just tested it and it's working fine 👌 No need to create access token afterwards.
In my case I added metadata while uploading and it loading as it showed in image but when I'm refresh page after 3 min I found that it upload correctly , so as Cafn explain if it not matter of metadata you should wait until it loaded
$uploadedObject=$bucket->upload($imageFile, [
'name' => 'Image_Name',
"metadata" => [ "contentType"=> 'image/png'],
]);
if mishandling When Access token revoked GetdownloadURL() will invalid. Hence I need a public access permanent URL without access token. How to makePublic() something did mistake but I can't conclude, gcs.bucket("Project-12345.appspot.com").file(fileName).makePublic()
Security Rules
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read;
allow write: if request.auth != null;
}}}
Mycode
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const serviceAccount = require('./ProjectID-12345-firebase-adminsdk-.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://ProjectID-12345.firebaseio.com"
});
const {Storage} = require('#google-cloud/storage');
const gcs = new Storage({
projectId: "projectId-12345",
keyFilename: serviceAccount
});
const GetUrl = (productId) => {
const ImgList = ["ImgA_650x650", "ImgB_650x650", "ImgC_650x650", "ImgD_650x650"] ;
let url = []
ImgList.forEach( (element , Index) =>{
let fileName = "product/"+ productId + "/resize"+ element;
let storageref = gcs.bucket("Project-12345.appspot.com").file(fileName);
storageref.makePublic();
url[Index] = storageref.publicUrl();
})
return url;
}
I get URL without Access token
[
'https://storage.googleapis.com/Project-12345.appspot.com/product/1zHTmjNc5CV4WBLDLgdV/resizeImgA_650x650',
'https://storage.googleapis.com/Project-12345.appspot.com/product/1zHTmjNc5CV4WBLDLgdV/resizeImgB_650x650',
'https://storage.googleapis.com/Project-12345.appspot.com/product/1zHTmjNc5CV4WBLDLgdV/resizeImgC_650x650',
'https://storage.googleapis.com/Project-12345.appspot.com/product/1zHTmjNc5CV4WBLDLgdV/resizeImgD_650x650'
]
But the issue is the URL is access denied. it Show error as
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>AccessDenied</Code>
<Message>Access denied.</Message>
<Details>Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object.</Details>
</Error>
The problem might be related with fact that makePublic() is asynchronous and in the presented code its use in synchronus way and as the results publicUrl(), which is synchronous, is executed before it.
makePublic() should be used with await in async function like:
const GetUrl = async (productId) => {
...
await storageref.makePublic();
...
or with then like:
storageref.makePublic().then(() => url[Index] = storageref.publicUrl());
or with callback.
Of course please treat is as pseudo code. I am not sure if you can just copy paste it and it will work, anyway for sure the function is asynchronous and have to be coded that way. There are nice examples in the documentation.
I'm trying to create a cloud function which saves some data (documents from firestore) to cloud storage.
Wrote some cloud functions before, but kind of new to cloud storage, buckets etc.
From what I've read I have to "stream" this data to a bucket.
I'd love to see a short snippet that does just that :)
For you to achieve that, it should not be something very complicated, so I hope I can help you.
To perform this, I will follow the example explained in the article Backup Firestore data to storage bucket on a schedule in GCP - which you can follow completely, in case you are interested - focusings in the upload from Firestore to Cloud Storage. I will explain which parts to use and how to use them, to achieve your agoal
Once you created your Cloud Storage bucket - it should have Multi-regional and Nearline configured in the settings - you need to use the below code as indicated after them.
index.js file:
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
// Replace BUCKET_NAME
const bucket = 'gs://<bucket-id>'
exports.scheduledFirestoreBackup = (event, context) => {
const databaseName = client.databasePath(
process.env.GCLOUD_PROJECT,
'(default)'
);
return client
.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
// Leave collectionIds empty to export all collections
// or define a list of collection IDs:
// collectionIds: ['users', 'posts']
collectionIds: [],
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return response;
})
.catch(err => {
console.error(err);
});
};
package.json file:
{
"dependencies": {
"#google-cloud/firestore": "^1.3.0"
}
}
These files should be created, with the configuration in the Cloud Function as following: an unique name; Cloud Sub/Pub as trigger; topic name similar or equal to initiateFirestoreBackup; using Node.js, source will be the above files written and function to execute scheduledFirestoreBackup.
The above codes should be enough for you to export from your Firestore to your Cloud Storage, due to the fact that it will be getting all your collections - or you can define specifics - and sending to the bucket you already created.
Besides that, in case you want more information on uploading files to Cloud Storage using Cloud Functions, you can check here as well: Uploading files from Firebase Cloud Functions to Cloud Storage
Let me know if the information helped you!
Thanks to #gso_gabriel I was able to create a partial backup for my documents.
To anyone who's interested, here's a simplified version of my code:
const bucketName = 'myproject.appspot.com';
exports.backup = functions.https.onCall(async (data, context) => {
const userDoc = await admin.firestore().collection('users').doc('abc123').get();
await writeFile('temp', 'user.json', JSON.stringify(userDoc.data()));
}
async function writeFile(dirName, fileName, content) {
var bucket = admin.storage().bucket(bucketName);
const destFilename = dirName + '/' + fileName;
const file = bucket.file(destFilename);
const options = {
destination: destFilename,
metadata: { contentType: "application/json" }
};
await bucket.file(destFilename).save(content, options);
}