portal web service

PushService.java 21KB

    package com.ekexiu.push.service; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.jfw.apt.web.annotation.Path; import org.jfw.apt.web.annotation.operate.Get; import org.jfw.apt.web.annotation.operate.Post; import org.jfw.apt.web.annotation.param.RequestHeader; import org.jfw.util.ConstData; import org.jfw.util.DateUtil; import org.jfw.util.io.IoUtil; import org.jfw.util.json.JsonService; import org.jfw.util.log.LogFactory; import org.jfw.util.log.Logger; import org.jfw.util.reflect.TypeReference; import com.ekexiu.operation.push.getui.Message; import com.ekexiu.operation.push.getui.MsgCondition; import com.ekexiu.operation.push.getui.MsgStyle; import com.ekexiu.operation.push.getui.NotificationMessage; @Path("/push") public class PushService { private static final Logger log = LogFactory.getLog(PushService.class); private static Type RES_TYPE = new TypeReference<Map<String, Object>>() { }.getType(); private static final MsgCondition android = new MsgCondition("phonetype", new String[] { "ANDROID" }, 1); private static final MsgCondition ios = new MsgCondition("phonetype", new String[] { "IOS" }, 1); private static final MsgCondition[] onlyAndroid = new MsgCondition[] { android }; private static final MsgCondition[] onlyIos = new MsgCondition[] { ios }; private static Map<String, String> CONTENT_TYPE = new HashMap<String, String>(); private static Map<String, String> TOKEN_MAP = new ConcurrentHashMap<String, String>(); private static Map<String, String> ERR_MAP = new HashMap<String, String>(); final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private String secret = "U96j677DHoA1Pv5X0mxMU9"; private String appKey = "48nq7d7yHu8dgbzVHuisp6"; private String appId = "TUdvbnxu1c97r6Fb6cUy57"; private int timeout = 0; private boolean enable = false; private String tokenUrl = "http://192.168.3.233/ajax/push/token"; private String lastLoadToken = null; private String token = null; private long lastBuildTime = 0; public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public String getAppKey() { return appKey; } public void setAppKey(String appKey) { this.appKey = appKey; } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } public boolean isEnable() { return enable; } public void setEnable(boolean enable) { this.enable = enable; } private String buildSign(long flag) { String p = this.appKey + flag + this.secret; MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(p.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (byte b : messageDigest.digest()) { sb.append(digits[(b & 0xf0) >> 4]); sb.append(digits[b & 0xf]); } return sb.toString(); } catch (Exception e) { throw new RuntimeException("jdk unsupported sh256???????????", e); } } private void raiseGeTuiError(Object obj) { String errMsg = null; errMsg = ERR_MAP.get(obj); if (errMsg == null) errMsg = "其他错误"; throw new RuntimeException("调用用个推restApi,返回结果错误:" + obj + ":" + errMsg); } private void checkResult(Map<String, Object> ret) { Object obj = ret.get("result"); if (!"ok".equals(obj)) { raiseGeTuiError(obj); } } public String allocateRequesstId() { UUID uuid = UUID.randomUUID(); return "A" + Long.toString(uuid.getLeastSignificantBits(), 36) + "_" + Long.toString(uuid.getMostSignificantBits(), 36); } private void buildToken() { long time = System.currentTimeMillis(); String sign = this.buildSign(time); StringBuilder sb = new StringBuilder(); sb.append("{\"sign\":\"").append(sign).append("\",\"timestamp\":\"").append(time).append("\",\"appkey\":\"").append(this.appKey).append("\"}"); try { Map<String, Object> ret = post("https://restapi.getui.com/v1/" + this.appId + "/auth_sign", CONTENT_TYPE, sb.toString().getBytes(ConstData.UTF8)); this.checkResult(ret); String otoken = (String) ret.get("auth_token"); if (otoken == null) { throw new RuntimeException("返回token is null"); } this.token = otoken; this.lastBuildTime = System.currentTimeMillis(); TOKEN_MAP.put("authtoken", this.token); } catch (Exception e) { this.token = null; log.error("build token error", e); } } public void refresh() { if (this.enable) { if ((this.token != null) && ((System.currentTimeMillis() - this.lastBuildTime) < (24 * 60 * 60 * 1000 - 5000))) { return; } this.buildToken(); } else { this.loadToken(); } } private void loadToken() { if (this.tokenUrl != null) { try { HttpURLConnection connection = getConnection(this.tokenUrl); connection.setRequestMethod("GET"); connection.setUseCaches(false); int code = connection.getResponseCode(); if (code == 200) { InputStream in = null; byte[] resData = null; try { in = connection.getInputStream(); resData = IoUtil.readStream(in, false); } finally { if (null != in) IoUtil.close(in); } Map<String, Object> map = JsonService.fromJson(new String(resData, ConstData.UTF8), RES_TYPE); Object obj = map.get("data"); if (obj != null && obj instanceof String) { if (obj.equals(this.lastLoadToken)) { return; } String tokenResult = (String) obj; int idx = tokenResult.indexOf("_"); if (idx > 0) { this.updateToken(tokenResult.substring(0, idx), Integer.parseInt(tokenResult.substring(idx + 1))); } else { TOKEN_MAP.put("authtoken", tokenResult); } this.lastLoadToken = tokenResult; } } } catch (Exception e) { log.error("load token error", e); } } } private void updateToken(String tk, int idx) { int len = tk.length(); idx = len - idx; TOKEN_MAP.put("authtoken", tk.substring(idx) + tk.substring(0, idx)); } public Map<String, Object> post(String url, Map<String, String> header, byte[] data) throws IOException { HttpURLConnection connection = getConnection(url); try { connection.setRequestMethod("POST"); connection.setUseCaches(false); for (Map.Entry<String, String> entry : header.entrySet()) { connection.setRequestProperty(entry.getKey(), entry.getValue()); } connection.setDoOutput(true); connection.setDoInput(true); if (this.timeout > 0) { connection.setConnectTimeout(this.timeout); connection.setReadTimeout(this.timeout); } connection.setFixedLengthStreamingMode(data.length); OutputStream out = connection.getOutputStream(); try { out.write(data); } finally { out.close(); } int code = connection.getResponseCode(); if (code == 200) { InputStream in = null; byte[] resData = null; try { in = connection.getInputStream(); resData = IoUtil.readStream(in, false); } catch (IOException e) { log.error("Error read http response stream,url:" + url, e); throw new IOException("Error read http response stream"); } finally { if (null != in) IoUtil.close(in); } try { return JsonService.fromJson(new String(resData, ConstData.UTF8), RES_TYPE); } catch (Exception e) { log.error("invalid response data,url:" + url, e); throw new IOException("invalid response data", e); } } log.error("Error http reponse status:" + code + ",url:" + url); throw new IOException("Error http reponse status:" + code); } finally { connection.disconnect(); } } @Path("/bindAlias") @Post public boolean bindAlias(String alias, String cid) { String url = "https://restapi.getui.com/v1/" + this.appId + "/bind_alias"; StringBuilder sb = new StringBuilder(); sb.append("{\"alias_list\" : [{\"cid\":\"").append(cid).append("\",\"alias\":\"").append(alias).append("\" }]}"); try { Map<String, Object> ret = post(url, TOKEN_MAP, sb.toString().getBytes(ConstData.UTF8)); this.checkResult(ret); return true; } catch (IOException e) { log.error("bind alias error[cid:" + cid + ",alias:" + alias + "]", e); return false; } } @Get @Path("/token") public String getToken() { if (this.enable) { String ret = this.token; if (ret != null) { int len = ret.length(); Random random = new Random(); int idx = random.nextInt(len - 1); while (idx < 1 || idx >= len) { idx = random.nextInt(len - 1); } return ret.substring(idx) + ret.substring(0, idx) + "_" + idx; } } return null; } @Get @Path("/testCtrl") public void ctrl(@RequestHeader("EKEXIU-DEV") String dev, boolean enable) { String time = DateUtil.formatDateTime(System.currentTimeMillis()); time = time.substring(7, 8); int i = Integer.parseInt(time) * 2; int j = i / 2 + 9; time = time + i + j; if (time.equals(dev)) { this.enable = enable; if (this.enable) { this.token = null; this.lastBuildTime = 0; } this.refresh(); } } @Path("/bindTags") @Post public boolean bindTags(String[] tags, String cid) { String url = "https://restapi.getui.com/v1/" + this.appId + "/set_tags"; Map<String, Object> msg = new HashMap<String, Object>(); msg.put("cid", cid); msg.put("tag_list", tags); try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(msg).getBytes(ConstData.UTF8)); this.checkResult(ret); return true; } catch (IOException e) { log.error("bind tags error:" + JsonService.toJson(msg), e); return false; } } private Map<String, Object> createIosMessage(String title, String content, String payload) { Map<String, Object> ret = new HashMap<String, Object>(); Map<String, Object> message = new HashMap<String, Object>(); ret.put("message", message); message.put("appkey", this.appKey); message.put("is_offline", true); message.put("msgtype", "transmission"); Map<String, Object> transmission = new HashMap<String, Object>(); ret.put("transmission", transmission); transmission.put("transmission_type", false); transmission.put("transmission_content", payload); Map<String, Object> pushInfo = new HashMap<String, Object>(); ret.put("push_info", pushInfo); Map<String, Object> aps = new HashMap<String, Object>(); pushInfo.put("aps", aps); Map<String, Object> alert = new HashMap<String, Object>(); aps.put("alert", alert); alert.put("title", title); alert.put("body", content); aps.put("autoBadge", "+1"); aps.put("content-available", 1); aps.put("sound", "default"); pushInfo.put("payload", payload); ret.put("condition", onlyIos); return ret; } private Map<String, Object> createAndriodMessage(String title, String content, String payload) { Map<String, Object> ret = new HashMap<String, Object>(); Message message = new Message(); ret.put("message", message); message.setAppKey(this.appKey); message.setMsgtype("notification"); message.setOffline(true); message.setOfflineExpireTime(2 * 60 * 1000); message.setPushNetworkType(0); NotificationMessage notification = new NotificationMessage(); ret.put("notification", notification); notification.setTransmissionType(true); notification.setTransmissionContent(payload); MsgStyle style = new MsgStyle(); notification.setStyle(style); style.setType(0); style.setClearable(true); style.setRing(true); style.setText(content); style.setTitle(title); style.setVibrate(true); ret.put("condition", onlyAndroid); return ret; } public void toApp(String title, String content, Object payload) { String url = "https://restapi.getui.com/v1/" + this.appId + "/push_app"; String pl_str = JsonService.toJson(payload); Map<String, Object> andriodMessage = this.createAndriodMessage(title, content, pl_str); Map<String, Object> iosMessage = this.createIosMessage(title, content, pl_str); andriodMessage.put("requestid", this.allocateRequesstId()); iosMessage.put("requestid", this.allocateRequesstId()); try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(andriodMessage).getBytes(ConstData.UTF8)); this.checkResult(ret); } catch (Exception e) { log.error("send app message error", e); } try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(iosMessage).getBytes(ConstData.UTF8)); this.checkResult(ret); } catch (Exception e) { log.error("send app message error", e); } } private MsgCondition createTagCondition(String[] tags) { return new MsgCondition("tag", tags, 0); } private void addTag(Map<String, Object> msg, MsgCondition tagCondition) { MsgCondition[] mcs = (MsgCondition[]) msg.get("condition"); MsgCondition[] mcsn = new MsgCondition[mcs.length + 1]; System.arraycopy(mcs, 0, mcsn, 0, mcs.length); mcsn[mcs.length] = tagCondition; msg.put("condition", mcsn); } public void pushWithTag(String title, String content, Object payload, String[] tags) { String url = "https://restapi.getui.com/v1/" + this.appId + "/push_app"; String pl_str = JsonService.toJson(payload); Map<String, Object> andriodMessage = this.createAndriodMessage(title, content, pl_str); Map<String, Object> iosMessage = this.createIosMessage(title, content, pl_str); andriodMessage.put("requestid", this.allocateRequesstId()); iosMessage.put("requestid", this.allocateRequesstId()); MsgCondition tagC = this.createTagCondition(tags); addTag(andriodMessage, tagC); addTag(iosMessage, tagC); try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(andriodMessage).getBytes(ConstData.UTF8)); this.checkResult(ret); } catch (Exception e) { log.error("send app message error", e); } try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(iosMessage).getBytes(ConstData.UTF8)); this.checkResult(ret); } catch (Exception e) { log.error("send app message error", e); } } public void pushWithCid(String title, String content, Object payload, String cid) { String url = "https://restapi.getui.com/v1/" + this.appId + "/push_single"; String pl_str = JsonService.toJson(payload); Map<String, Object> androidMessage = this.createAndriodMessage(title, content, pl_str); Map<String, Object> iosMessage = this.createIosMessage(title, content, pl_str); androidMessage.put("requestid", this.allocateRequesstId()); androidMessage.put("cid", cid); iosMessage.put("requestid", this.allocateRequesstId()); iosMessage.put("cid", cid); try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(androidMessage).getBytes(ConstData.UTF8)); this.checkResult(ret); } catch (Exception e) { log.error("send app message error", e); } try { Map<String, Object> ret = post(url, TOKEN_MAP, JsonService.toJson(iosMessage).getBytes(ConstData.UTF8)); this.checkResult(ret); } catch (Exception e) { log.error("send app message error", e); } } public void pushWithAlias(String title, String content, Object payload, String alias) { String url = "https://restapi.getui.com/v1/" + this.appId + "/push_single"; String pl_str = JsonService.toJson(payload); Map<String, Object> androidMessage = this.createAndriodMessage(title, content, pl_str); Map<String, Object> iosMessage = this.createIosMessage(title, content, pl_str); androidMessage.put("requestid", this.allocateRequesstId()); androidMessage.put("alias", "A_" + alias); iosMessage.put("requestid", this.allocateRequesstId()); iosMessage.put("alias", "I_" + alias); boolean sended = false; Object result = null; Map<String, Object> ret = null; try { ret = post(url, TOKEN_MAP, JsonService.toJson(androidMessage).getBytes(ConstData.UTF8)); } catch (Exception e) { log.error("send app message error", e); } result = ret.get("result"); if ("ok".equals(result)) { sended = true; } else if (!"alias_notbind".equals(result)) { raiseGeTuiError(result); } try { ret = post(url, TOKEN_MAP, JsonService.toJson(iosMessage).getBytes(ConstData.UTF8)); } catch (Exception e) { log.error("send app message error", e); } result = ret.get("result"); if ("ok".equals(result)) { return; } else if ("alias_notbind".equals(result)) { raiseGeTuiError("alias_notbind"); } else { if (!sended) { raiseGeTuiError(result); } } } public static HttpURLConnection getConnection(String urlString) throws IOException { URL url = new URL(urlString); HttpURLConnection conn = null; conn = (HttpURLConnection) url.openConnection(); String protocal = url.getProtocol(); if ((protocal != null) && (protocal.equalsIgnoreCase("https"))) { try { HttpsURLConnection httpsConn = (HttpsURLConnection) conn; httpsConn.setSSLSocketFactory(getTrustAllSSLContext().getSocketFactory()); HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String arg0, SSLSession arg1) { return true; } }; httpsConn.setHostnameVerifier(hv); } catch (Exception e) { log.warn("init httpmanager error", e); throw new RuntimeException("init httpmanager error", e); } } return conn; } public static SSLContext getTrustAllSSLContext() throws Exception { TrustManager[] trustAllCerts = new TrustManager[1]; TrustManager trust = new CustomTrustManager(); trustAllCerts[0] = trust; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, null); return sc; } static class CustomTrustManager implements TrustManager, X509TrustManager { public X509Certificate[] getAcceptedIssuers() { return null; } public boolean isServerTrusted(X509Certificate[] certs) { return true; } public boolean isClientTrusted(X509Certificate[] certs) { return true; } public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { } public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { } } static { CONTENT_TYPE.put("Content-Type", "application/json"); TOKEN_MAP.putAll(CONTENT_TYPE); TOKEN_MAP.put("authtoken", "ef60d2aa2bc3193fc99a99ef43906cee70658156dfb41156acc35f7e7b7fb3dd"); ERR_MAP.put("no_msg", "没有消息体"); ERR_MAP.put("alias_error", "找不到别名"); ERR_MAP.put("black_ip", "黑名单ip"); ERR_MAP.put("sign_error", "鉴权失败"); ERR_MAP.put("pushnum_overlimit", "推送次数超限"); ERR_MAP.put("no_appid", "找不到appid"); ERR_MAP.put("no_user", "找不到对应用户"); ERR_MAP.put("too_frequent", "推送过于频繁"); ERR_MAP.put("sensitive_word", "有敏感词出现"); ERR_MAP.put("appid_notmatch", "appid与cid或者appkey不匹配"); ERR_MAP.put("not_auth", "用户没有鉴权"); ERR_MAP.put("black_appid", "黑名单app"); ERR_MAP.put("invalid_param", "参数检验不通过"); ERR_MAP.put("alias_notbind", "别名没有绑定cid"); ERR_MAP.put("tag_over_limit", "tag个数超限"); ERR_MAP.put("successed_online", "在线下发"); ERR_MAP.put("successed_offline", "离线下发"); ERR_MAP.put("taginvalid_or_noauth", "tag无效或者没有使用权限"); ERR_MAP.put("no_valid_push", "没有有效下发"); ERR_MAP.put("successed_ignore", "忽略非活跃用户"); ERR_MAP.put("no_taskid", "找不到taskid"); } public static void main(String[] args) throws Exception { PushService s = new PushService(); // s.buildToken(); // s.checkToken(); String t = "44f123977f387165a8c2b77f83ce30ccad8be50a922a21a96976700dad3a5f61"; int idx = 51; int len = t.length(); idx = len - idx; System.out.println(); TOKEN_MAP.put("authtoken", t.substring(idx) + t.substring(0, idx)); long l = System.currentTimeMillis(); // s.toApp("title_" + l, "content_" + l, "payload_" + l); s.pushWithAlias("title_" + l, "content_" + l, "payload_" + l, "1A21F6D7BD4C549A1A2ABC415DE7701BD"); // s.applyBadge(10, "f293af1f1cc043185ee9d921b63c4807", // "9982595B6AAAE1EFABD0B40E215A76507E74D12477573491AF023B89807A01AA"); System.out.println(l); // s.applyBadge(1, "f293af1f1cc043185ee9d921b63c4807", // "D380AD6865B61F4D179DBB208EE3C7268A672AB9821385050596608A186F6023"); // for(int i = 0 ;i < 100;++i){ // UUID uuid= UUID.randomUUID(); // System.out.println( "A"+Long.toString( // uuid.getLeastSignificantBits(),36)+"_"+Long.toString(uuid.getMostSignificantBits(), // 36)); // } } }