├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── mpush │ ├── api │ ├── BindCallback.java │ ├── Client.java │ ├── ClientListener.java │ ├── Constants.java │ ├── Logger.java │ ├── Message.java │ ├── MessageHandler.java │ ├── PacketReader.java │ ├── PacketReceiver.java │ ├── PacketWriter.java │ ├── ack │ │ ├── AckCallback.java │ │ ├── AckContext.java │ │ ├── AckModel.java │ │ └── RetryCondition.java │ ├── connection │ │ ├── Cipher.java │ │ ├── Connection.java │ │ ├── SessionContext.java │ │ └── SessionStorage.java │ ├── http │ │ ├── HttpCallback.java │ │ ├── HttpMethod.java │ │ ├── HttpRequest.java │ │ └── HttpResponse.java │ ├── protocol │ │ ├── Command.java │ │ ├── ErrorCode.java │ │ ├── MPushProtocol.java │ │ └── Packet.java │ └── push │ │ ├── PushCallback.java │ │ ├── PushContext.java │ │ └── PushResult.java │ ├── client │ ├── AckRequestMgr.java │ ├── AllotClient.java │ ├── ClientConfig.java │ ├── ConnectThread.java │ ├── DefaultClientListener.java │ ├── HttpRequestMgr.java │ ├── MPushClient.java │ ├── MessageDispatcher.java │ └── TcpConnection.java │ ├── codec │ ├── AsyncPacketReader.java │ ├── AsyncPacketWriter.java │ ├── PacketDecoder.java │ └── PacketEncoder.java │ ├── handler │ ├── AckHandler.java │ ├── BaseMessageHandler.java │ ├── ErrorMessageHandler.java │ ├── FastConnectOkHandler.java │ ├── HandshakeOkHandler.java │ ├── HeartbeatHandler.java │ ├── HttpProxyHandler.java │ ├── KickUserHandler.java │ ├── OkMessageHandler.java │ └── PushMessageHandler.java │ ├── message │ ├── AckMessage.java │ ├── BaseMessage.java │ ├── BindUserMessage.java │ ├── ByteBufMessage.java │ ├── ErrorMessage.java │ ├── FastConnectMessage.java │ ├── FastConnectOkMessage.java │ ├── HandshakeMessage.java │ ├── HandshakeOkMessage.java │ ├── HttpRequestMessage.java │ ├── HttpResponseMessage.java │ ├── KickUserMessage.java │ ├── OkMessage.java │ └── PushMessage.java │ ├── security │ ├── AesCipher.java │ ├── CipherBox.java │ └── RsaCipher.java │ ├── session │ ├── FileSessionStorage.java │ └── PersistentSession.java │ └── util │ ├── ByteBuf.java │ ├── DefaultLogger.java │ ├── IOUtils.java │ ├── MPUtils.java │ ├── Strings.java │ ├── crypto │ ├── AESUtils.java │ ├── Base64.java │ ├── Base64Utils.java │ ├── MD5Utils.java │ └── RSAUtils.java │ └── thread │ ├── EventLock.java │ ├── ExecutorManager.java │ └── NamedThreadFactory.java └── test └── java └── com └── mpush └── client └── MPushClientTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.classpath 3 | *.project 4 | */.settings/* 5 | */target/* 6 | */bin/* 7 | */WebContent/* 8 | /*/*.iml 9 | 10 | .idea/ 11 | 12 | target/ 13 | 14 | # Mobile Tools for Java (J2ME) 15 | .mtj.tmp/ 16 | 17 | # Package Files # 18 | *.jar 19 | *.war 20 | *.ear 21 | *.iml 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | #### mpush-client-java是一个纯java实现的一个MPUS客户端,不依赖其他任何第三方框架。 3 | 4 | ## 用途 5 | #### 主要用于android sdk底层通信,该工程本身不包含任何android相关代码。 6 | 7 | ## 当前版本 8 | 9 | ```groovy 10 | compile 'com.github.mpusher:mpush-client-java:0.0.2' 11 | ``` 12 | 13 | ```xml 14 | 15 | com.github.mpusher 16 | mpush-client-java 17 | 0.0.2 18 | 19 | ``` 20 | 21 | ## 源码测试 22 | 23 | 参见 [`com.mpush.client.MPushClientTest.java`](https://github.com/mpusher/mpush-client-java/blob/master/src/test/java/com/mpush/client/MPushClientTest.java) 24 | ```java 25 | public class MPushClientTest { 26 | private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCghPCWCobG8nTD24juwSVataW7iViRxcTkey/B792VZEhuHjQvA3cAJgx2Lv8GnX8NIoShZtoCg3Cx6ecs+VEPD2fBcg2L4JK7xldGpOJ3ONEAyVsLOttXZtNXvyDZRijiErQALMTorcgi79M5uVX9/jMv2Ggb2XAeZhlLD28fHwIDAQAB";//公钥对应服务端的私钥 27 | private static final String allocServer = "http://127.0.0.1:9999/";//用于获取MPUSH server的ip:port, 用于负载均衡 28 | 29 | public static void main(String[] args) throws Exception { 30 | Client client = ClientConfig 31 | .build() 32 | .setPublicKey(publicKey) 33 | .setAllotServer(allocServer) 34 | .setDeviceId("1111111111") 35 | .setOsName("Android") 36 | .setOsVersion("6.0") 37 | .setClientVersion("2.0") 38 | .setUserId("doctor43test") 39 | .setSessionStorageDir(MPushClientTest.class.getResource("/").getFile()) 40 | .setLogger(new DefaultLogger()) 41 | .setLogEnabled(true) 42 | .setEnableHttpProxy(false) 43 | .setClientListener(new L()) 44 | .create(); 45 | client.start(); 46 | 47 | LockSupport.park(); 48 | } 49 | ``` 50 | #### 说明: 51 | 52 | allocServer的实现参照[AllocServer.java](https://github.com/mpusher/alloc/blob/master/src/main/java/com/shinemo/mpush/alloc/AllocServer.java) 53 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.sonatype.oss 8 | oss-parent 9 | 9 10 | 11 | com.github.mpusher 12 | mpush-client-java 13 | 0.8.1 14 | jar 15 | mpush-client-java 16 | MPUSH消息推送客户端SDK 17 | https://github.com/mpusher/mpush-client-java 18 | 19 | 20 | 21 | The Apache Software License, Version 2.0 22 | http://www.apache.org/licenses/LICENSE-2.0.txt 23 | repo 24 | 25 | 26 | 27 | 28 | master 29 | git@github.com:mpusher/mpush-client-java.git 30 | scm:git@github.com:mpusher/mpush-client-java.git 31 | scm:git@github.com:mpusher/mpush-client-java.git 32 | 33 | 34 | 35 | 36 | ohun 37 | ohun@live.cn 38 | mpusher 39 | 40 | 41 | 42 | 43 | 44 | release 45 | 46 | 47 | ossrh 48 | https://oss.sonatype.org/service/local/staging/deploy/maven2 49 | 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-source-plugin 56 | 57 | 58 | attach-sources 59 | 60 | jar-no-fork 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-javadoc-plugin 68 | 69 | 70 | attach-javadocs 71 | 72 | jar 73 | 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-gpg-plugin 80 | 81 | 82 | sign-artifacts 83 | verify 84 | 85 | sign 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | jar 95 | 96 | 97 | 98 | maven-jar-plugin 99 | 100 | 101 | 102 | false 103 | 104 | 105 | true 106 | 107 | ../lib/ 108 | 109 | com.mpush.test.Main 110 | 111 | 112 | 113 | 114 | 115 | package 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-compiler-plugin 128 | 3.1 129 | 130 | 1.7 131 | 1.7 132 | UTF-8 133 | 134 | 135 | 136 | org.apache.maven.plugins 137 | maven-surefire-plugin 138 | 2.4.2 139 | 140 | true 141 | 142 | 143 | 144 | 145 | 146 | 147 | junit 148 | junit 149 | test 150 | 4.10 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/BindCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | /** 23 | * Created by ohun on 16/10/17. 24 | * 25 | * @author ohun@live.cn (夜色) 26 | */ 27 | public interface BindCallback { 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/Client.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | import com.mpush.api.protocol.MPushProtocol; 24 | 25 | /** 26 | * Created by ohun on 2016/1/17. 27 | * 28 | * @author ohun@live.cn (夜色) 29 | */ 30 | public interface Client extends MPushProtocol { 31 | 32 | void start(); 33 | 34 | void stop(); 35 | 36 | void destroy(); 37 | 38 | boolean isRunning(); 39 | 40 | void onNetStateChange(boolean isConnected); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/ClientListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | /** 24 | * Created by ohun on 2016/1/23. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public interface ClientListener { 29 | 30 | void onConnected(Client client); 31 | 32 | void onDisConnected(Client client); 33 | 34 | void onHandshakeOk(Client client, int heartbeat); 35 | 36 | void onReceivePush(Client client, byte[] content, int messageId); 37 | 38 | void onKickUser(String deviceId, String userId); 39 | 40 | void onBind(boolean success, String userId); 41 | 42 | void onUnbind(boolean success, String userId); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | import java.nio.charset.Charset; 24 | 25 | /** 26 | * Created by ohun on 2015/12/23. 27 | * 28 | * @author ohun@live.cn (夜色) 29 | */ 30 | public interface Constants { 31 | Charset UTF_8 = Charset.forName("UTF-8"); 32 | 33 | int DEFAULT_SO_TIMEOUT = 1000 * 3;//客户端连接超时时间 34 | 35 | int DEFAULT_WRITE_TIMEOUT = 1000 * 10;//10s默认packet写超时 36 | 37 | byte[] EMPTY_BYTES = new byte[0]; 38 | 39 | int DEF_HEARTBEAT = 4 * 60 * 1000;//5min 默认心跳时间 40 | 41 | int DEF_COMPRESS_LIMIT = 1024;//1k 启用压缩阈值 42 | 43 | String DEF_OS_NAME = "android";//客户端OS 44 | 45 | int MAX_RESTART_COUNT = 10;//客户端重连次数超过该值,重连线程休眠10min后再重试 46 | int MAX_TOTAL_RESTART_COUNT = 1000;//客户端重连次数超过该值,将不再尝试重连 47 | 48 | int MAX_HB_TIMEOUT_COUNT = 2; 49 | 50 | String HTTP_HEAD_READ_TIMEOUT = "readTimeout"; 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/Logger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | /** 24 | * Created by ohun on 2016/1/25. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public interface Logger { 29 | 30 | void enable(boolean enabled); 31 | 32 | void d(String s, Object... args); 33 | 34 | void i(String s, Object... args); 35 | 36 | void w(String s, Object... args); 37 | 38 | void e(Throwable e, String s, Object... args); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | 26 | /** 27 | * Created by ohun on 2016/1/17. 28 | * 29 | * @author ohun@live.cn (夜色) 30 | */ 31 | public interface Message { 32 | 33 | Connection getConnection(); 34 | 35 | void decodeBody(); 36 | 37 | void encodeBody(); 38 | 39 | void send(); 40 | 41 | void sendRaw(); 42 | 43 | Packet getPacket(); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/MessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | 26 | /** 27 | * Created by ohun on 2016/1/23. 28 | * 29 | * @author ohun@live.cn (夜色) 30 | */ 31 | public interface MessageHandler { 32 | void handle(Packet packet, Connection connection); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/PacketReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | /** 24 | * Created by ohun on 2016/1/17. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public interface PacketReader { 29 | void startRead(); 30 | 31 | void stopRead(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/PacketReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | 26 | /** 27 | * Created by ohun on 2016/1/17. 28 | * 29 | * @author ohun@live.cn (夜色) 30 | */ 31 | public interface PacketReceiver { 32 | 33 | void onReceive(Packet packet, Connection connection); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/PacketWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api; 21 | 22 | 23 | import com.mpush.api.protocol.Packet; 24 | 25 | /** 26 | * Created by ohun on 2016/1/17. 27 | * 28 | * @author ohun@live.cn (夜色) 29 | */ 30 | public interface PacketWriter { 31 | void write(Packet packet); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/ack/AckCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.ack; 21 | 22 | import com.mpush.api.protocol.Packet; 23 | 24 | /** 25 | * Created by ohun on 2016/11/13. 26 | * 27 | * @author ohun@live.cn (夜色) 28 | */ 29 | public interface AckCallback { 30 | void onSuccess(Packet response); 31 | 32 | void onTimeout(Packet request); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/ack/AckContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.ack; 21 | 22 | import com.mpush.api.protocol.Packet; 23 | 24 | /** 25 | * Created by ohun on 2016/11/13. 26 | * 27 | * @author ohun@live.cn (夜色) 28 | */ 29 | public class AckContext { 30 | public AckCallback callback; 31 | public AckModel ackModel = AckModel.AUTO_ACK; 32 | public int timeout = 1000; 33 | public Packet request; 34 | public int retryCount; 35 | public RetryCondition retryCondition; 36 | 37 | public static AckContext build(AckCallback callback) { 38 | AckContext context = new AckContext(); 39 | context.setCallback(callback); 40 | return context; 41 | } 42 | 43 | public AckCallback getCallback() { 44 | return callback; 45 | } 46 | 47 | public AckContext setCallback(AckCallback callback) { 48 | this.callback = callback; 49 | return this; 50 | } 51 | 52 | public AckModel getAckModel() { 53 | return ackModel; 54 | } 55 | 56 | public AckContext setAckModel(AckModel ackModel) { 57 | this.ackModel = ackModel; 58 | return this; 59 | } 60 | 61 | public int getTimeout() { 62 | return timeout; 63 | } 64 | 65 | public AckContext setTimeout(int timeout) { 66 | this.timeout = timeout; 67 | return this; 68 | } 69 | 70 | public Packet getRequest() { 71 | return request; 72 | } 73 | 74 | public AckContext setRequest(Packet request) { 75 | this.request = request; 76 | return this; 77 | } 78 | 79 | public int getRetryCount() { 80 | return retryCount; 81 | } 82 | 83 | public AckContext setRetryCount(int retryCount) { 84 | this.retryCount = retryCount; 85 | return this; 86 | } 87 | 88 | public RetryCondition getRetryCondition() { 89 | return retryCondition; 90 | } 91 | 92 | public AckContext setRetryCondition(RetryCondition retryCondition) { 93 | this.retryCondition = retryCondition; 94 | return this; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/ack/AckModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.ack; 21 | 22 | import com.mpush.api.protocol.Packet; 23 | 24 | /** 25 | * Created by ohun on 16/9/6. 26 | * 27 | * @author ohun@live.cn (夜色) 28 | */ 29 | public enum AckModel { 30 | NO_ACK((byte) 0),//不需要ACK 31 | AUTO_ACK(Packet.FLAG_AUTO_ACK),//客户端收到消息后自动确认消息 32 | BIZ_ACK(Packet.FLAG_BIZ_ACK);//由客户端业务自己确认消息是否到达 33 | public final byte flag; 34 | 35 | AckModel(byte flag) { 36 | this.flag = flag; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/ack/RetryCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.ack; 21 | 22 | import com.mpush.api.connection.Connection; 23 | import com.mpush.api.protocol.Packet; 24 | 25 | /** 26 | * Created by ohun on 18/9/29. 27 | * 28 | * @author ohun@live.cn (夜色) 29 | */ 30 | public interface RetryCondition { 31 | boolean test(Connection connection, Packet packet); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/connection/Cipher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.connection; 21 | 22 | 23 | /** 24 | * Created by ohun on 2015/12/28. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public interface Cipher { 29 | 30 | byte[] decrypt(byte[] data); 31 | 32 | byte[] encrypt(byte[] data); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/connection/Connection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.connection; 21 | 22 | 23 | import com.mpush.api.Client; 24 | import com.mpush.api.protocol.Packet; 25 | 26 | import java.nio.channels.SocketChannel; 27 | 28 | /** 29 | * Created by ohun on 2015/12/22. 30 | * 31 | * @author ohun@live.cn (夜色) 32 | */ 33 | public interface Connection { 34 | 35 | void connect(); 36 | 37 | void close(); 38 | 39 | void reconnect(); 40 | 41 | void send(Packet packet);//TODO add send Listener 42 | 43 | boolean isConnected(); 44 | 45 | boolean isAutoConnect(); 46 | 47 | boolean isReadTimeout(); 48 | 49 | boolean isWriteTimeout(); 50 | 51 | void setLastReadTime(); 52 | 53 | void setLastWriteTime(); 54 | 55 | void resetTimeout(); 56 | 57 | SessionContext getSessionContext(); 58 | 59 | SocketChannel getChannel(); 60 | 61 | Client getClient(); 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/connection/SessionContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.connection; 21 | 22 | 23 | /** 24 | * Created by ohun on 2015/12/22. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public final class SessionContext { 29 | public int heartbeat; 30 | public Cipher cipher; 31 | public String bindUser; 32 | public String tags; 33 | 34 | public void changeCipher(Cipher cipher) { 35 | this.cipher = cipher; 36 | } 37 | 38 | public void setHeartbeat(int heartbeat) { 39 | this.heartbeat = heartbeat; 40 | } 41 | 42 | public SessionContext setBindUser(String bindUser) { 43 | this.bindUser = bindUser; 44 | return this; 45 | } 46 | 47 | public SessionContext setTags(String tags) { 48 | this.tags = tags; 49 | return this; 50 | } 51 | 52 | public boolean handshakeOk() { 53 | return heartbeat > 0; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "SessionContext{" + 59 | "heartbeat=" + heartbeat + 60 | ", cipher=" + cipher + 61 | ", bindUser='" + bindUser + '\'' + 62 | '}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/connection/SessionStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.connection; 21 | 22 | 23 | /** 24 | * Created by ohun on 2015/12/22. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public interface SessionStorage { 29 | void saveSession(String sessionContext); 30 | 31 | String getSession(); 32 | 33 | void clearSession(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/http/HttpCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.http; 21 | 22 | 23 | /** 24 | * Created by yxx on 2016/2/16. 25 | * 26 | * @author ohun@live.cn 27 | */ 28 | public interface HttpCallback { 29 | 30 | void onResponse(HttpResponse response); 31 | 32 | void onCancelled(); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/http/HttpMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.http; 21 | 22 | 23 | /** 24 | * Created by yxx on 2016/2/16. 25 | * 26 | * @author ohun@live.cn 27 | */ 28 | public interface HttpMethod { 29 | byte GET = 0; 30 | byte POST = 1; 31 | byte PUT = 2; 32 | byte DELETE = 3; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/http/HttpRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.http; 21 | 22 | 23 | import com.mpush.api.Constants; 24 | 25 | import java.io.UnsupportedEncodingException; 26 | import java.net.URLEncoder; 27 | import java.nio.charset.Charset; 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | import java.util.Scanner; 31 | 32 | import static com.mpush.api.Constants.HTTP_HEAD_READ_TIMEOUT; 33 | 34 | /** 35 | * Created by yxx on 2016/2/16. 36 | * 37 | * @author ohun@live.cn 38 | */ 39 | public final class HttpRequest { 40 | public static final String CONTENT_TYPE = "Content-Type"; 41 | public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded; charset="; 42 | public final byte method; 43 | public final String uri; 44 | private Map headers = new HashMap<>(); 45 | private byte[] body; 46 | private HttpCallback callback; 47 | private int timeout; 48 | 49 | public HttpRequest(byte method, String uri) { 50 | this.method = method; 51 | this.uri = uri; 52 | } 53 | 54 | public static HttpRequest buildGet(String uri) { 55 | return new HttpRequest(HttpMethod.GET, uri); 56 | } 57 | 58 | public static HttpRequest buildPost(String uri) { 59 | return new HttpRequest(HttpMethod.POST, uri); 60 | } 61 | 62 | public static HttpRequest buildPut(String uri) { 63 | return new HttpRequest(HttpMethod.PUT, uri); 64 | } 65 | 66 | public static HttpRequest buildDelete(String uri) { 67 | return new HttpRequest(HttpMethod.DELETE, uri); 68 | } 69 | 70 | public static HttpRequest build(byte method, String uri) { 71 | return new HttpRequest(method, uri); 72 | } 73 | 74 | public byte getMethod() { 75 | return method; 76 | } 77 | 78 | public String getUri() { 79 | return uri; 80 | } 81 | 82 | public Map getHeaders() { 83 | headers.put(HTTP_HEAD_READ_TIMEOUT, Integer.toString(timeout)); 84 | return headers; 85 | } 86 | 87 | public HttpRequest setHeaders(Map headers) { 88 | this.getHeaders().putAll(headers); 89 | return this; 90 | } 91 | 92 | public byte[] getBody() { 93 | return body; 94 | } 95 | 96 | public HttpRequest setBody(byte[] body, String contentType) { 97 | this.body = body; 98 | this.headers.put(CONTENT_TYPE, contentType); 99 | return this; 100 | } 101 | 102 | public HttpRequest setPostParam(Map headers, Charset paramsEncoding) { 103 | byte[] bytes = encodeParameters(headers, paramsEncoding.name()); 104 | setBody(bytes, CONTENT_TYPE_FORM + paramsEncoding.name()); 105 | return this; 106 | } 107 | 108 | public HttpRequest setPostParam(Map headers) { 109 | setPostParam(headers, Constants.UTF_8); 110 | return this; 111 | } 112 | 113 | public HttpCallback getCallback() { 114 | return callback; 115 | } 116 | 117 | public HttpRequest setCallback(HttpCallback callback) { 118 | this.callback = callback; 119 | return this; 120 | } 121 | 122 | public int getTimeout() { 123 | return timeout; 124 | } 125 | 126 | public HttpRequest setTimeout(int timeout) { 127 | this.timeout = timeout; 128 | return this; 129 | } 130 | 131 | /** 132 | * Converts params into an application/x-www-form-urlencoded encoded string. 133 | */ 134 | private byte[] encodeParameters(Map params, String paramsEncoding) { 135 | StringBuilder encodedParams = new StringBuilder(); 136 | try { 137 | for (Map.Entry entry : params.entrySet()) { 138 | encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding)); 139 | encodedParams.append('='); 140 | encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding)); 141 | encodedParams.append('&'); 142 | } 143 | return encodedParams.toString().getBytes(paramsEncoding); 144 | } catch (UnsupportedEncodingException uee) { 145 | throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee); 146 | } 147 | } 148 | 149 | @Override 150 | public String toString() { 151 | return "HttpRequest{" + 152 | "uri='" + uri + '\'' + 153 | ", method=" + method + 154 | ", timeout=" + timeout + 155 | '}'; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/http/HttpResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.http; 21 | 22 | 23 | import com.mpush.api.Constants; 24 | 25 | import java.util.Map; 26 | 27 | /** 28 | * Created by yxx on 2016/2/16. 29 | * 30 | * @author ohun@live.cn 31 | */ 32 | public final class HttpResponse { 33 | public final int statusCode; 34 | public final String reasonPhrase; 35 | public final Map headers; 36 | public final byte[] body; 37 | 38 | public HttpResponse(int statusCode, String reasonPhrase, Map headers, byte[] body) { 39 | this.statusCode = statusCode; 40 | this.reasonPhrase = reasonPhrase; 41 | this.headers = headers; 42 | this.body = body; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "HttpResponse{" + 48 | "statusCode=" + statusCode + 49 | ", reasonPhrase='" + reasonPhrase + '\'' + 50 | ", headers=" + headers + 51 | ", body=" + (body == null ? "" : new String(body, Constants.UTF_8)) + 52 | '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/protocol/Command.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.protocol; 21 | 22 | 23 | /** 24 | * Created by ohun on 2015/12/22. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public enum Command { 29 | HEARTBEAT(1), 30 | HANDSHAKE(2), 31 | LOGIN(3), 32 | LOGOUT(4), 33 | BIND(5), 34 | UNBIND(6), 35 | FAST_CONNECT(7), 36 | PAUSE(8), 37 | RESUME(9), 38 | ERROR(10), 39 | OK(11), 40 | HTTP_PROXY(12), 41 | KICK(13), 42 | GATEWAY_KICK(14), 43 | PUSH(15), 44 | GATEWAY_PUSH(16), 45 | NOTIFICATION(17), 46 | GATEWAY_NOTIFICATION(18), 47 | CHAT(19), 48 | GATEWAY_CHAT(20), 49 | GROUP(21), 50 | GATEWAY_GROUP(22), 51 | ACK(23), 52 | UNKNOWN(-1); 53 | 54 | Command(int cmd) { 55 | this.cmd = (byte) cmd; 56 | } 57 | 58 | public final byte cmd; 59 | 60 | public static Command toCMD(byte b) { 61 | if (b > 0 && b < values().length) return values()[b - 1]; 62 | return UNKNOWN; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/protocol/ErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.protocol; 21 | 22 | /** 23 | * Created by ohun on 2015/12/30. 24 | * 25 | * @author ohun@live.cn 26 | */ 27 | public enum ErrorCode { 28 | OFFLINE(1, "user offline"), 29 | PUSH_CLIENT_FAILURE(2, "push to client failure"), 30 | ROUTER_CHANGE(3, "router change"), 31 | ACK_TIMEOUT(4, "ack timeout"), 32 | DISPATCH_ERROR(100, "handle message error"), 33 | UNSUPPORTED_CMD(101, "unsupported command"), 34 | REPEAT_HANDSHAKE(102, "repeat handshake"), 35 | SESSION_EXPIRED(103, "session expired"), 36 | INVALID_DEVICE(104, "invalid device"), 37 | UNKNOWN(-1, "unknown"); 38 | 39 | ErrorCode(int code, String errorMsg) { 40 | this.errorMsg = errorMsg; 41 | this.errorCode = (byte) code; 42 | } 43 | 44 | public final byte errorCode; 45 | public final String errorMsg; 46 | 47 | public static ErrorCode toEnum(int code) { 48 | for (ErrorCode errorCode : values()) { 49 | if (errorCode.errorCode == code) { 50 | return errorCode; 51 | } 52 | } 53 | return UNKNOWN; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/protocol/MPushProtocol.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.protocol; 21 | 22 | 23 | import com.mpush.api.http.HttpRequest; 24 | import com.mpush.api.http.HttpResponse; 25 | import com.mpush.api.push.PushContext; 26 | 27 | import java.util.concurrent.Future; 28 | 29 | /** 30 | * Created by ohun on 2016/1/17. 31 | * 32 | * @author ohun@live.cn (夜色) 33 | */ 34 | public interface MPushProtocol { 35 | 36 | /** 37 | * 健康检查, 检测读写超时, 发送心跳 38 | * 39 | * @return true/false Client 40 | */ 41 | boolean healthCheck(); 42 | 43 | void fastConnect(); 44 | 45 | void handshake(); 46 | 47 | void bindUser(String userId, String tags); 48 | 49 | void unbindUser(); 50 | 51 | void ack(int messageId); 52 | 53 | Future push(PushContext context); 54 | 55 | Future sendHttp(HttpRequest request); 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/protocol/Packet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.protocol; 21 | 22 | 23 | import java.nio.ByteBuffer; 24 | 25 | /** 26 | * Created by ohun on 2015/12/19. 27 | * 28 | * @author ohun@live.cn (夜色) 29 | * bodyLength(4)+cmd(1)+cc(2)+flags(1)+sessionId(4)+lrc(1)+body(n) 30 | */ 31 | public final class Packet { 32 | public static final int HEADER_LEN = 13;//packet包头协议长度 33 | 34 | public static final byte FLAG_CRYPTO = 0x01;//packet包启用加密 35 | public static final byte FLAG_COMPRESS = 0x02;//packet包启用压缩 36 | public static final byte FLAG_BIZ_ACK = 0x04; 37 | public static final byte FLAG_AUTO_ACK = 0x08; 38 | 39 | public static final byte HB_PACKET_BYTE = -33; 40 | public static final Packet HB_PACKET = new Packet(Command.HEARTBEAT); 41 | 42 | public byte cmd; //命令 43 | public short cc; //校验码 暂时没有用到 44 | public byte flags; //特性,如是否加密,是否压缩等 45 | public int sessionId; // 会话id 46 | public byte lrc; // 校验,纵向冗余校验。只校验header 47 | public byte[] body; 48 | 49 | public Packet(byte cmd) { 50 | this.cmd = cmd; 51 | } 52 | 53 | public Packet(byte cmd, int sessionId) { 54 | this.cmd = cmd; 55 | this.sessionId = sessionId; 56 | } 57 | 58 | public Packet(Command cmd) { 59 | this.cmd = cmd.cmd; 60 | } 61 | 62 | public Packet(Command cmd, int sessionId) { 63 | this.cmd = cmd.cmd; 64 | this.sessionId = sessionId; 65 | } 66 | 67 | public int getBodyLength() { 68 | return body == null ? 0 : body.length; 69 | } 70 | 71 | public void addFlag(byte flag) { 72 | this.flags |= flag; 73 | } 74 | 75 | public boolean hasFlag(byte flag) { 76 | return (flags & flag) == flag; 77 | } 78 | 79 | public short calcCheckCode() { 80 | short checkCode = 0; 81 | if (body != null) { 82 | for (int i = 0; i < body.length; i++) { 83 | checkCode += (body[i] & 0x0ff); 84 | } 85 | } 86 | return checkCode; 87 | } 88 | 89 | public byte calcLrc() { 90 | byte[] data = ByteBuffer.allocate(HEADER_LEN - 1) 91 | .putInt(getBodyLength()) 92 | .put(cmd) 93 | .putShort(cc) 94 | .put(flags) 95 | .putInt(sessionId) 96 | .array(); 97 | byte lrc = 0; 98 | for (int i = 0; i < data.length; i++) { 99 | lrc ^= data[i]; 100 | } 101 | return lrc; 102 | } 103 | 104 | public boolean validCheckCode() { 105 | return calcCheckCode() == cc; 106 | } 107 | 108 | public boolean validLrc() { 109 | return (lrc ^ calcLrc()) == 0; 110 | } 111 | 112 | @Override 113 | public String toString() { 114 | return "Packet{" + 115 | "cmd=" + cmd + 116 | ", cc=" + cc + 117 | ", flags=" + flags + 118 | ", sessionId=" + sessionId + 119 | ", lrc=" + lrc + 120 | ", body=" + (body == null ? 0 : body.length) + 121 | '}'; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/push/PushCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.push; 21 | 22 | /** 23 | * Created by ohun on 16/10/13. 24 | * 25 | * @author ohun@live.cn (夜色) 26 | */ 27 | public interface PushCallback { 28 | 29 | void onSuccess(); 30 | 31 | void onTimeout(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/push/PushContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.push; 21 | 22 | import com.mpush.api.Constants; 23 | import com.mpush.api.ack.AckContext; 24 | import com.mpush.api.ack.AckModel; 25 | 26 | /** 27 | * Created by ohun on 16/10/13. 28 | * 29 | * @author ohun@live.cn (夜色) 30 | */ 31 | public final class PushContext extends AckContext { 32 | public byte[] content; 33 | 34 | public PushContext(byte[] content) { 35 | this.content = content; 36 | } 37 | 38 | public static PushContext build(byte[] content) { 39 | return new PushContext(content); 40 | } 41 | 42 | public static PushContext build(String content) { 43 | return new PushContext(content.getBytes(Constants.UTF_8)); 44 | } 45 | 46 | public byte[] getContent() { 47 | return content; 48 | } 49 | 50 | public PushContext setContent(byte[] content) { 51 | this.content = content; 52 | return this; 53 | } 54 | 55 | public AckModel getAckModel() { 56 | return ackModel; 57 | } 58 | 59 | public PushContext setAckModel(AckModel ackModel) { 60 | this.ackModel = ackModel; 61 | return this; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/api/push/PushResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.api.push; 21 | 22 | /** 23 | * Created by ohun on 16/10/13. 24 | * 25 | * @author ohun@live.cn (夜色) 26 | */ 27 | public final class PushResult { 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/AckRequestMgr.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | import com.mpush.api.Logger; 23 | import com.mpush.api.ack.AckCallback; 24 | import com.mpush.api.ack.AckContext; 25 | import com.mpush.api.ack.AckModel; 26 | import com.mpush.api.ack.RetryCondition; 27 | import com.mpush.api.connection.Connection; 28 | import com.mpush.api.protocol.Packet; 29 | import com.mpush.util.thread.ExecutorManager; 30 | 31 | import java.util.Map; 32 | import java.util.concurrent.*; 33 | 34 | /** 35 | * Created by ohun on 2016/11/13. 36 | * 37 | * @author ohun@live.cn (夜色) 38 | */ 39 | public final class AckRequestMgr { 40 | private static AckRequestMgr I; 41 | 42 | private final Logger logger = ClientConfig.I.getLogger(); 43 | 44 | private final Map queue = new ConcurrentHashMap<>(); 45 | private final ScheduledExecutorService timer = ExecutorManager.INSTANCE.getTimerThread(); 46 | private final Callable NONE = new Callable() { 47 | @Override 48 | public Boolean call() throws Exception { 49 | return Boolean.FALSE; 50 | } 51 | }; 52 | private Connection connection; 53 | 54 | 55 | public static AckRequestMgr I() { 56 | if (I == null) { 57 | synchronized (AckRequestMgr.class) { 58 | if (I == null) { 59 | I = new AckRequestMgr(); 60 | } 61 | } 62 | } 63 | return I; 64 | } 65 | 66 | private AckRequestMgr() { 67 | } 68 | 69 | public Future add(int sessionId, AckContext context) { 70 | if (context.ackModel == AckModel.NO_ACK) return null; 71 | if (context.callback == null) return null; 72 | return addTask(new RequestTask(sessionId, context)); 73 | } 74 | 75 | public RequestTask getAndRemove(int sessionId) { 76 | return queue.remove(sessionId); 77 | } 78 | 79 | 80 | public void clear() { 81 | for (RequestTask task : queue.values()) { 82 | try { 83 | task.future.cancel(true); 84 | } catch (Exception e) { 85 | } 86 | } 87 | } 88 | 89 | private RequestTask addTask(RequestTask task) { 90 | queue.put(task.sessionId, task); 91 | task.future = timer.schedule(task, task.timeout, TimeUnit.MILLISECONDS); 92 | return task; 93 | } 94 | 95 | public void setConnection(Connection connection) { 96 | this.connection = connection; 97 | } 98 | 99 | public final class RequestTask extends FutureTask implements Runnable { 100 | private final int timeout; 101 | private final long sendTime; 102 | private final int sessionId; 103 | private AckCallback callback; 104 | private Packet request; 105 | private Future future; 106 | private int retryCount; 107 | private RetryCondition retryCondition; 108 | 109 | private RequestTask(AckCallback callback, int timeout, int sessionId, Packet request, int retryCount, RetryCondition retryCondition) { 110 | super(NONE); 111 | this.callback = callback; 112 | this.timeout = timeout; 113 | this.sendTime = System.currentTimeMillis(); 114 | this.sessionId = sessionId; 115 | this.request = request; 116 | this.retryCount = retryCount; 117 | this.retryCondition = retryCondition; 118 | } 119 | 120 | private RequestTask(int sessionId, AckContext context) { 121 | this(context.callback, context.timeout, sessionId, context.request, context.retryCount, context.retryCondition); 122 | } 123 | 124 | @Override 125 | public boolean cancel(boolean mayInterruptIfRunning) { 126 | throw new UnsupportedOperationException(); 127 | } 128 | 129 | @Override 130 | public void run() { 131 | queue.remove(sessionId); 132 | timeout(); 133 | } 134 | 135 | public void timeout() { 136 | call(null); 137 | } 138 | 139 | public void success(Packet packet) { 140 | call(packet); 141 | } 142 | 143 | private void call(Packet response) { 144 | if (this.future.cancel(true)) { 145 | boolean success = response != null; 146 | this.set(success); 147 | if (callback != null) { 148 | if (success) { 149 | logger.d("receive one ack response, sessionId=%d, costTime=%d, request=%s, response=%s" 150 | , sessionId, (System.currentTimeMillis() - sendTime), request, response); 151 | callback.onSuccess(response); 152 | } else if (request != null && retryCount > 0) { 153 | if (retryCondition == null || retryCondition.test(connection, request)) { 154 | logger.w("one ack request timeout, retry=%d, sessionId=%d, costTime=%d, request=%s" 155 | , retryCount, sessionId, (System.currentTimeMillis() - sendTime), request); 156 | addTask(copy(retryCount - 1)); 157 | connection.send(request); 158 | } else { 159 | logger.w("one ack request timeout, but ignore by condition, retry=%d, sessionId=%d, costTime=%d, request=%s" 160 | , retryCount, sessionId, (System.currentTimeMillis() - sendTime), request); 161 | } 162 | } else { 163 | logger.w("one ack request timeout, sessionId=%d, costTime=%d, request=%s" 164 | , sessionId, (System.currentTimeMillis() - sendTime), request); 165 | callback.onTimeout(request); 166 | } 167 | } 168 | callback = null; 169 | request = null; 170 | retryCondition = null; 171 | } 172 | } 173 | 174 | private RequestTask copy(int retryCount) { 175 | return new RequestTask(callback, timeout, sessionId, request, retryCount, retryCondition); 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/AllotClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.api.Constants; 24 | import com.mpush.api.Logger; 25 | import com.mpush.util.IOUtils; 26 | 27 | import javax.net.ssl.*; 28 | import java.io.ByteArrayOutputStream; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.net.HttpURLConnection; 32 | import java.net.URL; 33 | import java.security.SecureRandom; 34 | import java.security.cert.CertificateException; 35 | import java.security.cert.X509Certificate; 36 | import java.util.ArrayList; 37 | import java.util.Arrays; 38 | import java.util.Collections; 39 | import java.util.List; 40 | 41 | import static com.mpush.api.Constants.DEFAULT_SO_TIMEOUT; 42 | 43 | /** 44 | * Created by yxx on 2016/6/8. 45 | * 46 | * @author ohun@live.cn (夜色) 47 | */ 48 | /*package*/ final class AllotClient { 49 | private List serverAddress = new ArrayList<>(); 50 | 51 | public List getServerAddress() { 52 | if (serverAddress.isEmpty()) { 53 | serverAddress = queryServerAddressList(); 54 | } 55 | return serverAddress; 56 | } 57 | 58 | public List queryServerAddressList() { 59 | ClientConfig config = ClientConfig.I; 60 | Logger logger = config.getLogger(); 61 | 62 | if (config.getAllotServer() == null) { 63 | if (config.getServerHost() != null) { 64 | serverAddress.add(config.getServerHost() + ":" + config.getServerPort()); 65 | } 66 | return serverAddress; 67 | } 68 | 69 | HttpURLConnection connection; 70 | try { 71 | URL url = new URL(config.getAllotServer()); 72 | connection = (HttpURLConnection) url.openConnection(); 73 | if (config.getAllotServer().startsWith("https")) { 74 | ((HttpsURLConnection) connection).setSSLSocketFactory(getSSLSocketFactory()); 75 | ((HttpsURLConnection) connection).setHostnameVerifier(new NullHostnameVerifier()); 76 | } 77 | connection.setConnectTimeout(DEFAULT_SO_TIMEOUT); 78 | connection.setReadTimeout(DEFAULT_SO_TIMEOUT); 79 | connection.setUseCaches(false); 80 | connection.setDoInput(true); 81 | connection.setDoOutput(false); 82 | int statusCode = connection.getResponseCode(); 83 | if (statusCode != HttpURLConnection.HTTP_OK) { 84 | logger.w("get server address failure statusCode=%d", statusCode); 85 | connection.disconnect(); 86 | return serverAddress; 87 | } 88 | } catch (Exception e) { 89 | logger.e(e, "get server address ex, when connect server. allot=%s", config.getAllotServer()); 90 | return Collections.emptyList(); 91 | } 92 | 93 | ByteArrayOutputStream out = new ByteArrayOutputStream(128); 94 | byte[] buffer = new byte[128]; 95 | InputStream in = null; 96 | try { 97 | in = connection.getInputStream(); 98 | int count; 99 | while ((count = in.read(buffer)) != -1) { 100 | out.write(buffer, 0, count); 101 | } 102 | } catch (IOException ioe) { 103 | logger.e(ioe, "get server address ex, when read result."); 104 | return serverAddress; 105 | } finally { 106 | IOUtils.close(in); 107 | connection.disconnect(); 108 | } 109 | 110 | byte[] content = out.toByteArray(); 111 | if (content.length > 0) { 112 | String result = new String(content, Constants.UTF_8); 113 | logger.w("get server address success result=%s", result); 114 | List serverAddress = new ArrayList<>(); 115 | serverAddress.addAll(Arrays.asList(result.split(","))); 116 | this.serverAddress = serverAddress; 117 | } else { 118 | logger.w("get server address failure return content empty."); 119 | } 120 | 121 | return serverAddress; 122 | } 123 | 124 | private SSLSocketFactory getSSLSocketFactory() { 125 | return getTrustAllContext().getSocketFactory(); 126 | } 127 | 128 | private SSLContext getTrustAllContext() { 129 | SSLContext sslContext = null; 130 | try { 131 | sslContext = SSLContext.getInstance("TLS"); 132 | sslContext.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom()); 133 | } catch (Exception e) { 134 | throw new RuntimeException(e); 135 | } 136 | return sslContext; 137 | } 138 | 139 | private static class TrustAnyTrustManager implements X509TrustManager { 140 | public void checkClientTrusted(X509Certificate[] chain, String authType) 141 | throws CertificateException { 142 | } 143 | 144 | public void checkServerTrusted(X509Certificate[] chain, String authType) 145 | throws CertificateException { 146 | } 147 | 148 | public X509Certificate[] getAcceptedIssuers() { 149 | return new X509Certificate[0]; 150 | } 151 | } 152 | 153 | private static class NullHostnameVerifier implements HostnameVerifier { 154 | 155 | @Override 156 | public boolean verify(String s, SSLSession sslSession) { 157 | return true; 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/ClientConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.api.Client; 24 | import com.mpush.api.ClientListener; 25 | import com.mpush.api.connection.SessionStorage; 26 | import com.mpush.session.FileSessionStorage; 27 | import com.mpush.util.DefaultLogger; 28 | import com.mpush.api.Constants; 29 | import com.mpush.api.Logger; 30 | 31 | /** 32 | * Created by ohun on 2016/1/17. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class ClientConfig { 37 | private final DefaultClientListener clientListener = new DefaultClientListener(); 38 | public static ClientConfig I = new ClientConfig(); 39 | private String allotServer; 40 | private String serverHost; 41 | private int serverPort; 42 | private String publicKey; 43 | private String deviceId; 44 | private String osName = Constants.DEF_OS_NAME; 45 | private String osVersion; 46 | private String clientVersion; 47 | private String userId; 48 | private String tags; 49 | private int maxHeartbeat = Constants.DEF_HEARTBEAT; 50 | private int minHeartbeat = Constants.DEF_HEARTBEAT; 51 | private int aesKeyLength = 16; 52 | private int compressLimit = Constants.DEF_COMPRESS_LIMIT; 53 | private SessionStorage sessionStorage; 54 | private String sessionStorageDir; 55 | private Logger logger; 56 | private boolean logEnabled; 57 | private boolean enableHttpProxy = true; 58 | private int handshakeTimeoutMills = 3000; 59 | private int handshakeRetryCount = 0; 60 | private int bindUserTimeoutMills = 3000; 61 | private int bindUserRetryCount = 1; 62 | 63 | public static ClientConfig build() { 64 | return I = new ClientConfig(); 65 | } 66 | 67 | public Client create() { 68 | return new MPushClient(this); 69 | } 70 | 71 | /*package*/ void destroy() { 72 | clientListener.setListener(null); 73 | I = new ClientConfig(); 74 | } 75 | 76 | public SessionStorage getSessionStorage() { 77 | if (sessionStorage == null) { 78 | sessionStorage = new FileSessionStorage(sessionStorageDir); 79 | } 80 | return sessionStorage; 81 | } 82 | 83 | public Logger getLogger() { 84 | if (logger == null) { 85 | logger = new DefaultLogger(); 86 | } 87 | return logger; 88 | } 89 | 90 | public ClientConfig setLogger(Logger logger) { 91 | this.logger = logger; 92 | this.getLogger().enable(logEnabled); 93 | return this; 94 | } 95 | 96 | public String getSessionStorageDir() { 97 | return sessionStorageDir; 98 | } 99 | 100 | public ClientConfig setSessionStorage(SessionStorage sessionStorage) { 101 | this.sessionStorage = sessionStorage; 102 | return this; 103 | } 104 | 105 | public ClientConfig setSessionStorageDir(String sessionStorageDir) { 106 | this.sessionStorageDir = sessionStorageDir; 107 | return this; 108 | } 109 | 110 | public String getAllotServer() { 111 | return allotServer; 112 | } 113 | 114 | public ClientConfig setAllotServer(String allotServer) { 115 | this.allotServer = allotServer; 116 | return this; 117 | } 118 | 119 | public String getDeviceId() { 120 | return deviceId; 121 | } 122 | 123 | public ClientConfig setDeviceId(String deviceId) { 124 | this.deviceId = deviceId; 125 | return this; 126 | } 127 | 128 | public String getOsName() { 129 | return osName; 130 | } 131 | 132 | public ClientConfig setOsName(String osName) { 133 | this.osName = osName; 134 | return this; 135 | } 136 | 137 | public String getOsVersion() { 138 | return osVersion; 139 | } 140 | 141 | public ClientConfig setOsVersion(String osVersion) { 142 | this.osVersion = osVersion; 143 | return this; 144 | } 145 | 146 | public String getClientVersion() { 147 | return clientVersion; 148 | } 149 | 150 | public ClientConfig setClientVersion(String clientVersion) { 151 | this.clientVersion = clientVersion; 152 | return this; 153 | } 154 | 155 | public int getMaxHeartbeat() { 156 | return maxHeartbeat; 157 | } 158 | 159 | public ClientConfig setMaxHeartbeat(int maxHeartbeat) { 160 | this.maxHeartbeat = maxHeartbeat; 161 | return this; 162 | } 163 | 164 | public int getMinHeartbeat() { 165 | return minHeartbeat; 166 | } 167 | 168 | public ClientConfig setMinHeartbeat(int minHeartbeat) { 169 | this.minHeartbeat = minHeartbeat; 170 | return this; 171 | } 172 | 173 | public int getAesKeyLength() { 174 | return aesKeyLength; 175 | } 176 | 177 | public ClientConfig setAesKeyLength(int aesKeyLength) { 178 | this.aesKeyLength = aesKeyLength; 179 | return this; 180 | } 181 | 182 | public String getPublicKey() { 183 | return publicKey; 184 | } 185 | 186 | public ClientConfig setPublicKey(String publicKey) { 187 | this.publicKey = publicKey; 188 | return this; 189 | } 190 | 191 | public int getCompressLimit() { 192 | return compressLimit; 193 | } 194 | 195 | public ClientConfig setCompressLimit(int compressLimit) { 196 | this.compressLimit = compressLimit; 197 | return this; 198 | } 199 | 200 | public ClientListener getClientListener() { 201 | return clientListener; 202 | } 203 | 204 | public ClientConfig setClientListener(ClientListener clientListener) { 205 | this.clientListener.setListener(clientListener); 206 | return this; 207 | } 208 | 209 | public String getUserId() { 210 | return userId; 211 | } 212 | 213 | public ClientConfig setUserId(String userId) { 214 | this.userId = userId; 215 | return this; 216 | } 217 | 218 | public boolean isLogEnabled() { 219 | return logEnabled; 220 | } 221 | 222 | public ClientConfig setLogEnabled(boolean logEnabled) { 223 | this.logEnabled = logEnabled; 224 | this.logger.enable(logEnabled); 225 | return this; 226 | } 227 | 228 | public boolean isEnableHttpProxy() { 229 | return enableHttpProxy; 230 | } 231 | 232 | public ClientConfig setEnableHttpProxy(boolean enableHttpProxy) { 233 | this.enableHttpProxy = enableHttpProxy; 234 | return this; 235 | } 236 | 237 | public String getServerHost() { 238 | return serverHost; 239 | } 240 | 241 | public ClientConfig setServerHost(String serverHost) { 242 | this.serverHost = serverHost; 243 | return this; 244 | } 245 | 246 | public int getServerPort() { 247 | return serverPort; 248 | } 249 | 250 | public ClientConfig setServerPort(int serverPort) { 251 | this.serverPort = serverPort; 252 | return this; 253 | } 254 | 255 | public String getTags() { 256 | return tags; 257 | } 258 | 259 | public ClientConfig setTags(String tags) { 260 | this.tags = tags; 261 | return this; 262 | } 263 | 264 | public int getHandshakeTimeoutMills() { 265 | return handshakeTimeoutMills; 266 | } 267 | 268 | public void setHandshakeTimeoutMills(int handshakeTimeoutMills) { 269 | this.handshakeTimeoutMills = handshakeTimeoutMills; 270 | } 271 | 272 | public int getHandshakeRetryCount() { 273 | return handshakeRetryCount; 274 | } 275 | 276 | public void setHandshakeRetryCount(int handshakeRetryCount) { 277 | this.handshakeRetryCount = handshakeRetryCount; 278 | } 279 | 280 | public int getBindUserTimeoutMills() { 281 | return bindUserTimeoutMills; 282 | } 283 | 284 | public void setBindUserTimeoutMills(int bindUserTimeoutMills) { 285 | this.bindUserTimeoutMills = bindUserTimeoutMills; 286 | } 287 | 288 | public int getBindUserRetryCount() { 289 | return bindUserRetryCount; 290 | } 291 | 292 | public void setBindUserRetryCount(int bindUserRetryCount) { 293 | this.bindUserRetryCount = bindUserRetryCount; 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/ConnectThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.util.thread.EventLock; 24 | import com.mpush.util.thread.ExecutorManager; 25 | 26 | import java.util.concurrent.Callable; 27 | 28 | /** 29 | * Created by yxx on 2016/6/9. 30 | * 31 | * @author ohun@live.cn (夜色) 32 | */ 33 | public class ConnectThread extends Thread { 34 | private volatile Callable runningTask; 35 | private volatile boolean runningFlag = true; 36 | private final EventLock connLock; 37 | public ConnectThread(EventLock connLock) { 38 | this.connLock = connLock; 39 | this.setName(ExecutorManager.START_THREAD_NAME); 40 | this.start(); 41 | } 42 | 43 | public synchronized void addConnectTask(Callable task) { 44 | Callable oldTask = runningTask; 45 | if (oldTask != null) { 46 | this.interrupt(); 47 | } 48 | runningTask = task; 49 | this.notify(); 50 | } 51 | 52 | public synchronized void shutdown() { 53 | this.runningFlag = false; 54 | this.interrupt(); 55 | } 56 | 57 | @Override 58 | public void run() { 59 | while (runningFlag) { 60 | try { 61 | synchronized (this) { 62 | while (runningTask == null) { 63 | this.wait(); 64 | } 65 | } 66 | if (runningTask.call()) { 67 | break; 68 | } 69 | } catch (InterruptedException e) { 70 | continue; 71 | } catch (Exception e) { 72 | ClientConfig.I.getLogger().e(e, "run connect task error"); 73 | break; 74 | } 75 | } 76 | //connLock.broadcast(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/DefaultClientListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.api.Client; 24 | import com.mpush.api.ClientListener; 25 | import com.mpush.util.thread.ExecutorManager; 26 | 27 | import java.util.concurrent.Executor; 28 | 29 | /*package*/ final class DefaultClientListener implements ClientListener { 30 | private final Executor executor = ExecutorManager.INSTANCE.getDispatchThread(); 31 | private ClientListener listener; 32 | 33 | public void setListener(ClientListener listener) { 34 | this.listener = listener; 35 | } 36 | 37 | @Override 38 | public void onConnected(final Client client) { 39 | if (listener != null) { 40 | executor.execute(new Runnable() { 41 | @Override 42 | public void run() { 43 | listener.onConnected(client); 44 | } 45 | }); 46 | } 47 | client.fastConnect(); 48 | } 49 | 50 | @Override 51 | public void onDisConnected(final Client client) { 52 | if (listener != null) { 53 | executor.execute(new Runnable() { 54 | @Override 55 | public void run() { 56 | listener.onDisConnected(client); 57 | } 58 | }); 59 | } 60 | AckRequestMgr.I().clear(); 61 | } 62 | 63 | @Override 64 | public void onHandshakeOk(final Client client, final int heartbeat) { 65 | if (listener != null) {//dispatcher已经使用了Executor,此处直接同步调用 66 | listener.onHandshakeOk(client, heartbeat); 67 | } 68 | client.bindUser(ClientConfig.I.getUserId(), ClientConfig.I.getTags()); 69 | } 70 | 71 | @Override 72 | public void onReceivePush(final Client client, final byte[] content, int messageId) { 73 | if (listener != null) {//dispatcher已经使用了Executor,此处直接同步调用 74 | listener.onReceivePush(client, content, messageId); 75 | } 76 | } 77 | 78 | @Override 79 | public void onKickUser(String deviceId, String userId) { 80 | if (listener != null) {//dispatcher已经使用了Executor,此处直接同步调用 81 | listener.onKickUser(deviceId, userId); 82 | } 83 | } 84 | 85 | @Override 86 | public void onBind(boolean success, String userId) { 87 | if (listener != null) {//dispatcher已经使用了Executor,此处直接同步调用 88 | listener.onBind(success, userId); 89 | } 90 | } 91 | 92 | @Override 93 | public void onUnbind(boolean success, String userId) { 94 | if (listener != null) {//dispatcher已经使用了Executor,此处直接同步调用 95 | listener.onUnbind(success, userId); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/HttpRequestMgr.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.api.http.HttpCallback; 24 | import com.mpush.api.http.HttpRequest; 25 | import com.mpush.api.Logger; 26 | import com.mpush.api.http.HttpResponse; 27 | import com.mpush.util.thread.ExecutorManager; 28 | 29 | import java.util.Map; 30 | import java.util.concurrent.Callable; 31 | import java.util.concurrent.ConcurrentHashMap; 32 | import java.util.concurrent.Executor; 33 | import java.util.concurrent.Future; 34 | import java.util.concurrent.FutureTask; 35 | import java.util.concurrent.ScheduledExecutorService; 36 | import java.util.concurrent.TimeUnit; 37 | 38 | import static java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT; 39 | 40 | /** 41 | * Created by yxx on 2016/2/16. 42 | * 43 | * @author ohun@live.cn 44 | */ 45 | public final class HttpRequestMgr { 46 | private static HttpRequestMgr I; 47 | private final Map queue = new ConcurrentHashMap<>(); 48 | private final ScheduledExecutorService timer = ExecutorManager.INSTANCE.getTimerThread(); 49 | private final Executor executor = ExecutorManager.INSTANCE.getDispatchThread(); 50 | //private final HttpResponse response404 = new HttpResponse(HTTP_NOT_FOUND, "Not Found", null, null); 51 | private final HttpResponse response408 = new HttpResponse(HTTP_CLIENT_TIMEOUT, "Request Timeout", null, null); 52 | private final Callable NONE = new Callable() { 53 | @Override 54 | public HttpResponse call() throws Exception { 55 | return response408; 56 | } 57 | }; 58 | private final Logger logger = ClientConfig.I.getLogger(); 59 | 60 | public static HttpRequestMgr I() { 61 | if (I == null) { 62 | synchronized (AckRequestMgr.class) { 63 | if (I == null) { 64 | I = new HttpRequestMgr(); 65 | } 66 | } 67 | } 68 | return I; 69 | } 70 | 71 | private HttpRequestMgr() { 72 | } 73 | 74 | public Future add(int sessionId, HttpRequest request) { 75 | RequestTask task = new RequestTask(sessionId, request); 76 | queue.put(sessionId, task); 77 | task.future = timer.schedule(task, task.timeout, TimeUnit.MILLISECONDS); 78 | return task; 79 | } 80 | 81 | public RequestTask getAndRemove(int sessionId) { 82 | return queue.remove(sessionId); 83 | } 84 | 85 | public final class RequestTask extends FutureTask implements Runnable { 86 | private HttpCallback callback; 87 | private final String uri; 88 | private final int timeout; 89 | private final long sendTime; 90 | private final int sessionId; 91 | private Future future; 92 | 93 | private RequestTask(int sessionId, HttpRequest request) { 94 | super(NONE); 95 | this.callback = request.getCallback(); 96 | this.timeout = request.getTimeout(); 97 | this.uri = request.uri; 98 | this.sendTime = System.currentTimeMillis(); 99 | this.sessionId = sessionId; 100 | } 101 | 102 | @Override 103 | public boolean cancel(boolean mayInterruptIfRunning) { 104 | boolean success = super.cancel(mayInterruptIfRunning); 105 | if (success) { 106 | if (future.cancel(true)) { 107 | queue.remove(sessionId); 108 | if (callback != null) { 109 | executor.execute(new Runnable() { 110 | @Override 111 | public void run() { 112 | callback.onCancelled(); 113 | } 114 | }); 115 | callback = null; 116 | } 117 | } 118 | } 119 | logger.d("one request task cancelled, sessionId=%d, costTime=%d, uri=%s", 120 | sessionId, (System.currentTimeMillis() - sendTime), uri); 121 | return success; 122 | } 123 | 124 | @Override 125 | public void run() { 126 | queue.remove(sessionId); 127 | setResponse(response408); 128 | } 129 | 130 | public void setResponse(HttpResponse response) { 131 | if (this.future.cancel(true)) { 132 | this.set(response); 133 | if (callback != null) { 134 | callback.onResponse(response); 135 | } 136 | callback = null; 137 | } 138 | logger.d("one request task end, sessionId=%d, costTime=%d, response=%d, uri=%s", 139 | sessionId, (System.currentTimeMillis() - sendTime), response.statusCode, uri); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/client/MessageDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.api.MessageHandler; 24 | import com.mpush.api.PacketReceiver; 25 | import com.mpush.api.connection.Connection; 26 | import com.mpush.api.protocol.Command; 27 | import com.mpush.api.protocol.Packet; 28 | import com.mpush.handler.*; 29 | import com.mpush.util.thread.ExecutorManager; 30 | import com.mpush.api.Logger; 31 | 32 | import java.util.HashMap; 33 | import java.util.Map; 34 | import java.util.concurrent.Executor; 35 | 36 | /** 37 | * Created by ohun on 2016/1/20. 38 | * 39 | * @author ohun@live.cn (夜色) 40 | */ 41 | public final class MessageDispatcher implements PacketReceiver { 42 | private final Executor executor = ExecutorManager.INSTANCE.getDispatchThread(); 43 | private final Map handlers = new HashMap<>(); 44 | private final Logger logger = ClientConfig.I.getLogger(); 45 | private final AckRequestMgr ackRequestMgr; 46 | 47 | public MessageDispatcher() { 48 | register(Command.HEARTBEAT, new HeartbeatHandler()); 49 | register(Command.FAST_CONNECT, new FastConnectOkHandler()); 50 | register(Command.HANDSHAKE, new HandshakeOkHandler()); 51 | register(Command.KICK, new KickUserHandler()); 52 | register(Command.OK, new OkMessageHandler()); 53 | register(Command.ERROR, new ErrorMessageHandler()); 54 | register(Command.PUSH, new PushMessageHandler()); 55 | register(Command.ACK, new AckHandler()); 56 | 57 | this.ackRequestMgr = AckRequestMgr.I(); 58 | } 59 | 60 | public void register(Command command, MessageHandler handler) { 61 | handlers.put(command.cmd, handler); 62 | } 63 | 64 | @Override 65 | public void onReceive(final Packet packet, final Connection connection) { 66 | final MessageHandler handler = handlers.get(packet.cmd); 67 | if (handler != null) { 68 | executor.execute(new Runnable() { 69 | @Override 70 | public void run() { 71 | try { 72 | doAckResponse(packet); 73 | handler.handle(packet, connection); 74 | } catch (Throwable throwable) { 75 | logger.e(throwable, "handle message error, packet=%s", packet); 76 | connection.reconnect(); 77 | } 78 | } 79 | }); 80 | } else { 81 | logger.w("<<< receive unsupported message, packet=%s", packet); 82 | //connection.reconnect(); 83 | } 84 | } 85 | 86 | private void doAckResponse(Packet packet) { 87 | AckRequestMgr.RequestTask task = ackRequestMgr.getAndRemove(packet.sessionId); 88 | if (task != null) { 89 | task.success(packet); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/codec/AsyncPacketReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.codec; 21 | 22 | 23 | import com.mpush.api.PacketReceiver; 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.util.thread.ExecutorManager; 27 | import com.mpush.client.ClientConfig; 28 | import com.mpush.api.Logger; 29 | import com.mpush.api.PacketReader; 30 | import com.mpush.util.thread.NamedThreadFactory; 31 | import com.mpush.util.ByteBuf; 32 | 33 | import java.io.IOException; 34 | import java.nio.ByteBuffer; 35 | import java.nio.channels.SocketChannel; 36 | 37 | /** 38 | * Created by ohun on 2016/1/17. 39 | * 40 | * @author ohun@live.cn (夜色) 41 | */ 42 | public final class AsyncPacketReader implements PacketReader, Runnable { 43 | private final NamedThreadFactory threadFactory = new NamedThreadFactory(ExecutorManager.READ_THREAD_NAME); 44 | private final Connection connection; 45 | private final PacketReceiver receiver; 46 | private final ByteBuf buffer; 47 | private final Logger logger; 48 | 49 | private Thread thread; 50 | 51 | public AsyncPacketReader(Connection connection, PacketReceiver receiver) { 52 | this.connection = connection; 53 | this.receiver = receiver; 54 | this.buffer = ByteBuf.allocateDirect(Short.MAX_VALUE);//默认读buffer大小为32k 55 | this.logger = ClientConfig.I.getLogger(); 56 | } 57 | 58 | @Override 59 | public synchronized void startRead() { 60 | this.thread = threadFactory.newThread(this); 61 | this.thread.start(); 62 | } 63 | 64 | @Override 65 | public synchronized void stopRead() { 66 | if (thread != null) { 67 | thread.interrupt(); 68 | thread = null; 69 | } 70 | } 71 | 72 | public void run() { 73 | try { 74 | this.buffer.clear(); 75 | while (connection.isConnected()) { 76 | ByteBuffer in = buffer.checkCapacity(1024).nioBuffer();//如果剩余空间不够每次增加1k 77 | if (!read(connection.getChannel(), in)) break; 78 | in.flip(); 79 | decodePacket(in); 80 | in.compact(); 81 | } 82 | } finally { 83 | logger.w("read an error, do reconnect!!!"); 84 | connection.reconnect(); 85 | } 86 | } 87 | 88 | private void decodePacket(ByteBuffer in) { 89 | Packet packet; 90 | while ((packet = PacketDecoder.decode(in)) != null) { 91 | // logger.d("decode one packet=%s", packet); 92 | receiver.onReceive(packet, connection); 93 | } 94 | } 95 | 96 | private boolean read(SocketChannel channel, ByteBuffer in) { 97 | int readCount; 98 | try { 99 | readCount = channel.read(in); 100 | connection.setLastReadTime(); 101 | } catch (IOException e) { 102 | logger.e(e, "read packet ex, do reconnect"); 103 | readCount = -1; 104 | sleep4Reconnect(); 105 | } 106 | return readCount > 0; 107 | } 108 | 109 | private void sleep4Reconnect() { 110 | try { 111 | Thread.sleep(500); 112 | } catch (InterruptedException e) { 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/codec/AsyncPacketWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.codec; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | import com.mpush.util.thread.ExecutorManager; 26 | import com.mpush.api.Logger; 27 | import com.mpush.api.PacketWriter; 28 | import com.mpush.client.ClientConfig; 29 | import com.mpush.util.ByteBuf; 30 | import com.mpush.util.thread.EventLock; 31 | 32 | import java.io.IOException; 33 | import java.nio.ByteBuffer; 34 | import java.util.concurrent.Executor; 35 | 36 | import static com.mpush.api.Constants.DEFAULT_WRITE_TIMEOUT; 37 | 38 | /** 39 | * Created by ohun on 2016/1/17. 40 | * 41 | * @author ohun@live.cn (夜色) 42 | */ 43 | public final class AsyncPacketWriter implements PacketWriter { 44 | private final Executor executor = ExecutorManager.INSTANCE.getWriteThread(); 45 | private final Logger logger; 46 | private final Connection connection; 47 | private final EventLock connLock; 48 | private final ByteBuf buffer; 49 | 50 | public AsyncPacketWriter(Connection connection, EventLock connLock) { 51 | this.connection = connection; 52 | this.connLock = connLock; 53 | this.buffer = ByteBuf.allocateDirect(1024);//默认写buffer为1k 54 | this.logger = ClientConfig.I.getLogger(); 55 | } 56 | 57 | public void write(Packet packet) { 58 | executor.execute(new WriteTask(packet)); 59 | } 60 | 61 | private class WriteTask implements Runnable { 62 | private final long sendTime = System.currentTimeMillis(); 63 | private final Packet packet; 64 | 65 | private WriteTask(Packet packet) { 66 | this.packet = packet; 67 | } 68 | 69 | @Override 70 | public void run() { 71 | buffer.clear(); 72 | PacketEncoder.encode(packet, buffer); 73 | buffer.flip(); 74 | ByteBuffer out = buffer.nioBuffer(); 75 | while (out.hasRemaining()) { 76 | if (connection.isConnected()) { 77 | try { 78 | connection.getChannel().write(out); 79 | connection.setLastWriteTime(); 80 | } catch (IOException e) { 81 | logger.e(e, "write packet ex, do reconnect, packet=%s", packet); 82 | if (isTimeout()) { 83 | logger.w("ignored timeout packet=%s, sendTime=%d", packet, sendTime); 84 | return; 85 | } 86 | connection.reconnect(); 87 | } 88 | } else if (isTimeout()) { 89 | logger.w("ignored timeout packet=%s, sendTime=%d", packet, sendTime); 90 | return; 91 | } else { 92 | connLock.await(DEFAULT_WRITE_TIMEOUT); 93 | } 94 | } 95 | logger.d("write packet end, packet=%s, costTime=%d", packet.cmd, (System.currentTimeMillis() - sendTime)); 96 | } 97 | 98 | public boolean isTimeout() { 99 | return System.currentTimeMillis() - sendTime > DEFAULT_WRITE_TIMEOUT; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/codec/PacketDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.codec; 21 | 22 | 23 | import com.mpush.api.protocol.Packet; 24 | 25 | import java.nio.ByteBuffer; 26 | 27 | /** 28 | * Created by ohun on 2016/1/17. 29 | * 30 | * @author ohun@live.cn (夜色) 31 | */ 32 | public final class PacketDecoder { 33 | 34 | public static Packet decode(ByteBuffer in) { 35 | Packet hp = decodeHeartbeat(in); 36 | if (hp != null) return hp; 37 | return decodeFrame(in); 38 | } 39 | 40 | private static Packet decodeHeartbeat(ByteBuffer in) { 41 | if (in.hasRemaining()) { 42 | in.mark(); 43 | if (in.get() == Packet.HB_PACKET_BYTE) { 44 | return Packet.HB_PACKET; 45 | } 46 | in.reset(); 47 | } 48 | return null; 49 | } 50 | 51 | private static Packet decodeFrame(ByteBuffer in) { 52 | if (in.remaining() >= Packet.HEADER_LEN) { 53 | in.mark(); 54 | int bufferSize = in.remaining(); 55 | int bodyLength = in.getInt(); 56 | if (bufferSize >= (bodyLength + Packet.HEADER_LEN)) { 57 | return readPacket(in, bodyLength); 58 | } 59 | in.reset(); 60 | } 61 | return null; 62 | } 63 | 64 | private static Packet readPacket(ByteBuffer in, int bodyLength) { 65 | byte command = in.get(); 66 | short cc = in.getShort(); 67 | byte flags = in.get(); 68 | int sessionId = in.getInt(); 69 | byte lrc = in.get(); 70 | byte[] body = null; 71 | if (bodyLength > 0) { 72 | body = new byte[bodyLength]; 73 | in.get(body); 74 | } 75 | Packet packet = new Packet(command); 76 | packet.cc = cc; 77 | packet.flags = flags; 78 | packet.sessionId = sessionId; 79 | packet.lrc = lrc; 80 | packet.body = body; 81 | return packet; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/codec/PacketEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.codec; 21 | 22 | 23 | import com.mpush.api.protocol.Command; 24 | import com.mpush.api.protocol.Packet; 25 | import com.mpush.util.ByteBuf; 26 | 27 | /** 28 | * Created by ohun on 2016/1/17. 29 | * 30 | * @author ohun@live.cn (夜色) 31 | */ 32 | public final class PacketEncoder { 33 | 34 | public static void encode(Packet packet, ByteBuf out) { 35 | 36 | if (packet.cmd == Command.HEARTBEAT.cmd) { 37 | out.put(Packet.HB_PACKET_BYTE); 38 | } else { 39 | out.putInt(packet.getBodyLength()); 40 | out.put(packet.cmd); 41 | out.putShort(packet.cc); 42 | out.put(packet.flags); 43 | out.putInt(packet.sessionId); 44 | out.put(packet.lrc); 45 | if (packet.getBodyLength() > 0) { 46 | out.put(packet.body); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/AckHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | import com.mpush.api.Logger; 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | import com.mpush.client.ClientConfig; 26 | import com.mpush.client.AckRequestMgr; 27 | import com.mpush.message.AckMessage; 28 | 29 | /** 30 | * Created by ohun on 16/9/5. 31 | * 32 | * @author ohun@live.cn (夜色) 33 | */ 34 | public class AckHandler extends BaseMessageHandler { 35 | 36 | private final Logger logger; 37 | private final AckRequestMgr ackRequestMgr; 38 | 39 | public AckHandler() { 40 | this.logger = ClientConfig.I.getLogger(); 41 | this.ackRequestMgr = AckRequestMgr.I(); 42 | } 43 | 44 | @Override 45 | public AckMessage decode(Packet packet, Connection connection) { 46 | return new AckMessage(packet, connection); 47 | } 48 | 49 | @Override 50 | public void handle(AckMessage message) { 51 | /*AckRequestMgr.RequestTask task = ackRequestMgr.getAndRemove(message.getSessionId()); 52 | if (task != null) { 53 | task.success(message.getPacket()); 54 | }*/ 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/BaseMessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.Message; 24 | import com.mpush.api.MessageHandler; 25 | import com.mpush.api.connection.Connection; 26 | import com.mpush.api.protocol.Packet; 27 | 28 | public abstract class BaseMessageHandler implements MessageHandler { 29 | public abstract T decode(Packet packet, Connection connection); 30 | 31 | public abstract void handle(T message); 32 | 33 | public void handle(Packet packet, Connection connection) { 34 | T t = decode(packet, connection); 35 | if (t != null) { 36 | t.decodeBody(); 37 | handle(t); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/ErrorMessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.Logger; 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Command; 26 | import com.mpush.api.protocol.Packet; 27 | import com.mpush.client.ClientConfig; 28 | import com.mpush.message.ErrorMessage; 29 | 30 | import static com.mpush.api.protocol.ErrorCode.REPEAT_HANDSHAKE; 31 | 32 | /** 33 | * Created by ohun on 2015/12/30. 34 | * 35 | * @author ohun@live.cn (夜色) 36 | */ 37 | public final class ErrorMessageHandler extends BaseMessageHandler { 38 | private final Logger logger = ClientConfig.I.getLogger(); 39 | 40 | @Override 41 | public ErrorMessage decode(Packet packet, Connection connection) { 42 | return new ErrorMessage(packet, connection); 43 | } 44 | 45 | @Override 46 | public void handle(ErrorMessage message) { 47 | logger.w(">>> receive an error message=%s", message); 48 | if (message.cmd == Command.FAST_CONNECT.cmd) { 49 | ClientConfig.I.getSessionStorage().clearSession(); 50 | message.getConnection().getClient().handshake(); 51 | } else if (message.cmd == Command.HANDSHAKE.cmd) { 52 | if (message.code != REPEAT_HANDSHAKE.errorCode //重复握手的错误消息直接忽略 53 | && !REPEAT_HANDSHAKE.errorMsg.equals(message.reason)) { 54 | message.getConnection().getClient().stop(); 55 | } 56 | } else { 57 | message.getConnection().reconnect(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/FastConnectOkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.ClientListener; 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.Logger; 26 | import com.mpush.client.ClientConfig; 27 | import com.mpush.api.protocol.Packet; 28 | import com.mpush.message.FastConnectOkMessage; 29 | 30 | /** 31 | * Created by ohun on 2016/1/23. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class FastConnectOkHandler extends BaseMessageHandler { 36 | private final Logger logger = ClientConfig.I.getLogger(); 37 | 38 | @Override 39 | public FastConnectOkMessage decode(Packet packet, Connection connection) { 40 | return new FastConnectOkMessage(packet, connection); 41 | } 42 | 43 | @Override 44 | public void handle(FastConnectOkMessage message) { 45 | logger.w(">>> fast connect ok, message=%s", message); 46 | message.getConnection().getSessionContext().setHeartbeat(message.heartbeat); 47 | ClientListener listener = ClientConfig.I.getClientListener(); 48 | listener.onHandshakeOk(message.getConnection().getClient(), message.heartbeat); 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/HandshakeOkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.ClientListener; 24 | import com.mpush.api.connection.SessionStorage; 25 | import com.mpush.session.PersistentSession; 26 | import com.mpush.client.ClientConfig; 27 | import com.mpush.api.Logger; 28 | import com.mpush.api.connection.Connection; 29 | import com.mpush.api.connection.SessionContext; 30 | import com.mpush.api.protocol.Packet; 31 | import com.mpush.message.HandshakeOkMessage; 32 | import com.mpush.security.AesCipher; 33 | import com.mpush.security.CipherBox; 34 | 35 | /** 36 | * Created by ohun on 2016/1/23. 37 | * 38 | * @author ohun@live.cn (夜色) 39 | */ 40 | public final class HandshakeOkHandler extends BaseMessageHandler { 41 | private final Logger logger = ClientConfig.I.getLogger(); 42 | 43 | @Override 44 | public HandshakeOkMessage decode(Packet packet, Connection connection) { 45 | return new HandshakeOkMessage(packet, connection); 46 | } 47 | 48 | @Override 49 | public void handle(HandshakeOkMessage message) { 50 | logger.w(">>> handshake ok message=%s", message); 51 | 52 | Connection connection = message.getConnection(); 53 | SessionContext context = connection.getSessionContext(); 54 | byte[] serverKey = message.serverKey; 55 | if (serverKey.length != CipherBox.INSTANCE.getAesKeyLength()) { 56 | logger.w("handshake error serverKey invalid message=%s", message); 57 | connection.reconnect(); 58 | return; 59 | } 60 | //设置心跳 61 | context.setHeartbeat(message.heartbeat); 62 | 63 | //更换密钥 64 | AesCipher cipher = (AesCipher) context.cipher; 65 | byte[] sessionKey = CipherBox.INSTANCE.mixKey(cipher.key, serverKey); 66 | context.changeCipher(new AesCipher(sessionKey, cipher.iv)); 67 | 68 | //触发握手成功事件 69 | 70 | ClientListener listener = ClientConfig.I.getClientListener(); 71 | listener.onHandshakeOk(connection.getClient(), message.heartbeat); 72 | 73 | //保存token 74 | saveToken(message, context); 75 | 76 | } 77 | 78 | private void saveToken(HandshakeOkMessage message, SessionContext context) { 79 | SessionStorage storage = ClientConfig.I.getSessionStorage(); 80 | if (storage == null || message.sessionId == null) return; 81 | PersistentSession session = new PersistentSession(); 82 | session.sessionId = message.sessionId; 83 | session.expireTime = message.expireTime; 84 | session.cipher = context.cipher; 85 | storage.saveSession(PersistentSession.encode(session)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/HeartbeatHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.api.Logger; 27 | import com.mpush.api.MessageHandler; 28 | import com.mpush.client.ClientConfig; 29 | 30 | /** 31 | * Created by ohun on 2015/12/30. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class HeartbeatHandler implements MessageHandler { 36 | private final Logger logger = ClientConfig.I.getLogger(); 37 | 38 | @Override 39 | public void handle(Packet packet, Connection connection) { 40 | logger.d(">>> receive heartbeat pong..."); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/HttpProxyHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.http.HttpResponse; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.client.HttpRequestMgr; 27 | import com.mpush.api.Logger; 28 | import com.mpush.client.ClientConfig; 29 | import com.mpush.message.HttpResponseMessage; 30 | 31 | /** 32 | * Created by ohun on 2015/12/30. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class HttpProxyHandler extends BaseMessageHandler { 37 | private final Logger logger = ClientConfig.I.getLogger(); 38 | private final HttpRequestMgr httpRequestMgr; 39 | 40 | public HttpProxyHandler() { 41 | this.httpRequestMgr = HttpRequestMgr.I(); 42 | } 43 | 44 | @Override 45 | public HttpResponseMessage decode(Packet packet, Connection connection) { 46 | return new HttpResponseMessage(packet, connection); 47 | } 48 | 49 | @Override 50 | public void handle(HttpResponseMessage message) { 51 | HttpRequestMgr.RequestTask task = httpRequestMgr.getAndRemove(message.getSessionId()); 52 | if (task != null) { 53 | HttpResponse response = new HttpResponse(message.statusCode, message.reasonPhrase, message.headers, message.body); 54 | task.setResponse(response); 55 | } 56 | logger.d(">>> receive one response, sessionId=%d, statusCode=%d", message.getSessionId(), message.statusCode); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/KickUserHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.ClientListener; 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.api.Logger; 27 | import com.mpush.client.ClientConfig; 28 | import com.mpush.message.KickUserMessage; 29 | 30 | /** 31 | * Created by ohun on 2016/1/23. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class KickUserHandler extends BaseMessageHandler { 36 | private Logger logger = ClientConfig.I.getLogger(); 37 | 38 | @Override 39 | public KickUserMessage decode(Packet packet, Connection connection) { 40 | return new KickUserMessage(packet, connection); 41 | } 42 | 43 | @Override 44 | public void handle(KickUserMessage message) { 45 | logger.w(">>> receive kickUser message=%s", message); 46 | ClientListener listener = ClientConfig.I.getClientListener(); 47 | listener.onKickUser(message.deviceId, message.userId); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/OkMessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.message.OkMessage; 27 | import com.mpush.api.Logger; 28 | import com.mpush.client.ClientConfig; 29 | 30 | /** 31 | * Created by ohun on 2015/12/30. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class OkMessageHandler extends BaseMessageHandler { 36 | private final Logger logger = ClientConfig.I.getLogger(); 37 | 38 | @Override 39 | public OkMessage decode(Packet packet, Connection connection) { 40 | return new OkMessage(packet, connection); 41 | } 42 | 43 | @Override 44 | public void handle(OkMessage message) { 45 | if (message.cmd == Command.BIND.cmd) { 46 | ClientConfig.I.getClientListener().onBind(true, message.getConnection().getSessionContext().bindUser); 47 | } else if (message.cmd == Command.UNBIND.cmd) { 48 | ClientConfig.I.getClientListener().onUnbind(true, null); 49 | } 50 | 51 | logger.w(">>> receive ok message=%s", message); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/handler/PushMessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.handler; 21 | 22 | 23 | import com.mpush.api.ClientListener; 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.message.AckMessage; 27 | import com.mpush.message.PushMessage; 28 | import com.mpush.client.ClientConfig; 29 | import com.mpush.api.Logger; 30 | 31 | /** 32 | * Created by ohun on 2015/12/30. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class PushMessageHandler extends BaseMessageHandler { 37 | private final Logger logger = ClientConfig.I.getLogger(); 38 | private final ClientListener listener = ClientConfig.I.getClientListener(); 39 | 40 | @Override 41 | public PushMessage decode(Packet packet, Connection connection) { 42 | return new PushMessage(packet, connection); 43 | } 44 | 45 | @Override 46 | public void handle(PushMessage message) { 47 | logger.d(">>> receive push message=%s", message.content.length); 48 | listener.onReceivePush(message.getConnection().getClient(), 49 | message.content, 50 | message.bizAck() ? message.getSessionId() : 0); 51 | if (message.autoAck()) { 52 | AckMessage.from(message).sendRaw(); 53 | logger.d("<<< send ack for push messageId=%d", message.getSessionId()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/AckMessage.java: -------------------------------------------------------------------------------- 1 | package com.mpush.message; 2 | 3 | import com.mpush.api.connection.Connection; 4 | import com.mpush.api.protocol.Command; 5 | import com.mpush.api.protocol.Packet; 6 | import com.mpush.util.ByteBuf; 7 | 8 | import java.nio.ByteBuffer; 9 | 10 | /** 11 | * Created by ohun on 16/9/5. 12 | * 13 | * @author ohun@live.cn (夜色) 14 | */ 15 | public class AckMessage extends ByteBufMessage { 16 | 17 | public AckMessage(int sessionId, Connection connection) { 18 | super(new Packet(Command.ACK, sessionId), connection); 19 | } 20 | 21 | public AckMessage(Packet packet, Connection connection) { 22 | super(packet, connection); 23 | } 24 | 25 | @Override 26 | protected void decode(ByteBuffer body) { 27 | 28 | } 29 | 30 | @Override 31 | protected void encode(ByteBuf body) { 32 | 33 | } 34 | 35 | 36 | public static AckMessage from(BaseMessage src) { 37 | return new AckMessage(new Packet(Command.ACK, src.getSessionId()), src.connection); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "AckMessage{" + 43 | "packet=" + packet + 44 | '}'; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/BaseMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.util.IOUtils; 24 | import com.mpush.client.ClientConfig; 25 | import com.mpush.api.Message; 26 | import com.mpush.api.connection.Connection; 27 | import com.mpush.api.connection.SessionContext; 28 | import com.mpush.api.protocol.Packet; 29 | 30 | import java.util.concurrent.atomic.AtomicInteger; 31 | 32 | /** 33 | * Created by ohun on 2015/12/28. 34 | * 35 | * @author ohun@live.cn (夜色) 36 | */ 37 | public abstract class BaseMessage implements Message { 38 | public static final byte STATUS_DECODED = 1; 39 | public static final byte STATUS_ENCODED = 2; 40 | private static final AtomicInteger SID_SEQ = new AtomicInteger(); 41 | protected final Packet packet; 42 | protected final Connection connection; 43 | protected byte status = 0; 44 | 45 | public BaseMessage(Packet packet, Connection connection) { 46 | this.packet = packet; 47 | this.connection = connection; 48 | } 49 | 50 | @Override 51 | public void decodeBody() { 52 | if ((status & STATUS_DECODED) != 0) return; 53 | else status |= STATUS_DECODED; 54 | 55 | if (packet.body != null && packet.body.length > 0) { 56 | //1.解密 57 | byte[] tmp = packet.body; 58 | if (packet.hasFlag(Packet.FLAG_CRYPTO)) { 59 | if (connection.getSessionContext().cipher != null) { 60 | tmp = connection.getSessionContext().cipher.decrypt(tmp); 61 | } 62 | } 63 | 64 | //2.解压 65 | if (packet.hasFlag(Packet.FLAG_COMPRESS)) { 66 | tmp = IOUtils.uncompress(tmp); 67 | } 68 | 69 | if (tmp.length == 0) { 70 | throw new RuntimeException("message decode ex"); 71 | } 72 | 73 | packet.body = tmp; 74 | decode(packet.body); 75 | } 76 | } 77 | 78 | @Override 79 | public void encodeBody() { 80 | if ((status & STATUS_ENCODED) != 0) return; 81 | else status |= STATUS_ENCODED; 82 | 83 | byte[] tmp = encode(); 84 | if (tmp != null && tmp.length > 0) { 85 | //1.压缩 86 | if (tmp.length > ClientConfig.I.getCompressLimit()) { 87 | byte[] result = IOUtils.compress(tmp); 88 | if (result.length > 0) { 89 | tmp = result; 90 | packet.addFlag(Packet.FLAG_COMPRESS); 91 | } 92 | } 93 | 94 | //2.加密 95 | SessionContext context = connection.getSessionContext(); 96 | if (context.cipher != null) { 97 | byte[] result = context.cipher.encrypt(tmp); 98 | if (result.length > 0) { 99 | tmp = result; 100 | packet.addFlag(Packet.FLAG_CRYPTO); 101 | } 102 | } 103 | packet.body = tmp; 104 | } 105 | } 106 | 107 | private void encodeBodyRaw() { 108 | if ((status & STATUS_ENCODED) != 0) return; 109 | else status |= STATUS_ENCODED; 110 | 111 | packet.body = encode(); 112 | } 113 | 114 | protected abstract void decode(byte[] body); 115 | 116 | protected abstract byte[] encode(); 117 | 118 | public Packet createResponse() { 119 | return new Packet(packet.cmd, packet.sessionId); 120 | } 121 | 122 | @Override 123 | public Packet getPacket() { 124 | return packet; 125 | } 126 | 127 | @Override 128 | public Connection getConnection() { 129 | return connection; 130 | } 131 | 132 | @Override 133 | public void send() { 134 | encodeBody(); 135 | connection.send(packet); 136 | } 137 | 138 | @Override 139 | public void sendRaw() { 140 | encodeBodyRaw(); 141 | connection.send(packet); 142 | } 143 | 144 | protected static int genSessionId() { 145 | return SID_SEQ.incrementAndGet(); 146 | } 147 | 148 | public int getSessionId() { 149 | return packet.sessionId; 150 | } 151 | 152 | @Override 153 | public String toString() { 154 | return "BaseMessage{" + 155 | "packet=" + packet + 156 | ", connection=" + connection + 157 | '}'; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/BindUserMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Command; 26 | import com.mpush.api.protocol.Packet; 27 | import com.mpush.util.ByteBuf; 28 | 29 | import java.nio.ByteBuffer; 30 | 31 | /** 32 | * Created by ohun on 2015/12/28. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class BindUserMessage extends ByteBufMessage { 37 | public String userId; 38 | public String alias; 39 | public String tags; 40 | 41 | private BindUserMessage(Command cmd, Connection connection) { 42 | super(new Packet(cmd, genSessionId()), connection); 43 | } 44 | 45 | public static BindUserMessage buildBind(Connection connection) { 46 | return new BindUserMessage(Command.BIND, connection); 47 | } 48 | 49 | public static BindUserMessage buildUnbind(Connection connection) { 50 | return new BindUserMessage(Command.UNBIND, connection); 51 | } 52 | 53 | @Override 54 | public void decode(ByteBuffer body) { 55 | userId = decodeString(body); 56 | alias = decodeString(body); 57 | tags = decodeString(body); 58 | } 59 | 60 | @Override 61 | public void encode(ByteBuf body) { 62 | encodeString(body, userId); 63 | encodeString(body, alias); 64 | encodeString(body, tags); 65 | } 66 | 67 | public BindUserMessage setUserId(String userId) { 68 | this.userId = userId; 69 | return this; 70 | } 71 | 72 | public BindUserMessage setAlias(String alias) { 73 | this.alias = alias; 74 | return this; 75 | } 76 | 77 | public BindUserMessage setTags(String tags) { 78 | this.tags = tags; 79 | return this; 80 | } 81 | 82 | @Override 83 | public String toString() { 84 | return "BindUserMessage{" + 85 | "userId='" + userId + '\'' + 86 | ", alias='" + alias + '\'' + 87 | ", tags='" + tags + '\'' + 88 | '}'; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/ByteBufMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | import com.mpush.util.ByteBuf; 26 | import com.mpush.api.Constants; 27 | 28 | import java.nio.ByteBuffer; 29 | 30 | /** 31 | * Created by ohun on 2015/12/28. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public abstract class ByteBufMessage extends BaseMessage { 36 | 37 | public ByteBufMessage(Packet message, Connection connection) { 38 | super(message, connection); 39 | } 40 | 41 | @Override 42 | protected void decode(byte[] body) { 43 | decode(ByteBuffer.wrap(body)); 44 | } 45 | 46 | @Override 47 | protected byte[] encode() { 48 | ByteBuf body = ByteBuf.allocate(1024); 49 | encode(body); 50 | return body.getArray(); 51 | } 52 | 53 | protected abstract void decode(ByteBuffer body); 54 | 55 | protected abstract void encode(ByteBuf body); 56 | 57 | protected void encodeString(ByteBuf body, String field) { 58 | encodeBytes(body, field == null ? null : field.getBytes(Constants.UTF_8)); 59 | } 60 | 61 | protected void encodeByte(ByteBuf body, byte field) { 62 | body.put(field); 63 | } 64 | 65 | protected void encodeInt(ByteBuf body, int field) { 66 | body.putInt(field); 67 | } 68 | 69 | protected void encodeLong(ByteBuf body, long field) { 70 | body.putLong(field); 71 | } 72 | 73 | protected void encodeBytes(ByteBuf body, byte[] field) { 74 | if (field == null || field.length == 0) { 75 | body.putShort(0); 76 | } else if (field.length < Short.MAX_VALUE) { 77 | body.putShort(field.length).put(field); 78 | } else { 79 | body.putShort(Short.MAX_VALUE).putInt(field.length - Short.MAX_VALUE).put(field); 80 | } 81 | } 82 | 83 | protected String decodeString(ByteBuffer body) { 84 | byte[] bytes = decodeBytes(body); 85 | if (bytes == null) return null; 86 | return new String(bytes, Constants.UTF_8); 87 | } 88 | 89 | protected byte[] decodeBytes(ByteBuffer body) { 90 | int fieldLength = body.getShort(); 91 | if (fieldLength == 0) return null; 92 | if (fieldLength == Short.MAX_VALUE) { 93 | fieldLength += body.getInt(); 94 | } 95 | byte[] bytes = new byte[fieldLength]; 96 | body.get(bytes); 97 | return bytes; 98 | } 99 | 100 | protected byte decodeByte(ByteBuffer body) { 101 | return body.get(); 102 | } 103 | 104 | protected int decodeInt(ByteBuffer body) { 105 | return body.getInt(); 106 | } 107 | 108 | protected long decodeLong(ByteBuffer body) { 109 | return body.getLong(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/ErrorMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.util.ByteBuf; 27 | 28 | import java.nio.ByteBuffer; 29 | 30 | /** 31 | * Created by ohun on 2015/12/28. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class ErrorMessage extends ByteBufMessage { 36 | public byte cmd; 37 | public byte code; 38 | public String reason; 39 | public String data; 40 | 41 | public ErrorMessage(byte cmd, Packet message, Connection connection) { 42 | super(message, connection); 43 | this.cmd = cmd; 44 | } 45 | 46 | public ErrorMessage(Packet message, Connection connection) { 47 | super(message, connection); 48 | } 49 | 50 | @Override 51 | public void decode(ByteBuffer body) { 52 | cmd = decodeByte(body); 53 | code = decodeByte(body); 54 | reason = decodeString(body); 55 | data = decodeString(body); 56 | } 57 | 58 | @Override 59 | public void encode(ByteBuf body) { 60 | encodeByte(body, cmd); 61 | encodeByte(body, code); 62 | encodeString(body, reason); 63 | encodeString(body, data); 64 | } 65 | 66 | public static ErrorMessage from(BaseMessage src) { 67 | return new ErrorMessage(src.packet.cmd, new Packet(Command.ERROR 68 | , src.packet.sessionId), src.connection); 69 | } 70 | 71 | public ErrorMessage setReason(String reason) { 72 | this.reason = reason; 73 | return this; 74 | } 75 | 76 | @Override 77 | public void send() { 78 | super.sendRaw(); 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return "ErrorMessage{" + 84 | "cmd=" + cmd + 85 | ", code=" + code + 86 | ", reason='" + reason + '\'' + 87 | '}'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/FastConnectMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.util.ByteBuf; 27 | 28 | import java.nio.ByteBuffer; 29 | 30 | /** 31 | * Created by ohun on 2015/12/25. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class FastConnectMessage extends ByteBufMessage { 36 | public String sessionId; 37 | public String deviceId; 38 | public int minHeartbeat; 39 | public int maxHeartbeat; 40 | 41 | public FastConnectMessage(Connection connection) { 42 | super(new Packet(Command.FAST_CONNECT, genSessionId()), connection); 43 | } 44 | 45 | public FastConnectMessage(Packet message, Connection connection) { 46 | super(message, connection); 47 | } 48 | 49 | @Override 50 | public void decode(ByteBuffer body) { 51 | sessionId = decodeString(body); 52 | deviceId = decodeString(body); 53 | minHeartbeat = decodeInt(body); 54 | maxHeartbeat = decodeInt(body); 55 | } 56 | 57 | @Override 58 | public void encode(ByteBuf body) { 59 | encodeString(body, sessionId); 60 | encodeString(body, deviceId); 61 | encodeInt(body, minHeartbeat); 62 | encodeInt(body, maxHeartbeat); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return "FastConnectMessage{" + 68 | "sessionId=" + packet.sessionId + 69 | ", sessionId='" + sessionId + '\'' + 70 | ", deviceId='" + deviceId + '\'' + 71 | ", minHeartbeat=" + minHeartbeat + 72 | ", maxHeartbeat=" + maxHeartbeat + 73 | '}'; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/FastConnectOkMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | import com.mpush.util.ByteBuf; 26 | 27 | import java.nio.ByteBuffer; 28 | 29 | /** 30 | * Created by ohun on 2015/12/28. 31 | * 32 | * @author ohun@live.cn (夜色) 33 | */ 34 | public final class FastConnectOkMessage extends ByteBufMessage { 35 | public int heartbeat; 36 | 37 | public FastConnectOkMessage(Packet message, Connection connection) { 38 | super(message, connection); 39 | } 40 | 41 | public static FastConnectOkMessage from(BaseMessage src) { 42 | return new FastConnectOkMessage(src.createResponse(), src.connection); 43 | } 44 | 45 | @Override 46 | public void decode(ByteBuffer body) { 47 | heartbeat = decodeInt(body); 48 | } 49 | 50 | @Override 51 | public void encode(ByteBuf body) { 52 | encodeInt(body, heartbeat); 53 | } 54 | 55 | public FastConnectOkMessage setHeartbeat(int heartbeat) { 56 | this.heartbeat = heartbeat; 57 | return this; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return "FastConnectOkMessage{" + 63 | "sessionId=" + packet.sessionId + 64 | ", heartbeat=" + heartbeat + 65 | '}'; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/HandshakeMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.util.ByteBuf; 27 | 28 | import java.nio.ByteBuffer; 29 | import java.util.Arrays; 30 | 31 | /** 32 | * Created by ohun on 2015/12/24. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class HandshakeMessage extends ByteBufMessage { 37 | public String deviceId; 38 | public String osName; 39 | public String osVersion; 40 | public String clientVersion; 41 | public byte[] iv; 42 | public byte[] clientKey; 43 | public int minHeartbeat; 44 | public int maxHeartbeat; 45 | public long timestamp; 46 | 47 | public HandshakeMessage(Connection connection) { 48 | super(new Packet(Command.HANDSHAKE, genSessionId()), connection); 49 | } 50 | 51 | public HandshakeMessage(Packet message, Connection connection) { 52 | super(message, connection); 53 | } 54 | 55 | @Override 56 | protected void decode(ByteBuffer body) { 57 | deviceId = decodeString(body); 58 | osName = decodeString(body); 59 | osVersion = decodeString(body); 60 | clientVersion = decodeString(body); 61 | iv = decodeBytes(body); 62 | clientKey = decodeBytes(body); 63 | minHeartbeat = decodeInt(body); 64 | maxHeartbeat = decodeInt(body); 65 | timestamp = decodeLong(body); 66 | } 67 | 68 | @Override 69 | protected void encode(ByteBuf body) { 70 | encodeString(body, deviceId); 71 | encodeString(body, osName); 72 | encodeString(body, osVersion); 73 | encodeString(body, clientVersion); 74 | encodeBytes(body, iv); 75 | encodeBytes(body, clientKey); 76 | encodeInt(body, minHeartbeat); 77 | encodeInt(body, maxHeartbeat); 78 | encodeLong(body, timestamp); 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return "HandshakeMessage{" + 84 | "sessionId=" + packet.sessionId + 85 | ", deviceId='" + deviceId + '\'' + 86 | ", osName='" + osName + '\'' + 87 | ", osVersion='" + osVersion + '\'' + 88 | ", clientVersion='" + clientVersion + '\'' + 89 | ", iv=" + Arrays.toString(iv) + 90 | ", clientKey=" + Arrays.toString(clientKey) + 91 | ", minHeartbeat=" + minHeartbeat + 92 | ", maxHeartbeat=" + maxHeartbeat + 93 | ", timestamp=" + timestamp + 94 | '}'; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/HandshakeOkMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.util.ByteBuf; 27 | 28 | import java.nio.ByteBuffer; 29 | import java.util.Arrays; 30 | 31 | /** 32 | * Created by ohun on 2015/12/27. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class HandshakeOkMessage extends ByteBufMessage { 37 | public byte[] serverKey; 38 | public int heartbeat; 39 | public String sessionId; 40 | public long expireTime; 41 | 42 | public HandshakeOkMessage(Packet message, Connection connection) { 43 | super(message, connection); 44 | } 45 | 46 | @Override 47 | public void decode(ByteBuffer body) { 48 | serverKey = decodeBytes(body); 49 | heartbeat = decodeInt(body); 50 | sessionId = decodeString(body); 51 | expireTime = decodeLong(body); 52 | } 53 | 54 | @Override 55 | public void encode(ByteBuf body) { 56 | encodeBytes(body, serverKey); 57 | encodeInt(body, heartbeat); 58 | encodeString(body, sessionId); 59 | encodeLong(body, expireTime); 60 | } 61 | 62 | public static HandshakeOkMessage from(BaseMessage src) { 63 | return new HandshakeOkMessage(src.createResponse(), src.connection); 64 | } 65 | 66 | public HandshakeOkMessage setServerKey(byte[] serverKey) { 67 | this.serverKey = serverKey; 68 | return this; 69 | } 70 | 71 | public HandshakeOkMessage setHeartbeat(int heartbeat) { 72 | this.heartbeat = heartbeat; 73 | return this; 74 | } 75 | 76 | public HandshakeOkMessage setSessionId(String sessionId) { 77 | this.sessionId = sessionId; 78 | return this; 79 | } 80 | 81 | public HandshakeOkMessage setExpireTime(long expireTime) { 82 | this.expireTime = expireTime; 83 | return this; 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | return "HandshakeOkMessage{" + 89 | "serverKey=" + Arrays.toString(serverKey) + 90 | ", heartbeat=" + heartbeat + 91 | ", sessionId='" + sessionId + '\'' + 92 | ", expireTime=" + expireTime + 93 | '}'; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/HttpRequestMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.util.MPUtils; 27 | import com.mpush.util.ByteBuf; 28 | 29 | import java.nio.ByteBuffer; 30 | import java.util.Map; 31 | 32 | /** 33 | * Created by ohun on 2016/2/15. 34 | * 35 | * @author ohun@live.cn (夜色) 36 | */ 37 | public final class HttpRequestMessage extends ByteBufMessage { 38 | public byte method; 39 | public String uri; 40 | public Map headers; 41 | public byte[] body; 42 | 43 | public HttpRequestMessage(Connection connection) { 44 | super(new Packet(Command.HTTP_PROXY, genSessionId()), connection); 45 | } 46 | 47 | public HttpRequestMessage(Packet message, Connection connection) { 48 | super(message, connection); 49 | } 50 | 51 | @Override 52 | public void decode(ByteBuffer body) { 53 | method = decodeByte(body); 54 | uri = decodeString(body); 55 | headers = MPUtils.headerFromString(decodeString(body)); 56 | this.body = decodeBytes(body); 57 | } 58 | 59 | @Override 60 | public void encode(ByteBuf body) { 61 | encodeByte(body, method); 62 | encodeString(body, uri); 63 | encodeString(body, MPUtils.headerToString(headers)); 64 | encodeBytes(body, this.body); 65 | } 66 | 67 | 68 | 69 | public String getMethod() { 70 | switch (method) { 71 | case 0: 72 | return "GET"; 73 | case 1: 74 | return "POST"; 75 | case 2: 76 | return "PUT"; 77 | case 3: 78 | return "DELETE"; 79 | } 80 | return "GET"; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/HttpResponseMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Packet; 25 | import com.mpush.util.ByteBuf; 26 | import com.mpush.util.MPUtils; 27 | 28 | import java.nio.ByteBuffer; 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | /** 33 | * Created by ohun on 2016/2/15. 34 | * 35 | * @author ohun@live.cn (夜色) 36 | */ 37 | public final class HttpResponseMessage extends ByteBufMessage { 38 | public int statusCode; 39 | public String reasonPhrase; 40 | public Map headers; 41 | public byte[] body; 42 | 43 | public HttpResponseMessage(Packet message, Connection connection) { 44 | super(message, connection); 45 | } 46 | 47 | @Override 48 | public void decode(ByteBuffer body) { 49 | statusCode = decodeInt(body); 50 | reasonPhrase = decodeString(body); 51 | headers = MPUtils.headerFromString(decodeString(body)); 52 | this.body = decodeBytes(body); 53 | } 54 | 55 | @Override 56 | public void encode(ByteBuf body) { 57 | encodeInt(body, statusCode); 58 | encodeString(body, reasonPhrase); 59 | encodeString(body, MPUtils.headerToString(headers)); 60 | encodeBytes(body, this.body); 61 | } 62 | 63 | public static HttpResponseMessage from(HttpRequestMessage src) { 64 | return new HttpResponseMessage(src.createResponse(), src.connection); 65 | } 66 | 67 | public HttpResponseMessage setStatusCode(int statusCode) { 68 | this.statusCode = statusCode; 69 | return this; 70 | } 71 | 72 | public HttpResponseMessage setReasonPhrase(String reasonPhrase) { 73 | this.reasonPhrase = reasonPhrase; 74 | return this; 75 | } 76 | 77 | public HttpResponseMessage addHeader(String name, String value) { 78 | if (headers == null) headers = new HashMap<>(); 79 | this.headers.put(name, value); 80 | return this; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/KickUserMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | 24 | import com.mpush.api.connection.Connection; 25 | import com.mpush.api.protocol.Command; 26 | import com.mpush.api.protocol.Packet; 27 | import com.mpush.util.ByteBuf; 28 | 29 | import java.nio.ByteBuffer; 30 | 31 | /** 32 | * Created by ohun on 2015/12/29. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class KickUserMessage extends ByteBufMessage { 37 | public String deviceId; 38 | public String userId; 39 | 40 | public KickUserMessage(Connection connection) { 41 | super(new Packet(Command.KICK), connection); 42 | } 43 | 44 | public KickUserMessage(Packet message, Connection connection) { 45 | super(message, connection); 46 | } 47 | 48 | @Override 49 | public void decode(ByteBuffer body) { 50 | deviceId = decodeString(body); 51 | userId = decodeString(body); 52 | } 53 | 54 | @Override 55 | public void encode(ByteBuf body) { 56 | encodeString(body, deviceId); 57 | encodeString(body, userId); 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return "KickUserMessage{" + 63 | "deviceId='" + deviceId + '\'' + 64 | ", userId='" + userId + '\'' + 65 | '}'; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/OkMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.connection.Connection; 26 | import com.mpush.api.protocol.Packet; 27 | import com.mpush.util.ByteBuf; 28 | 29 | import java.nio.ByteBuffer; 30 | 31 | /** 32 | * Created by ohun on 2015/12/28. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class OkMessage extends ByteBufMessage { 37 | public byte cmd; 38 | public byte code; 39 | public String data; 40 | 41 | public OkMessage(byte cmd, Packet message, Connection connection) { 42 | super(message, connection); 43 | this.cmd = cmd; 44 | } 45 | 46 | public OkMessage(Packet message, Connection connection) { 47 | super(message, connection); 48 | } 49 | 50 | @Override 51 | public void decode(ByteBuffer body) { 52 | cmd = decodeByte(body); 53 | code = decodeByte(body); 54 | data = decodeString(body); 55 | } 56 | 57 | @Override 58 | public void encode(ByteBuf body) { 59 | encodeByte(body, cmd); 60 | encodeByte(body, code); 61 | encodeString(body, data); 62 | } 63 | 64 | public static OkMessage from(BaseMessage src) { 65 | return new OkMessage(src.packet.cmd, new Packet(Command.OK 66 | , src.packet.sessionId), src.connection); 67 | } 68 | 69 | public OkMessage setCode(byte code) { 70 | this.code = code; 71 | return this; 72 | } 73 | 74 | public OkMessage setData(String data) { 75 | this.data = data; 76 | return this; 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "OkMessage{" + 82 | "cmd=" + cmd + 83 | ", code=" + code + 84 | ", data='" + data + '\'' + 85 | '}'; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/message/PushMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.message; 21 | 22 | 23 | import com.mpush.api.connection.Connection; 24 | import com.mpush.api.protocol.Command; 25 | import com.mpush.api.protocol.Packet; 26 | import com.mpush.api.Constants; 27 | 28 | /** 29 | * Created by ohun on 2015/12/30. 30 | * 31 | * @author ohun@live.cn (夜色) 32 | */ 33 | public final class PushMessage extends BaseMessage { 34 | 35 | public byte[] content; 36 | 37 | public PushMessage(byte[] content, Connection connection) { 38 | super(new Packet(Command.PUSH, genSessionId()), connection); 39 | this.content = content; 40 | } 41 | 42 | public PushMessage(Packet packet, Connection connection) { 43 | super(packet, connection); 44 | } 45 | 46 | @Override 47 | public void decode(byte[] body) { 48 | content = body; 49 | } 50 | 51 | @Override 52 | public byte[] encode() { 53 | return content; 54 | } 55 | 56 | public boolean autoAck() { 57 | return packet.hasFlag(Packet.FLAG_AUTO_ACK); 58 | } 59 | 60 | public boolean bizAck() { 61 | return packet.hasFlag(Packet.FLAG_BIZ_ACK); 62 | } 63 | 64 | public PushMessage addFlag(byte flag) { 65 | packet.addFlag(flag); 66 | return this; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "PushMessage{" + 72 | "content='" + content.length + '\'' + 73 | '}'; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/security/AesCipher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.security; 21 | 22 | 23 | 24 | import com.mpush.api.connection.Cipher; 25 | import com.mpush.util.crypto.AESUtils; 26 | 27 | /** 28 | * Created by ohun on 2015/12/28. 29 | * 30 | * @author ohun@live.cn (夜色) 31 | */ 32 | public final class AesCipher implements Cipher { 33 | public final byte[] key; 34 | public final byte[] iv; 35 | 36 | public AesCipher(byte[] key, byte[] iv) { 37 | this.key = key; 38 | this.iv = iv; 39 | } 40 | 41 | @Override 42 | public byte[] decrypt(byte[] data) { 43 | return AESUtils.decrypt(data, key, iv); 44 | } 45 | 46 | @Override 47 | public byte[] encrypt(byte[] data) { 48 | return AESUtils.encrypt(data, key, iv); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return toString(key) + ',' + toString(iv); 54 | } 55 | 56 | public String toString(byte[] a) { 57 | StringBuilder b = new StringBuilder(); 58 | for (int i = 0; i < a.length; i++) { 59 | if (i != 0) b.append('|'); 60 | b.append(a[i]); 61 | } 62 | return b.toString(); 63 | } 64 | 65 | public static byte[] toArray(String str) { 66 | String[] a = str.split("\\|"); 67 | if (a.length != CipherBox.INSTANCE.getAesKeyLength()) { 68 | return null; 69 | } 70 | byte[] bytes = new byte[a.length]; 71 | for (int i = 0; i < a.length; i++) { 72 | bytes[i] = Byte.parseByte(a[i]); 73 | } 74 | return bytes; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/security/CipherBox.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.security; 21 | 22 | 23 | 24 | import com.mpush.client.ClientConfig; 25 | import com.mpush.util.crypto.RSAUtils; 26 | 27 | import java.security.SecureRandom; 28 | import java.security.interfaces.RSAPublicKey; 29 | 30 | /** 31 | * Created by ohun on 2015/12/24. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class CipherBox { 36 | public int aesKeyLength = ClientConfig.I.getAesKeyLength(); 37 | public static final CipherBox INSTANCE = new CipherBox(); 38 | private SecureRandom random = new SecureRandom(); 39 | private RSAPublicKey publicKey; 40 | 41 | 42 | public RSAPublicKey getPublicKey() { 43 | if (publicKey == null) { 44 | String key = ClientConfig.I.getPublicKey(); 45 | try { 46 | publicKey = (RSAPublicKey) RSAUtils.decodePublicKey(key); 47 | } catch (Exception e) { 48 | throw new RuntimeException("load public key ex, key=" + key, e); 49 | } 50 | } 51 | return publicKey; 52 | } 53 | 54 | public byte[] randomAESKey() { 55 | byte[] bytes = new byte[aesKeyLength]; 56 | random.nextBytes(bytes); 57 | return bytes; 58 | } 59 | 60 | public byte[] randomAESIV() { 61 | byte[] bytes = new byte[aesKeyLength]; 62 | random.nextBytes(bytes); 63 | return bytes; 64 | } 65 | 66 | public byte[] mixKey(byte[] clientKey, byte[] serverKey) { 67 | byte[] sessionKey = new byte[aesKeyLength]; 68 | for (int i = 0; i < aesKeyLength; i++) { 69 | byte a = clientKey[i]; 70 | byte b = serverKey[i]; 71 | int sum = Math.abs(a + b); 72 | int c = (sum % 2 == 0) ? a ^ b : b ^ a; 73 | sessionKey[i] = (byte) c; 74 | } 75 | return sessionKey; 76 | } 77 | 78 | public int getAesKeyLength() { 79 | return aesKeyLength; 80 | } 81 | 82 | public RsaCipher getRsaCipher() { 83 | return new RsaCipher(getPublicKey()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/security/RsaCipher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.security; 21 | 22 | 23 | 24 | import com.mpush.api.connection.Cipher; 25 | import com.mpush.util.crypto.RSAUtils; 26 | 27 | import java.security.interfaces.RSAPublicKey; 28 | 29 | /** 30 | * Created by ohun on 2015/12/28. 31 | * 32 | * @author ohun@live.cn (夜色) 33 | */ 34 | public final class RsaCipher implements Cipher { 35 | 36 | private final RSAPublicKey publicKey; 37 | 38 | public RsaCipher(RSAPublicKey publicKey) { 39 | this.publicKey = publicKey; 40 | } 41 | 42 | @Override 43 | public byte[] decrypt(byte[] data) { 44 | throw new UnsupportedOperationException(); 45 | } 46 | 47 | @Override 48 | public byte[] encrypt(byte[] data) { 49 | return RSAUtils.encryptByPublicKey(data, publicKey); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "RsaCipher [publicKey=" + new String(publicKey.getEncoded()) + "]"; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/session/FileSessionStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.session; 21 | 22 | 23 | import com.mpush.api.connection.SessionStorage; 24 | import com.mpush.util.IOUtils; 25 | import com.mpush.api.Constants; 26 | import com.mpush.client.ClientConfig; 27 | 28 | import java.io.*; 29 | 30 | /** 31 | * Created by ohun on 2016/1/25. 32 | * 33 | * @author ohun@live.cn (夜色) 34 | */ 35 | public final class FileSessionStorage implements SessionStorage { 36 | private final String rootDir; 37 | private final String fileName = "token.dat"; 38 | 39 | public FileSessionStorage(String rootDir) { 40 | this.rootDir = rootDir; 41 | } 42 | 43 | @Override 44 | public void saveSession(String sessionContext) { 45 | File file = new File(rootDir, fileName); 46 | FileOutputStream out = null; 47 | try { 48 | if (!file.exists()) file.getParentFile().mkdirs(); 49 | else if (file.canWrite()) file.delete(); 50 | out = new FileOutputStream(file); 51 | out.write(sessionContext.getBytes(Constants.UTF_8)); 52 | } catch (Exception e) { 53 | ClientConfig.I.getLogger().e(e, "save session context ex, session=%s, rootDir=%s" 54 | , sessionContext, rootDir); 55 | } finally { 56 | IOUtils.close(out); 57 | } 58 | } 59 | 60 | @Override 61 | public String getSession() { 62 | File file = new File(rootDir, fileName); 63 | if (!file.exists()) return null; 64 | InputStream in = null; 65 | try { 66 | in = new FileInputStream(file); 67 | byte[] bytes = new byte[in.available()]; 68 | if (bytes.length > 0) { 69 | in.read(bytes); 70 | return new String(bytes, Constants.UTF_8); 71 | } 72 | in.close(); 73 | } catch (Exception e) { 74 | ClientConfig.I.getLogger().e(e, "get session context ex,rootDir=%s", rootDir); 75 | } finally { 76 | IOUtils.close(in); 77 | } 78 | return null; 79 | } 80 | 81 | @Override 82 | public void clearSession() { 83 | File file = new File(rootDir, fileName); 84 | if (file.exists() && file.canWrite()) { 85 | file.delete(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/session/PersistentSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.session; 21 | 22 | 23 | import com.mpush.api.connection.Cipher; 24 | import com.mpush.security.AesCipher; 25 | import com.mpush.util.Strings; 26 | 27 | /** 28 | * Created by ohun on 2016/1/25. 29 | * 30 | * @author ohun@live.cn (夜色) 31 | */ 32 | public final class PersistentSession { 33 | public String sessionId; 34 | public long expireTime; 35 | public Cipher cipher; 36 | 37 | public boolean isExpired() { 38 | return expireTime < System.currentTimeMillis(); 39 | } 40 | 41 | public static String encode(PersistentSession session) { 42 | return session.sessionId 43 | + "," + session.expireTime 44 | + "," + session.cipher.toString(); 45 | } 46 | 47 | public static PersistentSession decode(String value) { 48 | String[] array = value.split(","); 49 | if (array.length != 4) return null; 50 | PersistentSession session = new PersistentSession(); 51 | session.sessionId = array[0]; 52 | session.expireTime = Strings.toLong(array[1], 0); 53 | byte[] key = AesCipher.toArray(array[2]); 54 | byte[] iv = AesCipher.toArray(array[3]); 55 | if (key == null || iv == null) return null; 56 | session.cipher = new AesCipher(key, iv); 57 | return session; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return "PersistentSession{" + 63 | "sessionId='" + sessionId + '\'' + 64 | ", expireTime=" + expireTime + 65 | ", cipher=" + cipher + 66 | '}'; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/ByteBuf.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util; 21 | 22 | 23 | import java.nio.*; 24 | 25 | /** 26 | * Created by ohun on 2016/1/21. 27 | * 28 | * @author ohun@live.cn (夜色) 29 | */ 30 | public final class ByteBuf { 31 | private ByteBuffer tmpNioBuf; 32 | 33 | public static ByteBuf allocate(int capacity) { 34 | ByteBuf buffer = new ByteBuf(); 35 | buffer.tmpNioBuf = ByteBuffer.allocate(capacity); 36 | return buffer; 37 | } 38 | 39 | public static ByteBuf allocateDirect(int capacity) { 40 | ByteBuf buffer = new ByteBuf(); 41 | buffer.tmpNioBuf = ByteBuffer.allocateDirect(capacity); 42 | return buffer; 43 | } 44 | 45 | public static ByteBuf wrap(byte[] array) { 46 | ByteBuf buffer = new ByteBuf(); 47 | buffer.tmpNioBuf = ByteBuffer.wrap(array); 48 | return buffer; 49 | } 50 | 51 | public byte[] getArray() { 52 | tmpNioBuf.flip(); 53 | byte[] array = new byte[tmpNioBuf.remaining()]; 54 | tmpNioBuf.get(array); 55 | tmpNioBuf.compact(); 56 | return array; 57 | } 58 | 59 | public ByteBuf get(byte[] array) { 60 | tmpNioBuf.get(array); 61 | return this; 62 | } 63 | 64 | public byte get() { 65 | return tmpNioBuf.get(); 66 | } 67 | 68 | public ByteBuf put(byte b) { 69 | checkCapacity(1); 70 | tmpNioBuf.put(b); 71 | return this; 72 | } 73 | 74 | public short getShort() { 75 | return tmpNioBuf.getShort(); 76 | } 77 | 78 | public ByteBuf putShort(int value) { 79 | checkCapacity(2); 80 | tmpNioBuf.putShort((short) value); 81 | return this; 82 | } 83 | 84 | public int getInt() { 85 | return tmpNioBuf.getInt(); 86 | } 87 | 88 | public ByteBuf putInt(int value) { 89 | checkCapacity(4); 90 | tmpNioBuf.putInt(value); 91 | return this; 92 | } 93 | 94 | public long getLong() { 95 | return tmpNioBuf.getLong(); 96 | } 97 | 98 | public ByteBuf putLong(long value) { 99 | checkCapacity(8); 100 | tmpNioBuf.putLong(value); 101 | return this; 102 | } 103 | 104 | public ByteBuf put(byte[] value) { 105 | checkCapacity(value.length); 106 | tmpNioBuf.put(value); 107 | return this; 108 | } 109 | 110 | public ByteBuf checkCapacity(int minWritableBytes) { 111 | int remaining = tmpNioBuf.remaining(); 112 | if (remaining < minWritableBytes) { 113 | int newCapacity = newCapacity(tmpNioBuf.capacity() + minWritableBytes); 114 | ByteBuffer newBuffer = tmpNioBuf.isDirect() ? ByteBuffer.allocateDirect(newCapacity) : ByteBuffer.allocate(newCapacity); 115 | tmpNioBuf.flip(); 116 | newBuffer.put(tmpNioBuf); 117 | tmpNioBuf = newBuffer; 118 | } 119 | return this; 120 | } 121 | 122 | private int newCapacity(int minNewCapacity) { 123 | int newCapacity = 64; 124 | while (newCapacity < minNewCapacity) { 125 | newCapacity <<= 1; 126 | } 127 | return newCapacity; 128 | } 129 | 130 | public ByteBuffer nioBuffer() { 131 | return tmpNioBuf; 132 | } 133 | 134 | public ByteBuf clear() { 135 | tmpNioBuf.clear(); 136 | return this; 137 | } 138 | 139 | public ByteBuf flip() { 140 | tmpNioBuf.flip(); 141 | return this; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/DefaultLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util; 21 | 22 | 23 | import com.mpush.api.Logger; 24 | 25 | import java.text.DateFormat; 26 | import java.text.SimpleDateFormat; 27 | import java.util.Date; 28 | 29 | /** 30 | * Created by ohun on 2016/1/25. 31 | * 32 | * @author ohun@live.cn (夜色) 33 | */ 34 | public final class DefaultLogger implements Logger { 35 | private static final String TAG = "[mpush] "; 36 | private final DateFormat format = new SimpleDateFormat("HH:mm:ss.SSS"); 37 | 38 | private boolean enable = false; 39 | 40 | @Override 41 | public void enable(boolean enabled) { 42 | this.enable = enabled; 43 | } 44 | 45 | @Override 46 | public void d(String s, Object... args) { 47 | if (enable) { 48 | System.out.printf(format.format(new Date()) + " [D] " + TAG + s + '\n', args); 49 | } 50 | } 51 | 52 | @Override 53 | public void i(String s, Object... args) { 54 | if (enable) { 55 | System.out.printf(format.format(new Date()) + " [I] " + TAG + s + '\n', args); 56 | } 57 | } 58 | 59 | @Override 60 | public void w(String s, Object... args) { 61 | if (enable) { 62 | System.err.printf(format.format(new Date()) + " [W] " + TAG + s + '\n', args); 63 | } 64 | } 65 | 66 | @Override 67 | public void e(Throwable e, String s, Object... args) { 68 | if (enable) { 69 | System.err.printf(format.format(new Date()) + " [E] " + TAG + s + '\n', args); 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/IOUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util; 21 | 22 | 23 | 24 | import com.mpush.api.Constants; 25 | 26 | import java.io.ByteArrayInputStream; 27 | import java.io.ByteArrayOutputStream; 28 | import java.io.Closeable; 29 | import java.io.IOException; 30 | import java.util.zip.DeflaterOutputStream; 31 | import java.util.zip.InflaterInputStream; 32 | 33 | /** 34 | * Created by ohun on 2015/12/25. 35 | * 36 | * @author ohun@live.cn (夜色) 37 | */ 38 | public final class IOUtils { 39 | 40 | public static void close(Closeable closeable) { 41 | if (closeable != null) { 42 | try { 43 | closeable.close(); 44 | } catch (Exception e) { 45 | } 46 | } 47 | } 48 | 49 | public static byte[] compress(byte[] data) { 50 | ByteArrayOutputStream byteStream = new ByteArrayOutputStream(data.length / 4); 51 | DeflaterOutputStream zipOut = new DeflaterOutputStream(byteStream); 52 | try { 53 | zipOut.write(data); 54 | zipOut.finish(); 55 | zipOut.close(); 56 | } catch (IOException e) { 57 | return Constants.EMPTY_BYTES; 58 | } finally { 59 | close(zipOut); 60 | } 61 | return byteStream.toByteArray(); 62 | } 63 | 64 | public static byte[] uncompress(byte[] data) { 65 | InflaterInputStream in = new InflaterInputStream(new ByteArrayInputStream(data)); 66 | ByteArrayOutputStream out = new ByteArrayOutputStream(data.length * 4); 67 | byte[] buffer = new byte[1024]; 68 | int length; 69 | try { 70 | while ((length = in.read(buffer)) != -1) { 71 | out.write(buffer, 0, length); 72 | } 73 | } catch (IOException e) { 74 | return Constants.EMPTY_BYTES; 75 | } finally { 76 | close(in); 77 | } 78 | return out.toByteArray(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/MPUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util; 21 | 22 | 23 | import java.net.InetAddress; 24 | import java.net.UnknownHostException; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | import java.util.regex.Pattern; 28 | 29 | /** 30 | * Created by ohun on 2016/1/25. 31 | * 32 | * @author ohun@live.cn (夜色) 33 | */ 34 | public final class MPUtils { 35 | 36 | /** 37 | * Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation 38 | * of Android's private InetAddress#isNumeric API. 39 | *

40 | *

This matches IPv6 addresses as a hex string containing at least one colon, and possibly 41 | * including dots after the first colon. It matches IPv4 addresses as strings containing only 42 | * decimal digits and dots. This pattern matches strings like "a:.23" and "54" that are neither IP 43 | * addresses nor hostnames; they will be verified as IP addresses (which is a more strict 44 | * verification). 45 | */ 46 | private static final Pattern VERIFY_AS_IP_ADDRESS = Pattern.compile( 47 | "([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)"); 48 | 49 | public static String parseHost2Ip(String host) { 50 | InetAddress ia = null; 51 | try { 52 | ia = InetAddress.getByName(host); 53 | } catch (UnknownHostException e) { 54 | } 55 | if (ia != null) { 56 | return ia.getHostAddress(); 57 | } 58 | return host; 59 | } 60 | 61 | public static String headerToString(Map headers) { 62 | if (headers != null && headers.size() > 0) { 63 | StringBuilder sb = new StringBuilder(headers.size() * 64); 64 | for (Map.Entry entry : headers.entrySet()) { 65 | sb.append(entry.getKey()) 66 | .append(':') 67 | .append(entry.getValue()).append('\n'); 68 | } 69 | return sb.toString(); 70 | } 71 | return null; 72 | } 73 | 74 | 75 | public static Map headerFromString(String headersString) { 76 | if (headersString == null) return null; 77 | Map headers = new HashMap<>(); 78 | int L = headersString.length(); 79 | String name, value = null; 80 | for (int i = 0, start = 0; i < L; i++) { 81 | char c = headersString.charAt(i); 82 | if (c != '\n') continue; 83 | if (start >= L - 1) break; 84 | String header = headersString.substring(start, i); 85 | start = i + 1; 86 | int index = header.indexOf(':'); 87 | if (index <= 0) continue; 88 | name = header.substring(0, index); 89 | if (index < header.length() - 1) { 90 | value = header.substring(index + 1); 91 | } 92 | headers.put(name, value); 93 | } 94 | return headers; 95 | } 96 | 97 | /** 98 | * Returns true if {@code host} is not a host name and might be an IP address. 99 | */ 100 | public static boolean verifyAsIpAddress(String host) { 101 | return VERIFY_AS_IP_ADDRESS.matcher(host).matches(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/Strings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util; 21 | 22 | 23 | /** 24 | * Created by ohun on 2015/12/23. 25 | * 26 | * @author ohun@live.cn (夜色) 27 | */ 28 | public final class Strings { 29 | public static final String EMPTY = ""; 30 | 31 | public static boolean isBlank(CharSequence text) { 32 | if (text == null || text.length() == 0) return true; 33 | for (int i = 0, L = text.length(); i < L; i++) { 34 | if (!Character.isWhitespace(text.charAt(i))) return false; 35 | } 36 | return true; 37 | } 38 | 39 | public static long toLong(String text, long defaultVal) { 40 | try { 41 | return Long.parseLong(text); 42 | } catch (NumberFormatException e) { 43 | } 44 | return defaultVal; 45 | } 46 | 47 | public static int toInt(String text, int defaultVal) { 48 | try { 49 | return Integer.parseInt(text); 50 | } catch (NumberFormatException e) { 51 | } 52 | return defaultVal; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/crypto/AESUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util.crypto; 21 | 22 | 23 | 24 | import com.mpush.client.ClientConfig; 25 | import com.mpush.api.Constants; 26 | 27 | import javax.crypto.Cipher; 28 | import javax.crypto.spec.IvParameterSpec; 29 | import javax.crypto.spec.SecretKeySpec; 30 | 31 | /** 32 | * Created by ohun on 2015/12/25. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public final class AESUtils { 37 | public static final String KEY_ALGORITHM = "AES"; 38 | public static final String KEY_ALGORITHM_PADDING = "AES/CBC/PKCS5Padding"; 39 | 40 | 41 | public static byte[] encrypt(byte[] data, byte[] encryptKey, byte[] iv) { 42 | IvParameterSpec zeroIv = new IvParameterSpec(iv); 43 | SecretKeySpec key = new SecretKeySpec(encryptKey, KEY_ALGORITHM); 44 | try { 45 | Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_PADDING); 46 | cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv); 47 | return cipher.doFinal(data); 48 | } catch (Exception e) { 49 | ClientConfig.I.getLogger().e(e, "encrypt ex, decryptKey=%s", encryptKey); 50 | } 51 | return Constants.EMPTY_BYTES; 52 | } 53 | 54 | public static byte[] decrypt(byte[] data, byte[] decryptKey, byte[] iv) { 55 | IvParameterSpec zeroIv = new IvParameterSpec(iv); 56 | SecretKeySpec key = new SecretKeySpec(decryptKey, KEY_ALGORITHM); 57 | try { 58 | Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_PADDING); 59 | cipher.init(Cipher.DECRYPT_MODE, key, zeroIv); 60 | return cipher.doFinal(data); 61 | } catch (Exception e) { 62 | ClientConfig.I.getLogger().e(e, "decrypt ex, decryptKey=%s", decryptKey); 63 | } 64 | return Constants.EMPTY_BYTES; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/crypto/Base64Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util.crypto; 21 | 22 | 23 | 24 | import com.mpush.api.Constants; 25 | 26 | import java.io.*; 27 | 28 | /** 29 | *

30 | * BASE64编码解码工具包 31 | *

32 | *

33 | * 依赖javabase64-1.3.1.jar 34 | *

35 | */ 36 | public class Base64Utils { 37 | 38 | /** 39 | * 文件读取缓冲区大小 40 | */ 41 | private static final int CACHE_SIZE = 1024; 42 | 43 | /** 44 | *

45 | * BASE64字符串解码为二进制数据 46 | *

47 | * 48 | * @param base64 xxx 49 | * @return return 50 | * @throws Exception xxx 51 | */ 52 | public static byte[] decode(String base64) throws Exception { 53 | return Base64.getDecoder().decode(base64); 54 | } 55 | 56 | /** 57 | *

58 | * 二进制数据编码为BASE64字符串 59 | *

60 | * 61 | * @param bytes xxx 62 | * @return return 63 | * @throws Exception xxx 64 | */ 65 | public static String encode(byte[] bytes) throws Exception { 66 | return new String(Base64.getEncoder().encode(bytes), Constants.UTF_8); 67 | } 68 | 69 | /** 70 | *

71 | * 将文件编码为BASE64字符串 72 | *

73 | *

74 | * 大文件慎用,可能会导致内存溢出 75 | *

76 | * 77 | * @param filePath 文件绝对路径 78 | * @return return xxxx 79 | * @throws Exception xxxx 80 | */ 81 | public static String encodeFile(String filePath) throws Exception { 82 | byte[] bytes = fileToByte(filePath); 83 | return encode(bytes); 84 | } 85 | 86 | /** 87 | *

88 | * BASE64字符串转回文件 89 | *

90 | * 91 | * @param filePath 文件绝对路径 92 | * @param base64 编码字符串 93 | * @throws Exception xxxx 94 | */ 95 | public static void decodeToFile(String filePath, String base64) throws Exception { 96 | byte[] bytes = decode(base64); 97 | byteArrayToFile(bytes, filePath); 98 | } 99 | 100 | /** 101 | *

102 | * 文件转换为二进制数组 103 | *

104 | * 105 | * @param filePath 文件路径 106 | * @return return xxxx 107 | * @throws Exception xxxx 108 | */ 109 | public static byte[] fileToByte(String filePath) throws Exception { 110 | byte[] data = new byte[0]; 111 | File file = new File(filePath); 112 | if (file.exists()) { 113 | FileInputStream in = new FileInputStream(file); 114 | ByteArrayOutputStream out = new ByteArrayOutputStream(2048); 115 | byte[] cache = new byte[CACHE_SIZE]; 116 | int nRead = 0; 117 | while ((nRead = in.read(cache)) != -1) { 118 | out.write(cache, 0, nRead); 119 | out.flush(); 120 | } 121 | out.close(); 122 | in.close(); 123 | data = out.toByteArray(); 124 | } 125 | return data; 126 | } 127 | 128 | /** 129 | *

130 | * 二进制数据写文件 131 | *

132 | * 133 | * @param bytes 二进制数据 134 | * @param filePath 文件生成目录 135 | * @throws Exception Exception 136 | */ 137 | public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { 138 | InputStream in = new ByteArrayInputStream(bytes); 139 | File destFile = new File(filePath); 140 | if (!destFile.getParentFile().exists()) { 141 | destFile.getParentFile().mkdirs(); 142 | } 143 | destFile.createNewFile(); 144 | OutputStream out = new FileOutputStream(destFile); 145 | byte[] cache = new byte[CACHE_SIZE]; 146 | int nRead = 0; 147 | while ((nRead = in.read(cache)) != -1) { 148 | out.write(cache, 0, nRead); 149 | out.flush(); 150 | } 151 | out.close(); 152 | in.close(); 153 | } 154 | } -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/crypto/MD5Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util.crypto; 21 | 22 | 23 | 24 | import com.mpush.util.IOUtils; 25 | import com.mpush.api.Constants; 26 | import com.mpush.util.Strings; 27 | 28 | import javax.crypto.Mac; 29 | import javax.crypto.spec.SecretKeySpec; 30 | import java.io.File; 31 | import java.io.FileInputStream; 32 | import java.io.InputStream; 33 | import java.security.MessageDigest; 34 | 35 | /** 36 | * Created by ohun on 2015/12/25. 37 | * 38 | * @author ohun@live.cn (夜色) 39 | */ 40 | public final class MD5Utils { 41 | public static String encrypt(File file) { 42 | InputStream in = null; 43 | try { 44 | MessageDigest digest = MessageDigest.getInstance("MD5"); 45 | in = new FileInputStream(file); 46 | byte[] buffer = new byte[10240];//10k 47 | int readLen; 48 | while ((readLen = in.read(buffer)) != -1) { 49 | digest.update(buffer, 0, readLen); 50 | } 51 | return toHex(digest.digest()); 52 | } catch (Exception e) { 53 | return Strings.EMPTY; 54 | } finally { 55 | IOUtils.close(in); 56 | } 57 | } 58 | 59 | public static String encrypt(String text) { 60 | try { 61 | MessageDigest digest = MessageDigest.getInstance("MD5"); 62 | digest.update(text.getBytes(Constants.UTF_8)); 63 | return toHex(digest.digest()); 64 | } catch (Exception e) { 65 | return Strings.EMPTY; 66 | } 67 | } 68 | 69 | public static String encrypt(byte[] bytes) { 70 | try { 71 | MessageDigest digest = MessageDigest.getInstance("MD5"); 72 | digest.update(bytes); 73 | return toHex(digest.digest()); 74 | } catch (Exception e) { 75 | return Strings.EMPTY; 76 | } 77 | } 78 | 79 | private static String toHex(byte[] bytes) { 80 | StringBuffer buffer = new StringBuffer(bytes.length * 2); 81 | 82 | for (int i = 0; i < bytes.length; ++i) { 83 | buffer.append(Character.forDigit((bytes[i] & 240) >> 4, 16)); 84 | buffer.append(Character.forDigit(bytes[i] & 15, 16)); 85 | } 86 | 87 | return buffer.toString(); 88 | } 89 | 90 | /** 91 | * HmacSHA1 加密 92 | * 93 | * @param data xxx 94 | * @param encryptKey xxx 95 | * @return xxxx 96 | */ 97 | public static String hmacSha1(String data, String encryptKey) { 98 | final String HMAC_SHA1 = "HmacSHA1"; 99 | SecretKeySpec signingKey = new SecretKeySpec(encryptKey.getBytes(Constants.UTF_8), HMAC_SHA1); 100 | try { 101 | Mac mac = Mac.getInstance(HMAC_SHA1); 102 | mac.init(signingKey); 103 | mac.update(data.getBytes(Constants.UTF_8)); 104 | return toHex(mac.doFinal()); 105 | } catch (Exception e) { 106 | return Strings.EMPTY; 107 | } 108 | } 109 | 110 | /** 111 | * HmacSHA1 加密 112 | * 113 | * @param data xxx 114 | * @return xxx 115 | */ 116 | public static String sha1(String data) { 117 | try { 118 | MessageDigest digest = MessageDigest.getInstance("SHA-1"); 119 | return toHex(digest.digest(data.getBytes(Constants.UTF_8))); 120 | } catch (Exception e) { 121 | return Strings.EMPTY; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/thread/EventLock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util.thread; 21 | 22 | 23 | import java.util.concurrent.TimeUnit; 24 | import java.util.concurrent.locks.Condition; 25 | import java.util.concurrent.locks.ReentrantLock; 26 | 27 | /** 28 | * Created by ohun on 2016/1/17. 29 | * 30 | * @author ohun@live.cn (夜色) 31 | */ 32 | public final class EventLock { 33 | private final ReentrantLock lock; 34 | private final Condition cond; 35 | 36 | public EventLock() { 37 | lock = new ReentrantLock(); 38 | cond = lock.newCondition(); 39 | } 40 | 41 | public void lock() { 42 | lock.lock(); 43 | } 44 | 45 | public void unlock() { 46 | lock.unlock(); 47 | } 48 | 49 | public void signal() { 50 | cond.signal(); 51 | } 52 | 53 | public void signalAll() { 54 | cond.signalAll(); 55 | } 56 | 57 | public void broadcast() { 58 | lock.lock(); 59 | cond.signalAll(); 60 | lock.unlock(); 61 | } 62 | 63 | public boolean await(long timeout) { 64 | lock.lock(); 65 | try { 66 | cond.awaitNanos(TimeUnit.MILLISECONDS.toNanos(timeout)); 67 | } catch (InterruptedException e) { 68 | return true; 69 | } finally { 70 | lock.unlock(); 71 | } 72 | return false; 73 | } 74 | 75 | public boolean await() { 76 | lock.lock(); 77 | try { 78 | cond.await(); 79 | } catch (InterruptedException e) { 80 | return true; 81 | } finally { 82 | lock.unlock(); 83 | } 84 | return false; 85 | } 86 | 87 | public ReentrantLock getLock() { 88 | return lock; 89 | } 90 | 91 | public Condition getCond() { 92 | return cond; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/thread/ExecutorManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util.thread; 21 | 22 | 23 | import com.mpush.client.ClientConfig; 24 | 25 | import java.util.concurrent.LinkedBlockingQueue; 26 | import java.util.concurrent.RejectedExecutionHandler; 27 | import java.util.concurrent.ScheduledExecutorService; 28 | import java.util.concurrent.ScheduledThreadPoolExecutor; 29 | import java.util.concurrent.ThreadPoolExecutor; 30 | import java.util.concurrent.TimeUnit; 31 | 32 | /** 33 | * Created by ohun on 2016/1/23. 34 | * 35 | * @author ohun@live.cn (夜色) 36 | */ 37 | public final class ExecutorManager { 38 | public static final String THREAD_NAME_PREFIX = "mp-client-"; 39 | public static final String WRITE_THREAD_NAME = THREAD_NAME_PREFIX + "write-t"; 40 | public static final String READ_THREAD_NAME = THREAD_NAME_PREFIX + "read-t"; 41 | public static final String DISPATCH_THREAD_NAME = THREAD_NAME_PREFIX + "dispatch-t"; 42 | public static final String START_THREAD_NAME = THREAD_NAME_PREFIX + "start-t"; 43 | public static final String TIMER_THREAD_NAME = THREAD_NAME_PREFIX + "timer-t"; 44 | public static final ExecutorManager INSTANCE = new ExecutorManager(); 45 | private ThreadPoolExecutor writeThread; 46 | private ThreadPoolExecutor dispatchThread; 47 | private ScheduledExecutorService timerThread; 48 | 49 | public ThreadPoolExecutor getWriteThread() { 50 | if (writeThread == null || writeThread.isShutdown()) { 51 | writeThread = new ThreadPoolExecutor(1, 1, 52 | 0L, TimeUnit.MILLISECONDS, 53 | new LinkedBlockingQueue(100), 54 | new NamedThreadFactory(WRITE_THREAD_NAME), 55 | new RejectedHandler()); 56 | } 57 | return writeThread; 58 | } 59 | 60 | public ThreadPoolExecutor getDispatchThread() { 61 | if (dispatchThread == null || dispatchThread.isShutdown()) { 62 | dispatchThread = new ThreadPoolExecutor(2, 4, 63 | 1L, TimeUnit.SECONDS, 64 | new LinkedBlockingQueue(100), 65 | new NamedThreadFactory(DISPATCH_THREAD_NAME), 66 | new RejectedHandler()); 67 | } 68 | return dispatchThread; 69 | } 70 | 71 | public ScheduledExecutorService getTimerThread() { 72 | if (timerThread == null || timerThread.isShutdown()) { 73 | timerThread = new ScheduledThreadPoolExecutor(1, 74 | new NamedThreadFactory(TIMER_THREAD_NAME), 75 | new RejectedHandler()); 76 | } 77 | return timerThread; 78 | } 79 | 80 | public synchronized void shutdown() { 81 | if (writeThread != null) { 82 | writeThread.shutdownNow(); 83 | writeThread = null; 84 | } 85 | if (dispatchThread != null) { 86 | dispatchThread.shutdownNow(); 87 | dispatchThread = null; 88 | } 89 | if (timerThread != null) { 90 | timerThread.shutdownNow(); 91 | timerThread = null; 92 | } 93 | } 94 | 95 | public static boolean isMPThread() { 96 | return Thread.currentThread().getName().startsWith(THREAD_NAME_PREFIX); 97 | } 98 | 99 | private static class RejectedHandler implements RejectedExecutionHandler { 100 | 101 | @Override 102 | public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 103 | ClientConfig.I.getLogger().w("a task was rejected r=%s", r); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/mpush/util/thread/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.util.thread; 21 | 22 | 23 | import java.util.concurrent.ThreadFactory; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | /** 27 | * Created by xiaoxu.yxx on 2015/7/19. 28 | */ 29 | public final class NamedThreadFactory implements ThreadFactory { 30 | protected final AtomicInteger threadNumber = new AtomicInteger(1); 31 | protected final String namePrefix; 32 | protected final ThreadGroup group; 33 | 34 | public NamedThreadFactory(final String namePrefix) { 35 | this.namePrefix = namePrefix; 36 | this.group = Thread.currentThread().getThreadGroup(); 37 | } 38 | 39 | public Thread newThread(String name, Runnable r) { 40 | return new Thread(r, name); 41 | } 42 | 43 | @Override 44 | public Thread newThread(Runnable r) { 45 | Thread t = newThread(namePrefix + threadNumber.getAndIncrement(), r); 46 | if (t.isDaemon()) 47 | t.setDaemon(false); 48 | return t; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/mpush/client/MPushClientTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2015-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Contributors: 17 | * ohun@live.cn (夜色) 18 | */ 19 | 20 | package com.mpush.client; 21 | 22 | 23 | import com.mpush.api.Client; 24 | import com.mpush.api.ClientListener; 25 | import com.mpush.util.DefaultLogger; 26 | 27 | import java.util.concurrent.Executors; 28 | import java.util.concurrent.ScheduledExecutorService; 29 | import java.util.concurrent.TimeUnit; 30 | 31 | /** 32 | * Created by ohun on 2016/1/25. 33 | * 34 | * @author ohun@live.cn (夜色) 35 | */ 36 | public class MPushClientTest { 37 | private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCghPCWCobG8nTD24juwSVataW7iViRxcTkey/B792VZEhuHjQvA3cAJgx2Lv8GnX8NIoShZtoCg3Cx6ecs+VEPD2fBcg2L4JK7xldGpOJ3ONEAyVsLOttXZtNXvyDZRijiErQALMTorcgi79M5uVX9/jMv2Ggb2XAeZhlLD28fHwIDAQAB"; 38 | private static final String allocServer = "http://103.60.220.145:9999/"; 39 | 40 | public static void main(String[] args) throws Exception { 41 | int count = 1; 42 | String serverHost = "127.0.0.1"; 43 | int sleep = 1000; 44 | 45 | if (args != null && args.length > 0) { 46 | count = Integer.parseInt(args[0]); 47 | if (args.length > 1) { 48 | serverHost = args[1]; 49 | } 50 | if (args.length > 2) { 51 | sleep = Integer.parseInt(args[1]); 52 | } 53 | } 54 | 55 | ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); 56 | ClientListener listener = new L(scheduledExecutor); 57 | Client client = null; 58 | String cacheDir = MPushClientTest.class.getResource("/").getFile(); 59 | for (int i = 0; i < count; i++) { 60 | client = ClientConfig 61 | .build() 62 | .setPublicKey(publicKey) 63 | //.setAllotServer(allocServer) 64 | .setServerHost(serverHost) 65 | .setServerPort(3000) 66 | .setDeviceId("deviceId-test" + i) 67 | .setOsName("android") 68 | .setOsVersion("6.0") 69 | .setClientVersion("2.0") 70 | .setUserId("user-" + i) 71 | .setTags("tag-" + i) 72 | .setSessionStorageDir(cacheDir + i) 73 | .setLogger(new DefaultLogger()) 74 | .setLogEnabled(true) 75 | .setEnableHttpProxy(true) 76 | .setClientListener(listener) 77 | .create(); 78 | client.start(); 79 | Thread.sleep(sleep); 80 | } 81 | } 82 | 83 | public static class L implements ClientListener { 84 | private final ScheduledExecutorService scheduledExecutor; 85 | boolean flag = true; 86 | 87 | public L(ScheduledExecutorService scheduledExecutor) { 88 | this.scheduledExecutor = scheduledExecutor; 89 | } 90 | 91 | @Override 92 | public void onConnected(Client client) { 93 | flag = true; 94 | } 95 | 96 | @Override 97 | public void onDisConnected(Client client) { 98 | flag = false; 99 | } 100 | 101 | @Override 102 | public void onHandshakeOk(final Client client, final int heartbeat) { 103 | scheduledExecutor.scheduleAtFixedRate(new Runnable() { 104 | @Override 105 | public void run() { 106 | client.healthCheck(); 107 | } 108 | }, 10, 10, TimeUnit.SECONDS); 109 | 110 | //client.push(PushContext.build("test")); 111 | 112 | } 113 | 114 | @Override 115 | public void onReceivePush(Client client, byte[] content, int messageId) { 116 | if (messageId > 0) client.ack(messageId); 117 | } 118 | 119 | @Override 120 | public void onKickUser(String deviceId, String userId) { 121 | 122 | } 123 | 124 | @Override 125 | public void onBind(boolean success, String userId) { 126 | 127 | } 128 | 129 | @Override 130 | public void onUnbind(boolean success, String userId) { 131 | 132 | } 133 | } 134 | } --------------------------------------------------------------------------------