admin
2022-01-12 4a7367a869ef12375ea6678ca44e102b8919c624
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
package cn.jpush.api.push;
 
import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.ServiceHelper;
import cn.jiguang.common.connection.*;
import cn.jiguang.common.resp.*;
import cn.jiguang.common.utils.Base64;
import cn.jiguang.common.utils.Preconditions;
import cn.jiguang.common.utils.StringUtils;
import cn.jiguang.common.utils.sm2.SM2Util;
import cn.jpush.api.push.model.*;
import cn.jpush.api.push.model.audience.Audience;
import com.google.gson.*;
 
import java.util.List;
 
/**
 * Entrance for sending Push.
 * <p>
 * For the following parameters, you can set them by instance creation.
 * This action will override setting in PushPayload Optional.
 * * apnsProduction If not present, the default is true.
 * * timeToLive If not present, the default is 86400(s) (one day).
 * <p>
 * Can be used directly.
 */
public class PushClient {
 
    private IHttpClient _httpClient;
    private String _baseUrl;
    private String _pushPath;
    private String _pushValidatePath;
    private String batchRegidPushPath;
    private String batchAliasPushPath;
    private String _filePushPath;
 
    private JsonParser _jsonParser = new JsonParser();
 
    // If not present, true by default.
    private int _apnsProduction;
 
    // If not present, the default value is 86400(s) (one day)
    private long _timeToLive;
 
    // encrypt type, the default value is empty
    private String _encryptType;
 
    public PushClient() {}
 
    /**
     * Create a Push Client.
     *
     * @param masterSecret API access secret of the appKey.
     * @param appKey       The KEY of one application on JPush.
     */
    public PushClient(String masterSecret, String appKey) {
        this(masterSecret, appKey, null, ClientConfig.getInstance());
    }
 
    /**
     * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig} instead of this constructor.
     *
     * @param masterSecret  API access secret of the appKey.
     * @param appKey        The KEY of one application on JPush.
     * @param maxRetryTimes The max retry times.
     */
    @Deprecated
    public PushClient(String masterSecret, String appKey, int maxRetryTimes) {
        this(masterSecret, appKey, maxRetryTimes, null);
    }
 
    /**
     * Create a Push Client with max retry times.
     * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig} instead of this constructor.
     *
     * @param masterSecret  API access secret of the appKey.
     * @param appKey        The KEY of one application on JPush.
     * @param maxRetryTimes max retry times
     * @param proxy         The max retry times.
     */
    @Deprecated
    public PushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) {
        ServiceHelper.checkBasic(appKey, masterSecret);
 
        ClientConfig conf = ClientConfig.getInstance();
        conf.setMaxRetryTimes(maxRetryTimes);
 
        this._baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME);
        this._pushPath = (String) conf.get(ClientConfig.PUSH_PATH);
        this._pushValidatePath = (String) conf.get(ClientConfig.PUSH_VALIDATE_PATH);
        this._filePushPath = (String) conf.get(ClientConfig.FILE_PUSH_PATH);
 
        this._apnsProduction = (Integer) conf.get(ClientConfig.APNS_PRODUCTION);
        this._timeToLive = (Long) conf.get(ClientConfig.TIME_TO_LIVE);
 
        String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret);
        this._httpClient = new NativeHttpClient(authCode, proxy, conf);
    }
 
    public PushClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) {
        ServiceHelper.checkBasic(appKey, masterSecret);
 
        this._baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME);
        this._pushPath = (String) conf.get(ClientConfig.PUSH_PATH);
        this._pushValidatePath = (String) conf.get(ClientConfig.PUSH_VALIDATE_PATH);
        this._filePushPath = (String) conf.get(ClientConfig.FILE_PUSH_PATH);
 
        this.batchAliasPushPath = (String) conf.get(ClientConfig.BATCH_ALIAS_PUSH_PATH);
        this.batchRegidPushPath = (String) conf.get(ClientConfig.BATCH_REGID_PUSH_PATH);
 
        this._apnsProduction = (Integer) conf.get(ClientConfig.APNS_PRODUCTION);
        this._timeToLive = (Long) conf.get(ClientConfig.TIME_TO_LIVE);
        this._encryptType = (String) conf.get(ClientConfig.ENCRYPT_TYPE);
 
        String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret);
        this._httpClient = new NativeHttpClient(authCode, proxy, conf);
 
    }
 
    /**
     * Create a Push Client with global settings.
     * <p>
     * If you want different settings from default globally, this constructor is what you needed.
     * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig} instead of this constructor.
     *
     * @param masterSecret   API access secret of the appKey.
     * @param appKey         The KEY of one application on JPush.
     * @param apnsProduction Global APNs environment setting. It will override PushPayload Options.
     * @param timeToLive     Global time_to_live setting. It will override PushPayload Options.
     */
    @Deprecated
    public PushClient(String masterSecret, String appKey, boolean apnsProduction, long timeToLive) {
        this(masterSecret, appKey);
        if (apnsProduction) {
            _apnsProduction = 1;
        } else {
            _apnsProduction = 0;
        }
        this._timeToLive = timeToLive;
    }
 
    /**
     * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setGlobalPushSetting} instead of this method.
     *
     * @param apnsProduction Global APNs environment setting. It will override PushPayload Options.
     * @param timeToLive     Global time_to_live setting. It will override PushPayload Options.
     */
    @Deprecated
    public void setDefaults(boolean apnsProduction, long timeToLive) {
        if (apnsProduction) {
            _apnsProduction = 1;
        } else {
            _apnsProduction = 0;
        }
        this._timeToLive = timeToLive;
    }
 
    public void setBaseUrl(String baseUrl) {
        this._baseUrl = baseUrl;
    }
 
    public PushResult sendPush(PushPayload pushPayload) throws APIConnectionException, APIRequestException {
        checkPushPayload(pushPayload);
 
        ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, getEncryptData(pushPayload));
 
        return BaseResult.fromResponse(response, PushResult.class);
    }
 
 
    public PushResult sendPushValidate(PushPayload pushPayload) throws APIConnectionException, APIRequestException {
        checkPushPayload(pushPayload);
 
        ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushValidatePath, getEncryptData(pushPayload));
 
        return BaseResult.fromResponse(response, PushResult.class);
    }
 
    public PushResult sendPush(String payloadString) throws APIConnectionException, APIRequestException {
        Preconditions.checkArgument(StringUtils.isNotEmpty(payloadString), "pushPayload should not be empty");
 
        try {
            _jsonParser.parse(payloadString);
        } catch (JsonParseException e) {
            Preconditions.checkArgument(false, "payloadString should be a valid JSON string.");
        }
 
        ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, getEncryptData(payloadString));
 
        return BaseResult.fromResponse(response, PushResult.class);
    }
 
    public PushResult sendFilePush(PushPayload pushPayload) throws APIConnectionException, APIRequestException {
        checkPushPayload(pushPayload);
 
        ResponseWrapper response = _httpClient.sendPost(_baseUrl + _filePushPath, getEncryptData(pushPayload));
 
        return BaseResult.fromResponse(response, PushResult.class);
    }
 
    public PushResult sendPushValidate(String payloadString) throws APIConnectionException, APIRequestException {
        Preconditions.checkArgument(StringUtils.isNotEmpty(payloadString), "pushPayload should not be empty");
 
        try {
            _jsonParser.parse(payloadString);
        } catch (JsonParseException e) {
            Preconditions.checkArgument(false, "payloadString should be a valid JSON string.");
        }
 
        ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushValidatePath, getEncryptData(payloadString));
 
        return BaseResult.fromResponse(response, PushResult.class);
    }
 
    public BatchPushResult batchSendPushByRegId(List<PushPayload> pushPayloadList) throws APIConnectionException, APIRequestException {
        return batchSendPush(_baseUrl + batchRegidPushPath, pushPayloadList);
    }
 
    public BatchPushResult batchSendPushByAlias(List<PushPayload> pushPayloadList) throws APIConnectionException, APIRequestException {
        return batchSendPush(_baseUrl + batchAliasPushPath, pushPayloadList);
    }
 
    public BatchPushResult batchSendPush(String url, List<PushPayload> pushPayloadList) throws APIConnectionException, APIRequestException {
 
        Preconditions.checkArgument((null != pushPayloadList), "param should not be null");
        Preconditions.checkArgument((!pushPayloadList.isEmpty()), "pushPayloadList should not be empty");
 
        Gson gson = new Gson();
 
        JsonObject contentJson = new JsonObject();
 
        CIDResult cidResult = getCidList(pushPayloadList.size(), "push");
        int i = 0;
        JsonObject pushPayLoadList = new JsonObject();
        // setting cid
        for (PushPayload payload : pushPayloadList) {
            String cid = payload.getCid();
            if (cid != null && !cid.trim().isEmpty()) {
                payload.setCid(null);
            } else {
                cid = cidResult.cidlist.get(i++);
            }
            pushPayLoadList.add(cid, payload.toJSON());
        }
        contentJson.add("pushlist", pushPayLoadList);
 
        ResponseWrapper response = _httpClient.sendPost(url, getEncryptData(gson.toJson(contentJson)));
 
        return BatchPushResult.fromResponse(response);
 
    }
 
    /**
     * Get cid list, the data form of cid is appKey-uuid.
     *
     * @param count the count of cid list, from 1 to 1000. default is 1.
     * @param type  default is "push", option: "schedule"
     * @return CIDResult, an array of cid
     * @throws APIConnectionException connect exception
     * @throws APIRequestException    request exception
     */
    public CIDResult getCidList(int count, String type) throws APIConnectionException, APIRequestException {
        Preconditions.checkArgument(count >= 1 && count <= 1000, "count should not less than 1 or larger than 1000");
        Preconditions.checkArgument(type == null || type.equals("push") || type.equals("schedule"), "type should be \"push\" or \"schedule\"");
        ResponseWrapper responseWrapper;
        if (type != null) {
            responseWrapper = _httpClient.sendGet(_baseUrl + _pushPath + "/cid?count=" + count + "&type=" + type);
        } else {
            responseWrapper = _httpClient.sendGet(_baseUrl + _pushPath + "/cid?count=" + count);
        }
        return BaseResult.fromResponse(responseWrapper, CIDResult.class);
    }
 
    /**
     * Delete a push by msgId.
     *
     * @param msgId The message id
     * @return delete result
     * @throws APIConnectionException connect exception
     * @throws APIRequestException    request exception
     */
    public DefaultResult deletePush(String msgId) throws APIConnectionException, APIRequestException {
        Preconditions.checkArgument(StringUtils.isNotEmpty(msgId), "msgId should not be empty");
 
        ResponseWrapper responseWrapper = _httpClient.sendDelete(_baseUrl + _pushPath + "/" + msgId);
 
        return DefaultResult.fromResponse(responseWrapper);
    }
 
    public void setHttpClient(IHttpClient client) {
        this._httpClient = client;
    }
 
    // 如果使用 NettyHttpClient,在发送请求后需要手动调用 close 方法
    public void close() {
        if (_httpClient != null && _httpClient instanceof NettyHttpClient) {
            ((NettyHttpClient) _httpClient).close();
        } else if (_httpClient != null && _httpClient instanceof ApacheHttpClient) {
            ((ApacheHttpClient) _httpClient).close();
        }
    }
 
    /**
     * 获取加密的payload数据
     *
     * @param payloadData
     * @return
     */
    private String getEncryptData(String payloadData) {
        JsonElement payloadElement = _jsonParser.parse(payloadData);
        JsonObject jsonObject = payloadElement.getAsJsonObject();
        Audience audience = Audience.fromJsonElement(jsonObject.get("audience"));
        return getEncryptData(payloadData, audience);
    }
 
    /**
     * 获取加密的payload数据
     *
     * @param pushPayload
     * @return
     */
    private String getEncryptData(PushPayload pushPayload) {
        if (StringUtils.isEmpty(_encryptType)) {
            return pushPayload.toString();
        }
        if (EncryptKeys.ENCRYPT_SMS2_TYPE.equals(_encryptType)) {
            EncryptPushPayload encryptPushPayload = new EncryptPushPayload();
            try {
                encryptPushPayload.setPayload(String.valueOf(Base64.encode(SM2Util.encrypt(pushPayload.toString(), EncryptKeys.DEFAULT_SM2_ENCRYPT_KEY))));
            } catch (Exception e) {
                throw new RuntimeException("encrypt word exception", e);
            }
            encryptPushPayload.setAudience(pushPayload.getAudience());
            return encryptPushPayload.toString();
        }
        // 不支持的加密默认不加密
        return pushPayload.toString();
    }
 
    /**
     * 获取加密的payload数据
     *
     * @param pushPayload
     * @return
     */
    private String getEncryptData(String pushPayload, Audience audience) {
        if (StringUtils.isEmpty(_encryptType)) {
            return pushPayload;
        }
        if (EncryptKeys.ENCRYPT_SMS2_TYPE.equals(_encryptType)) {
            EncryptPushPayload encryptPushPayload = new EncryptPushPayload();
            try {
                encryptPushPayload.setPayload(String.valueOf(Base64.encode(SM2Util.encrypt(pushPayload, EncryptKeys.DEFAULT_SM2_ENCRYPT_KEY))));
            } catch (Exception e) {
                throw new RuntimeException("encrypt word exception", e);
            }
            encryptPushPayload.setAudience(audience);
            return encryptPushPayload.toString();
        }
        // 不支持的加密默认不加密
        return pushPayload;
    }
 
    private void checkPushPayload(PushPayload pushPayload) {
        Preconditions.checkArgument(!(null == pushPayload), "pushPayload should not be null");
 
        if (_apnsProduction > 0) {
            pushPayload.resetOptionsApnsProduction(true);
        } else if (_apnsProduction == 0) {
            pushPayload.resetOptionsApnsProduction(false);
        }
 
        if (_timeToLive >= 0) {
            pushPayload.resetOptionsTimeToLive(_timeToLive);
        }
    }
 
}