-
Notifications
You must be signed in to change notification settings - Fork 263
/
InstanceIdClientImpl.java
165 lines (137 loc) · 5.68 KB
/
InstanceIdClientImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.messaging;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponseInterceptor;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.util.Key;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseException;
import com.google.firebase.internal.AbstractHttpErrorHandler;
import com.google.firebase.internal.ApiClientUtils;
import com.google.firebase.internal.ErrorHandlingHttpClient;
import com.google.firebase.internal.HttpRequestInfo;
import com.google.firebase.internal.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* A helper class for interacting with the Firebase Instance ID service. Implements the FCM
* topic management functionality.
*/
final class InstanceIdClientImpl implements InstanceIdClient {
private static final String IID_HOST = "https://iid.googleapis.com";
private static final String IID_SUBSCRIBE_PATH = "iid/v1:batchAdd";
private static final String IID_UNSUBSCRIBE_PATH = "iid/v1:batchRemove";
private final ErrorHandlingHttpClient<FirebaseMessagingException> requestFactory;
InstanceIdClientImpl(HttpRequestFactory requestFactory, JsonFactory jsonFactory) {
this(requestFactory, jsonFactory, null);
}
InstanceIdClientImpl(
HttpRequestFactory requestFactory,
JsonFactory jsonFactory,
@Nullable HttpResponseInterceptor responseInterceptor) {
InstanceIdErrorHandler errorHandler = new InstanceIdErrorHandler(jsonFactory);
this.requestFactory = new ErrorHandlingHttpClient<>(requestFactory, jsonFactory, errorHandler)
.setInterceptor(responseInterceptor);
}
static InstanceIdClientImpl fromApp(FirebaseApp app) {
return new InstanceIdClientImpl(
ApiClientUtils.newAuthorizedRequestFactory(app),
app.getOptions().getJsonFactory());
}
public TopicManagementResponse subscribeToTopic(
String topic, List<String> registrationTokens) throws FirebaseMessagingException {
return sendInstanceIdRequest(topic, registrationTokens, IID_SUBSCRIBE_PATH);
}
public TopicManagementResponse unsubscribeFromTopic(
String topic, List<String> registrationTokens) throws FirebaseMessagingException {
return sendInstanceIdRequest(topic, registrationTokens, IID_UNSUBSCRIBE_PATH);
}
private TopicManagementResponse sendInstanceIdRequest(
String topic,
List<String> registrationTokens,
String path) throws FirebaseMessagingException {
String url = String.format("%s/%s", IID_HOST, path);
Map<String, Object> payload = ImmutableMap.of(
"to", getPrefixedTopic(topic),
"registration_tokens", registrationTokens
);
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(url, payload)
.addHeader("access_token_auth", "true");
InstanceIdServiceResponse response = new InstanceIdServiceResponse();
requestFactory.sendAndParse(request, response);
return new TopicManagementResponse(response.results);
}
private String getPrefixedTopic(String topic) {
if (topic.startsWith("/topics/")) {
return topic;
} else {
return "/topics/" + topic;
}
}
private static class InstanceIdServiceResponse {
@Key("results")
private List<GenericJson> results;
}
private static class InstanceIdServiceErrorResponse {
@Key("error")
private String error;
}
private static class InstanceIdErrorHandler
extends AbstractHttpErrorHandler<FirebaseMessagingException> {
private final JsonFactory jsonFactory;
InstanceIdErrorHandler(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
}
@Override
protected FirebaseMessagingException createException(FirebaseException base) {
String message = getCustomMessage(base);
return FirebaseMessagingException.withCustomMessage(base, message);
}
private String getCustomMessage(FirebaseException base) {
String response = getResponse(base);
InstanceIdServiceErrorResponse parsed = safeParse(response);
if (!Strings.isNullOrEmpty(parsed.error)) {
return "Error while calling the IID service: " + parsed.error;
}
return base.getMessage();
}
private String getResponse(FirebaseException base) {
if (base.getHttpResponse() == null) {
return null;
}
return base.getHttpResponse().getContent();
}
private InstanceIdServiceErrorResponse safeParse(String response) {
InstanceIdServiceErrorResponse parsed = new InstanceIdServiceErrorResponse();
if (!Strings.isNullOrEmpty(response)) {
// Parse the error response from the IID service.
// Sample response: {"error": "error message text"}
try {
jsonFactory.createJsonParser(response).parse(parsed);
} catch (IOException ignore) {
// Ignore any error that may occur while parsing the error response. The server
// may have responded with a non-json payload.
}
}
return parsed;
}
}
}