Skip to content

Commit

Permalink
fix(storage, android)!: android now updates customMetadata as a group
Browse files Browse the repository at this point in the history
BREAKING CHANGE: android works like web+iOS now: customMetadata if passed in will be
updated as a single atomic unit, all keys at once. Any key you want to keep in customMetadata
must be passed in during update; any missing keys will be removed. Set customMetadata to null
in order to remove customMetadata entirely, omit it during update to leave it unchanged.
  • Loading branch information
mikehardy committed Jun 19, 2022
1 parent a8c1cf4 commit d602436
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public void setAutoInitEnabled(Boolean enabled, Promise promise) {

@ReactMethod
public void getToken(String appName, String senderId, Promise promise) {
FirebaseMessaging messagingInstance = FirebaseApp.getInstance(appName).get(FirebaseMessaging.class);
FirebaseMessaging messagingInstance =
FirebaseApp.getInstance(appName).get(FirebaseMessaging.class);
Tasks.call(getExecutor(), () -> Tasks.await(messagingInstance.getToken()))
.addOnCompleteListener(
task -> {
Expand All @@ -136,7 +137,8 @@ public void getToken(String appName, String senderId, Promise promise) {

@ReactMethod
public void deleteToken(String appName, String senderId, Promise promise) {
FirebaseMessaging messagingInstance = FirebaseApp.getInstance(appName).get(FirebaseMessaging.class);
FirebaseMessaging messagingInstance =
FirebaseApp.getInstance(appName).get(FirebaseMessaging.class);
Tasks.call(
getExecutor(),
() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
import com.google.firebase.storage.StorageTask;
import io.invertase.firebase.app.ReactNativeFirebaseApp;
import io.invertase.firebase.common.SharedUtils;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;

class ReactNativeFirebaseStorageCommon {
Expand Down Expand Up @@ -93,15 +93,40 @@ static String getTaskStatus(@Nullable StorageTask<?> task) {
}

/** Converts a RN ReadableMap into a StorageMetadata instance */
static StorageMetadata buildMetadataFromMap(ReadableMap metadataMap, @Nullable Uri file) {
static StorageMetadata buildMetadataFromMap(
ReadableMap metadataMap, @Nullable Uri file, @Nullable StorageMetadata existingMetadata) {
StorageMetadata.Builder metadataBuilder = new StorageMetadata.Builder();

if (metadataMap != null) {
if (metadataMap.hasKey(KEY_CUSTOM_META)) {
ReadableMap customerMetaMap = Objects.requireNonNull(metadataMap.getMap(KEY_CUSTOM_META));
Map<String, Object> customMeta = customerMetaMap.toHashMap();
for (Map.Entry<String, Object> entry : customMeta.entrySet()) {
if (metadataMap.hasKey(KEY_CUSTOM_META) || (existingMetadata != null)) {

Map<String, Object> customMetadata = new HashMap<>();
ReadableMap freshCustomMetadata = metadataMap.getMap(KEY_CUSTOM_META);
Map<String, Object> existingCustomMetadata = new HashMap<>();

// Our baseline will be any existing custom metadata if it exists
if (existingMetadata != null) {
for (String existingKey : existingMetadata.getCustomMetadataKeys()) {
customMetadata.put(existingKey, existingMetadata.getCustomMetadata(existingKey));
existingCustomMetadata.put(
existingKey, existingMetadata.getCustomMetadata(existingKey));
}
}

// Clobber with any fresh custom metadata if it exists
if (freshCustomMetadata != null) {
customMetadata.putAll(freshCustomMetadata.toHashMap());
}

for (Map.Entry<String, Object> entry : customMetadata.entrySet()) {
metadataBuilder.setCustomMetadata(entry.getKey(), (String) entry.getValue());

// API contract updates custom metadata as a group but android SDK has key granularity
// So if freshCustomMetadata exists, for any key that in our merged map but not in
// freshCustomMetadata, set to null to clear
if (freshCustomMetadata == null || !freshCustomMetadata.hasKey(entry.getKey())) {
metadataBuilder.setCustomMetadata(entry.getKey(), null);
}
}
}

Expand Down Expand Up @@ -167,29 +192,31 @@ static WritableMap getMetadataAsMap(@Nullable StorageMetadata storageMetadata) {
if (storageMetadata.getCacheControl() != null
&& storageMetadata.getCacheControl().length() > 0) {
metadata.putString(KEY_CACHE_CONTROL, storageMetadata.getCacheControl());
} else {
metadata.putNull(KEY_CACHE_CONTROL);
}

if (storageMetadata.getContentLanguage() != null
&& storageMetadata.getContentLanguage().length() > 0) {
metadata.putString(KEY_CONTENT_LANG, storageMetadata.getContentLanguage());
} else {
metadata.putNull(KEY_CONTENT_LANG);
}

metadata.putString(KEY_CONTENT_DISPOSITION, storageMetadata.getContentDisposition());
metadata.putString(KEY_CONTENT_ENCODING, storageMetadata.getContentEncoding());
metadata.putString(KEY_CONTENT_TYPE, storageMetadata.getContentType());
if (storageMetadata.getContentDisposition() != null
&& storageMetadata.getContentDisposition().length() > 0) {
metadata.putString(KEY_CONTENT_DISPOSITION, storageMetadata.getContentDisposition());
}
if (storageMetadata.getContentEncoding() != null
&& storageMetadata.getContentEncoding().length() > 0) {
metadata.putString(KEY_CONTENT_ENCODING, storageMetadata.getContentEncoding());
}
if (storageMetadata.getContentType() != null && storageMetadata.getContentType().length() > 0) {
metadata.putString(KEY_CONTENT_TYPE, storageMetadata.getContentType());
}

if (storageMetadata.getCustomMetadataKeys().size() > 0) {
WritableMap customMetadata = Arguments.createMap();
for (String key : storageMetadata.getCustomMetadataKeys()) {
customMetadata.putString(key, storageMetadata.getCustomMetadata(key));
}
metadata.putMap(KEY_CUSTOM_META, customMetadata);
} else {
metadata.putNull(KEY_CUSTOM_META);
}

return metadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,24 @@ public void listAll(String appName, String url, Promise promise) {
}
}

// Useful for development / debugging
private void dumpMetadata(StorageMetadata metadata) {
System.err.println("STORAGE dumping metadata contents");
System.err.println("STORAGE - cacheControl " + metadata.getCacheControl());
System.err.println("STORAGE - contentDisposition " + metadata.getContentDisposition());
System.err.println("STORAGE - contentEncoding " + metadata.getContentEncoding());
System.err.println("STORAGE - contentLanguage " + metadata.getContentLanguage());
System.err.println("STORAGE - contentType " + metadata.getContentType());
for (String customKey : metadata.getCustomMetadataKeys()) {
System.err.println(
"STORAGE - customMetadata: '"
+ customKey
+ "' / '"
+ metadata.getCustomMetadata(customKey)
+ "'");
}
}

/**
* @link https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
*/
Expand All @@ -177,17 +195,35 @@ public void updateMetadata(
String appName, String url, ReadableMap metadataMap, final Promise promise) {
try {
StorageReference reference = getReferenceFromUrl(url, appName);
StorageMetadata metadata = buildMetadataFromMap(metadataMap, null);

reference
.updateMetadata(metadata)
.getMetadata()
.addOnCompleteListener(
getExecutor(),
task -> {
if (task.isSuccessful()) {
promise.resolve(getMetadataAsMap(task.getResult()));
getTask -> {
if (getTask.isSuccessful()) {

// dumpMetadata(getTask.getResult());
StorageMetadata metadata =
buildMetadataFromMap(metadataMap, null, getTask.getResult());
// dumpMetadata(metadata);

reference
.updateMetadata(metadata)
.addOnCompleteListener(
getExecutor(),
updateTask -> {
if (updateTask.isSuccessful()) {
// dumpMetadata(updateTask.getResult());
promise.resolve(getMetadataAsMap(updateTask.getResult()));
} else {
updateTask.getException().printStackTrace();
promiseRejectStorageException(promise, updateTask.getException());
}
});

} else {
promiseRejectStorageException(promise, task.getException());
promiseRejectStorageException(promise, getTask.getException());
}
});
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ void addOnCompleteListener(ExecutorService executor, Promise promise) {

/** Put String or Data from JavaScript */
void begin(ExecutorService executor, String string, String format, ReadableMap metadataMap) {
StorageMetadata metadata = buildMetadataFromMap(metadataMap, null);
StorageMetadata metadata = buildMetadataFromMap(metadataMap, null, null);
uploadTask = storageReference.putBytes(uploadStringToByteArray(string, format), metadata);
setStorageTask(uploadTask);
addEventListeners(executor);
Expand All @@ -195,7 +195,7 @@ void begin(ExecutorService executor, String string, String format, ReadableMap m
/** Put File from JavaScript */
void begin(ExecutorService executor, String localFilePath, ReadableMap metadataMap) {
Uri fileUri = SharedUtils.getUri(localFilePath);
StorageMetadata metadata = buildMetadataFromMap(metadataMap, fileUri);
StorageMetadata metadata = buildMetadataFromMap(metadataMap, fileUri, null);
uploadTask = storageReference.putFile(fileUri, metadata);
setStorageTask(uploadTask);
addEventListeners(executor);
Expand Down
Loading

0 comments on commit d602436

Please sign in to comment.