Skip to content

Commit 7b6246b

Browse files
Update CloudEvent upcasting logic (GoogleCloudPlatform#99)
1 parent 382bd10 commit 7b6246b

File tree

6 files changed

+79
-11
lines changed

6 files changed

+79
-11
lines changed

.github/workflows/conformance.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ jobs:
5555
with:
5656
functionType: 'cloudevent'
5757
useBuildpacks: false
58-
validateMapping: false
58+
validateMapping: true
5959
cmd: "'mvn -f invoker/conformance/pom.xml function:run -Drun.functionTarget=com.google.cloud.functions.conformance.CloudEventsConformanceFunction'"
6060
startDelay: 10

invoker/core/src/main/java/com/google/cloud/functions/invoker/CloudFunctionsContext.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ abstract class CloudFunctionsContext implements Context {
5050
// TODO: expose this in the Context interface (as a default method).
5151
abstract Map<String, String> params();
5252

53+
@Nullable
54+
abstract String domain();
55+
5356
@Override
5457
public abstract Map<String, String> attributes();
5558

@@ -71,6 +74,7 @@ abstract static class Builder {
7174
abstract Builder setResource(String x);
7275
abstract Builder setParams(Map<String, String> x);
7376
abstract Builder setAttributes(Map<String, String> value);
77+
abstract Builder setDomain(String x);
7478

7579
abstract CloudFunctionsContext build();
7680
}

invoker/core/src/main/java/com/google/cloud/functions/invoker/GcfEvents.java

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,13 @@ class GcfEvents {
8282
new FirestoreFirebaseEventAdapter("google.firebase.analytics.log.v1.written", FIREBASE_SERVICE)),
8383

8484
entry("providers/google.firebase.database/eventTypes/ref.create",
85-
new FirestoreFirebaseEventAdapter("google.firebase.database.document.v1.created",
86-
FIREBASE_DB_SERVICE)),
85+
new FirebaseDatabaseEventAdapter("google.firebase.database.document.v1.created")),
8786
entry("providers/google.firebase.database/eventTypes/ref.write",
88-
new FirestoreFirebaseEventAdapter("google.firebase.database.document.v1.written",
89-
FIREBASE_DB_SERVICE)),
87+
new FirebaseDatabaseEventAdapter("google.firebase.database.document.v1.written")),
9088
entry("providers/google.firebase.database/eventTypes/ref.update",
91-
new FirestoreFirebaseEventAdapter("google.firebase.database.document.v1.updated",
92-
FIREBASE_DB_SERVICE)),
89+
new FirebaseDatabaseEventAdapter("google.firebase.database.document.v1.updated")),
9390
entry("providers/google.firebase.database/eventTypes/ref.delete",
94-
new FirestoreFirebaseEventAdapter("google.firebase.database.document.v1.deleted",
95-
FIREBASE_DB_SERVICE)),
91+
new FirebaseDatabaseEventAdapter("google.firebase.database.document.v1.deleted")),
9692

9793
entry("providers/cloud.pubsub/eventTypes/topic.publish",
9894
new PubSubEventAdapter(PUB_SUB_MESSAGE_PUBLISHED)),
@@ -172,6 +168,8 @@ private static class PubSubEventAdapter extends EventAdapter {
172168
@Override
173169
String maybeReshapeData(Event legacyEvent, String jsonData) {
174170
JsonObject jsonObject = GSON.fromJson(jsonData, JsonObject.class);
171+
jsonObject.addProperty("messageId", legacyEvent.getContext().eventId());
172+
jsonObject.addProperty("publishTime", legacyEvent.getContext().timestamp());
175173
JsonObject wrapped = new JsonObject();
176174
wrapped.add("message", jsonObject);
177175
return GSON.toJson(wrapped);
@@ -232,6 +230,44 @@ String maybeReshapeData(Event legacyEvent, String jsonData) {
232230
}
233231
}
234232

233+
private static class FirebaseDatabaseEventAdapter extends EventAdapter {
234+
private static final Pattern FIREBASE_DB_RESOURCE_PATTERN =
235+
Pattern.compile("^projects/_/(instances/[^/]+)/((documents|refs)/.+)$");
236+
237+
FirebaseDatabaseEventAdapter(String cloudEventType) {
238+
super(cloudEventType, FIREBASE_DB_SERVICE);
239+
}
240+
241+
@Override
242+
SourceAndSubject convertResourceToSourceAndSubject(String resourceName, Event legacyEvent) {
243+
Matcher matcher = FIREBASE_DB_RESOURCE_PATTERN.matcher(resourceName);
244+
String location = parseLocation(legacyEvent);
245+
if (matcher.matches() && location != null) {
246+
String resource = String.format("projects/_/locations/%s/%s", location, matcher.group(1));
247+
String subject = matcher.group(2);
248+
return SourceAndSubject.of(resource, subject);
249+
}
250+
return super.convertResourceToSourceAndSubject(resourceName, legacyEvent);
251+
}
252+
253+
private String parseLocation(Event legacyEvent) {
254+
String domain = legacyEvent.getContext().domain();
255+
if (domain == null) {
256+
return null;
257+
}
258+
// The default location for firebaseio.com is us-central1
259+
if ("firebaseio.com".equals(domain)) {
260+
return "us-central1";
261+
}
262+
// Otherwise the location can be inferred from the first subdomain
263+
String[] subdomains = domain.split("\\.");
264+
if (subdomains.length > 1) {
265+
return subdomains[0];
266+
}
267+
return null;
268+
}
269+
}
270+
235271
private static class FirebaseAuthEventAdapter extends EventAdapter {
236272
FirebaseAuthEventAdapter(String cloudEventType) {
237273
super(cloudEventType, FIREBASE_AUTH_SERVICE);

invoker/core/src/test/java/com/google/cloud/functions/invoker/GcfEventsTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ public class GcfEventsTest {
5252
{"legacy_pubsub.json", "google.cloud.pubsub.topic.v1.messagePublished",
5353
"//pubsub.googleapis.com/projects/sample-project/topics/gcf-test", null},
5454
{"firebase-db1.json", "google.firebase.database.document.v1.written",
55-
"//firebasedatabase.googleapis.com/projects/_/instances/my-project-id", "refs/gcf-test/xyz"},
55+
"//firebasedatabase.googleapis.com/projects/_/locations/us-central1/instances/my-project-id",
56+
"refs/gcf-test/xyz"},
57+
{"firebase-db2.json", "google.firebase.database.document.v1.written",
58+
"//firebasedatabase.googleapis.com/projects/_/locations/europe-west1/instances/my-project-id",
59+
"refs/gcf-test/xyz"},
5660
{"firebase-auth1.json", "google.firebase.auth.user.v1.created",
5761
"//firebaseauth.googleapis.com/projects/my-project-id", "users/UUpby3s4spZre6kHsgVSPetzQ8l2"},
5862
{"firebase-auth2.json", "google.firebase.auth.user.v1.deleted",
@@ -211,7 +215,9 @@ public void pubSubWrapping() throws IOException {
211215
assertThat(new String(cloudEvent.getData().toBytes(), UTF_8))
212216
.isEqualTo("{\"message\":{\"@type\":\"type.googleapis.com/google.pubsub.v1.PubsubMessage\","
213217
+ "\"attributes\":{\"attribute1\":\"value1\"},"
214-
+ "\"data\":\"VGhpcyBpcyBhIHNhbXBsZSBtZXNzYWdl\"}}");
218+
+ "\"data\":\"VGhpcyBpcyBhIHNhbXBsZSBtZXNzYWdl\","
219+
+ "\"messageId\":\"1215011316659232\","
220+
+ "\"publishTime\":\"2020-05-18T12:13:19.209Z\"}}");
215221
}
216222

217223
// Checks that a Firestore event correctly gets an extra "wildcards" property in its CloudEvent data

invoker/core/src/test/resources/firebase-db1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"auth": {
77
"admin": true
88
},
9+
"domain": "firebaseio.com",
910
"data": {
1011
"data": null,
1112
"delta": {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"eventType": "providers/google.firebase.database/eventTypes/ref.write",
3+
"params": {
4+
"child": "xyz"
5+
},
6+
"auth": {
7+
"admin": true
8+
},
9+
"domain":"europe-west1.firebasedatabase.app",
10+
"data": {
11+
"data": {
12+
"grandchild": "other"
13+
},
14+
"delta": {
15+
"grandchild": "other changed"
16+
}
17+
},
18+
"resource": "projects/_/instances/my-project-id/refs/gcf-test/xyz",
19+
"timestamp": "2020-09-29T11:32:00.000Z",
20+
"eventId": "aaaaaa-1111-bbbb-2222-cccccccccccc"
21+
}

0 commit comments

Comments
 (0)