├── .github └── workflows │ └── maven.yml ├── .gitignore ├── LICENSE ├── README.md ├── go-push-adapter-sdk ├── pom.xml └── src │ ├── main │ ├── java │ │ └── .gitignore │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── go-push-common ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── common │ │ │ ├── Constants.java │ │ │ ├── constants │ │ │ ├── DeviceMessageEnum.java │ │ │ ├── HandshakeEnum.java │ │ │ ├── IdleEnum.java │ │ │ ├── NodeMessageEnum.java │ │ │ ├── RedisKeyEnum.java │ │ │ ├── RestfulRespEnum.java │ │ │ └── ZkGroupEnum.java │ │ │ └── utils │ │ │ ├── ip │ │ │ └── IpUtils.java │ │ │ └── zk │ │ │ ├── ZkUtils.java │ │ │ └── listener │ │ │ └── ZkStateListener.java │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── go-push-data-center ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── datacenter │ │ │ ├── DataCenterApplication.java │ │ │ ├── config │ │ │ ├── GoPushDataCenterConfig.java │ │ │ └── ZookeeperConfig.java │ │ │ ├── dymic │ │ │ ├── discovery │ │ │ │ └── NodeServerDiscoveryService.java │ │ │ └── register │ │ │ │ └── DataCenterRegisterService.java │ │ │ ├── infos │ │ │ └── watchdog │ │ │ │ ├── DataCenterInfoWatchdog.java │ │ │ │ └── listener │ │ │ │ ├── DataCenterInfoDataListener.java │ │ │ │ └── event │ │ │ │ └── DataCenterInfoEvent.java │ │ │ ├── nodes │ │ │ ├── handlers │ │ │ │ ├── DeviceDisconnectHandler.java │ │ │ │ ├── DeviceDockedHandler.java │ │ │ │ ├── MessageToMultiDeviceHandler.java │ │ │ │ ├── MultiMessageToDeviceHandler.java │ │ │ │ ├── NodeInfoHandler.java │ │ │ │ ├── PingHandler.java │ │ │ │ └── PongHandler.java │ │ │ ├── inbound │ │ │ │ └── NodeChannelInBoundHandler.java │ │ │ └── manager │ │ │ │ ├── INode.java │ │ │ │ ├── Node.java │ │ │ │ └── NodeManager.java │ │ │ └── restfuls │ │ │ ├── aop │ │ │ └── RestfulLoaderAspect.java │ │ │ ├── controller │ │ │ ├── ApisDeviceController.java │ │ │ └── ApisPushController.java │ │ │ ├── loader │ │ │ └── LoaderService.java │ │ │ └── pojo │ │ │ ├── BaseResp.java │ │ │ └── bo │ │ │ ├── Device.java │ │ │ └── LoadbanceNode.java │ └── resources │ │ ├── application.yml │ │ └── banner.txt │ └── test │ └── java │ └── .gitignore ├── go-push-handler-device ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── devices │ │ │ └── handlers │ │ │ ├── IDeviceDisconnectHandler.java │ │ │ ├── IDeviceDockedHandler.java │ │ │ └── IDeviceMessageHandler.java │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── go-push-handler-node ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── nodes │ │ │ └── handlers │ │ │ └── INodeMessageHandler.java │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── go-push-infos ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── infos │ │ │ ├── datacenter │ │ │ └── bo │ │ │ │ ├── DataCenterInfo.java │ │ │ │ ├── NodeClientLoaderInfo.java │ │ │ │ └── RestfulLoaderInfo.java │ │ │ └── nodeserver │ │ │ └── bo │ │ │ ├── HandlerInfo.java │ │ │ ├── NodeLoaderInfo.java │ │ │ ├── NodeServerInfo.java │ │ │ └── ProcessorInfo.java │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── go-push-monitor ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── monitor │ │ │ ├── MonitorApplication.java │ │ │ ├── config │ │ │ └── ZookeeperConfig.java │ │ │ ├── controller │ │ │ ├── MonitorController.java │ │ │ ├── MonitorDataController.java │ │ │ └── pojo │ │ │ │ └── BaseResp.java │ │ │ └── dymic │ │ │ └── discovery │ │ │ ├── MonitorDataCenterService.java │ │ │ └── MonitorNodeServerService.java │ └── resources │ │ ├── application.yml │ │ ├── banner.txt │ │ └── templates │ │ └── monitor.html │ └── test │ └── java │ └── .gitignore ├── go-push-node-server ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── nodeserver │ │ │ ├── NodeServerApplication.java │ │ │ ├── config │ │ │ ├── BatchProcessorConfig.java │ │ │ ├── GoPushNodeServerConfig.java │ │ │ └── ZookeeperConfig.java │ │ │ ├── devices │ │ │ ├── BatchProcessor.java │ │ │ ├── DeviceServerBootstrap.java │ │ │ ├── handlers │ │ │ │ ├── DeviceDeviceDisconnectHandler.java │ │ │ │ ├── DeviceDeviceDockedHandler.java │ │ │ │ ├── DevicePingHandler.java │ │ │ │ ├── DevicePongHandler.java │ │ │ │ ├── HandShakeHandler.java │ │ │ │ ├── PingPongProcessor.java │ │ │ │ └── PushRespHandler.java │ │ │ ├── inbound │ │ │ │ └── DeviceChannelInboundHandler.java │ │ │ ├── senders │ │ │ │ ├── IPushSender.java │ │ │ │ └── PushSender.java │ │ │ └── stores │ │ │ │ ├── DeviceChannelStore.java │ │ │ │ └── IDeviceChannelStore.java │ │ │ ├── dymic │ │ │ ├── discovery │ │ │ │ └── DataCenterDiscoveryService.java │ │ │ └── register │ │ │ │ └── NodeServerRegisterService.java │ │ │ ├── infos │ │ │ └── watchdog │ │ │ │ ├── NodeServerInfoWatchdog.java │ │ │ │ └── listener │ │ │ │ ├── PostNodeServerInfoDataListener.java │ │ │ │ └── event │ │ │ │ └── NodeServerInfoEvent.java │ │ │ └── nodes │ │ │ ├── NodeServerBootstrap.java │ │ │ ├── handlers │ │ │ ├── MessageToMultiDeviceHandler.java │ │ │ ├── MultiMessageToDeviceHandler.java │ │ │ ├── NodeBaseHandler.java │ │ │ ├── NodeDeviceDisconnectHandler.java │ │ │ ├── NodeDeviceDockedHandler.java │ │ │ ├── NodeInfoHandler.java │ │ │ ├── NodePingHandler.java │ │ │ └── NodePongHandler.java │ │ │ ├── inbound │ │ │ └── NodeChannelInBoundHandler.java │ │ │ ├── senders │ │ │ ├── INodeSender.java │ │ │ └── NodeSender.java │ │ │ └── stores │ │ │ ├── DataCenterChannelStore.java │ │ │ └── IDataCenterChannelStore.java │ └── resources │ │ ├── application.yml │ │ └── banner.txt │ └── test │ └── java │ └── .gitignore ├── go-push-protocol-device ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── protocol │ │ │ ├── device │ │ │ ├── DeviceMessage.java │ │ │ ├── DeviceMessageReq.java │ │ │ ├── DeviceMessageResp.java │ │ │ ├── HandShakeReq.java │ │ │ ├── HandShakeResp.java │ │ │ ├── Ping.java │ │ │ ├── Pong.java │ │ │ ├── PushReq.java │ │ │ └── PushResp.java │ │ │ └── exceptions │ │ │ └── DeviceProtocolException.java │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── go-push-protocol-node ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── gopush │ │ │ └── protocol │ │ │ ├── exceptions │ │ │ └── NodeProtocolException.java │ │ │ └── node │ │ │ ├── DeviceDisconReq.java │ │ │ ├── DeviceDisconResp.java │ │ │ ├── DeviceDockedReq.java │ │ │ ├── DeviceDockedResp.java │ │ │ ├── MessageToMultiDeviceReq.java │ │ │ ├── MessageToMultiDeviceResp.java │ │ │ ├── MultiMessageToDeviceReq.java │ │ │ ├── MultiMessageToDeviceResp.java │ │ │ ├── NodeInfoReq.java │ │ │ ├── NodeInfoResp.java │ │ │ ├── NodeMessage.java │ │ │ ├── NodeMessageReq.java │ │ │ ├── NodeMessageResp.java │ │ │ ├── Ping.java │ │ │ └── Pong.java │ └── resources │ │ └── .gitignore │ └── test │ └── java │ └── .gitignore ├── index.html └── pom.xml /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: CI MAVEN 5 | on: 6 | push: 7 | branches: [ master ] 8 | pull_request: 9 | branches: [ master ] 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up JDK 11 19 | uses: actions/setup-java@v2 20 | with: 21 | java-version: '11' 22 | distribution: 'adopt' 23 | cache: maven 24 | - name: Build with Maven 25 | run: mvn -B package --file pom.xml 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler Files # 2 | *.class 3 | 4 | # Package Files # 5 | *.jar 6 | *.war 7 | *.ear 8 | 9 | # IDE Files # 10 | *.iml 11 | .idea/** 12 | *.classpath 13 | *.project 14 | *.settings 15 | target/ 16 | 17 | # Zip Files # 18 | *.zip 19 | *.7z 20 | *.rar 21 | 22 | # Installer Files # 23 | *.exe 24 | *.so 25 | *.dll 26 | *.cab 27 | 28 | # Log Temp Files # 29 | *.via 30 | *.tmp 31 | *.err 32 | *.keep 33 | 34 | # Version Temp Files # 35 | *.bak 36 | *.svn 37 | *.git 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## GoPush ![](https://img.shields.io/github/stars/pinkhello/gopush?color=0088ff) ![](https://img.shields.io/github/forks/pinkhello/gopush?color=0088ff) ![](https://img.shields.io/github/issues/pinkhello/gopush?color=0088ff) ![](https://img.shields.io/github/issues-pr/pinkhello/gopush?color=0088ff) 2 | 3 | ## Project Repertories 4 | - [Github](https://github.com/pinkhello/gopush) 5 | - [Gitee](https://gitee.com/openWolf/gopush) 6 | 7 | ## Depends 8 | > `Netty`、`Zookeeper`、`Redis` 9 | > `Java8`、`SpringBoot` 10 | 11 | ## Description 12 | Suitable for customer service, IM, and Iot ...... 13 | 14 | [![Stargazers repo roster for @pinkhello/gopush](https://reporoster.com/stars/pinkhello/gopush)](https://github.com/pinkhello/gopush/stargazers) 15 | 16 | 17 | ## Stargazers over time 18 | 19 | [![Stargazers over time](https://starchart.cc/pinkhello/gopush.svg)](https://starchart.cc/pinkhello/gopush) 20 | 21 | 22 | ## Frames 23 | ![技术架构图](https://git.oschina.net/uploads/images/2017/0627/092129_ddd20f29_7872.png "技术架构图") 24 | -------------------------------------------------------------------------------- /go-push-adapter-sdk/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | jar 12 | go-push-adapter-sdk 13 | 14 | 15 | -------------------------------------------------------------------------------- /go-push-adapter-sdk/src/main/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-adapter-sdk/src/main/java/.gitignore -------------------------------------------------------------------------------- /go-push-adapter-sdk/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-adapter-sdk/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-adapter-sdk/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-adapter-sdk/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | com.gopush 13 | jar 14 | go-push-common 15 | 16 | 17 | 18 | 19 | io.netty 20 | netty-all 21 | provided 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | 27 | 28 | 29 | org.apache.curator 30 | curator-recipes 31 | 32 | 33 | org.apache.commons 34 | commons-lang3 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common; 2 | 3 | 4 | import io.netty.util.AttributeKey; 5 | 6 | /** 7 | * go-push 8 | * 9 | * @类功能说明:全局常量定义 10 | * @作者:喝咖啡的囊地鼠 11 | * @创建时间:2017/6/18 下午3:02 12 | * @VERSION: 13 | */ 14 | public class Constants { 15 | 16 | 17 | /***** 18 | * 19 | * Device 和 NodeServer 之间 20 | * 21 | * ***/ 22 | //绑定设备 23 | public static final AttributeKey CHANNEL_ATTR_DEVICE = AttributeKey.newInstance("device"); 24 | 25 | //绑定的握手状态 26 | public static final AttributeKey CHANNEL_ATTR_HANDSHAKE = AttributeKey.newInstance("handshake"); 27 | 28 | //绑定的心跳间隔 // read ,write, all 29 | public static final AttributeKey CHANNEL_ATTR_IDLE = AttributeKey.newInstance("idle"); 30 | 31 | /***** 32 | * 33 | * NodeServer 与 DataCenter 之间 34 | * 35 | * ***/ 36 | public static final AttributeKey CHANNEL_ATTR_DATACENTER = AttributeKey.newInstance("datacenter"); 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/DeviceMessageEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | /** 4 | * @author 喝咖啡的囊地鼠 5 | * @date 2017/9/14 上午12:14 6 | */ 7 | public enum DeviceMessageEnum { 8 | } 9 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/HandshakeEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/14 上午12:05 10 | */ 11 | @Getter 12 | public enum HandshakeEnum { 13 | HANDSAHKE_OK(200, "握手成功"), 14 | HANDSHAKE_INVALID_DEVICE(300, "非法设备"), 15 | HANDSHAKE_INVALID_TOKEN(301, "非法Token"); 16 | private int key; 17 | private String descri; 18 | 19 | HandshakeEnum(int key, String descri) { 20 | this.key = key; 21 | this.descri = descri; 22 | } 23 | 24 | public static HandshakeEnum fromKey(int key) { 25 | if (key <= 0) { 26 | return null; 27 | } 28 | return Arrays.stream(HandshakeEnum.values()) 29 | .filter(a -> key == a.getKey()) 30 | .findFirst() 31 | .orElse(null); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/IdleEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @author:喝咖啡的囊地鼠 11 | * @date:2017/7/10 下午11:38 12 | */ 13 | @Getter 14 | public enum IdleEnum { 15 | READ_IDLE(10), 16 | WRITE_IDLE(30), 17 | ALL_IDLE(50); 18 | private int value; 19 | 20 | IdleEnum(int value) { 21 | this.value = value; 22 | } 23 | 24 | public static IdleEnum fromValue(int value) { 25 | if (value <= 0) { 26 | return null; 27 | } 28 | return Arrays.stream(IdleEnum.values()) 29 | .filter(a -> value == a.getValue()) 30 | .findFirst() 31 | .orElse(null); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/NodeMessageEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | 8 | /** 9 | * @author 喝咖啡的囊地鼠 10 | * @date 2017/9/14 上午12:13 11 | */ 12 | @Getter 13 | public enum NodeMessageEnum { 14 | 15 | OK(200, "OK"), 16 | FAIL(500, "FAIL"); 17 | 18 | 19 | private int code; 20 | private String descri; 21 | 22 | NodeMessageEnum(int code, String descri) { 23 | this.code = code; 24 | this.descri = descri; 25 | } 26 | 27 | public static NodeMessageEnum fromCode(int code) { 28 | if (code <= 0) { 29 | return null; 30 | } 31 | return Arrays.stream(NodeMessageEnum.values()) 32 | .filter(a -> code == a.getCode()) 33 | .findFirst() 34 | .orElse(null); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/RedisKeyEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @author:喝咖啡的囊地鼠 11 | * @date:2017/7/11 上午12:14 12 | */ 13 | @Getter 14 | public enum RedisKeyEnum { 15 | 16 | DEVICE_KEY("DE:"), 17 | DEIVCE_TOKEN_FIELD("token"), 18 | DEVICE_NODE_FIELD("node"), 19 | DEVICE_CHANNEL_FIELD("channel"); 20 | 21 | private String value; 22 | 23 | RedisKeyEnum(String value) { 24 | this.value = value; 25 | } 26 | 27 | public static IdleEnum fromValue(String value) { 28 | if (value == null || value.isEmpty()) { 29 | return null; 30 | } 31 | return Arrays.stream(IdleEnum.values()) 32 | .filter(a -> value.equals(a.getValue())) 33 | .findFirst() 34 | .orElse(null); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/RestfulRespEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/14 下午5:31 10 | */ 11 | @Getter 12 | public enum RestfulRespEnum { 13 | 14 | OK(0, "成功"); 15 | 16 | private int key; 17 | private String descri; 18 | 19 | RestfulRespEnum(int key, String descri) { 20 | this.key = key; 21 | this.descri = descri; 22 | } 23 | 24 | 25 | public static RestfulRespEnum fromKey(int key) { 26 | if (key <= 0) { 27 | return null; 28 | } 29 | return Arrays.stream(RestfulRespEnum.values()) 30 | .filter(a -> key == a.getKey()) 31 | .findFirst() 32 | .orElse(null); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/constants/ZkGroupEnum.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.constants; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/12 上午3:16 10 | */ 11 | @Getter 12 | public enum ZkGroupEnum { 13 | NODE_SERVER("/NODE-SERVER"), 14 | DATA_CENTER("/DATA-CENTER"); 15 | private String value; 16 | 17 | ZkGroupEnum(String value) { 18 | this.value = value; 19 | } 20 | 21 | public static IdleEnum fromValue(String value) { 22 | if (value == null || value.isEmpty()) { 23 | return null; 24 | } 25 | return Arrays.stream(IdleEnum.values()) 26 | .filter(a -> value.equals(a.getValue())) 27 | .findFirst() 28 | .orElse(null); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/utils/ip/IpUtils.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.utils.ip; 2 | 3 | import java.net.Inet4Address; 4 | import java.net.InetAddress; 5 | import java.net.NetworkInterface; 6 | import java.util.Enumeration; 7 | 8 | /** 9 | * go-push 10 | * 11 | * @类功能说明:Ip工具类 12 | * @作者:喝咖啡的囊地鼠 13 | * @创建时间:2017/6/24 上午11:23 14 | * @VERSION: 15 | */ 16 | public class IpUtils { 17 | 18 | /*** 19 | * 获取外网IP 20 | * @return 21 | */ 22 | public static String internetIp() { 23 | try { 24 | 25 | Enumeration networks = NetworkInterface.getNetworkInterfaces(); 26 | InetAddress inetAddress = null; 27 | Enumeration inetAddresses = null; 28 | while (networks.hasMoreElements()) { 29 | inetAddresses = networks.nextElement().getInetAddresses(); 30 | while (inetAddresses.hasMoreElements()) { 31 | inetAddress = inetAddresses.nextElement(); 32 | if (inetAddress != null 33 | && inetAddress instanceof Inet4Address 34 | && !inetAddress.isSiteLocalAddress() 35 | && !inetAddress.isLoopbackAddress() 36 | && inetAddress.getHostAddress().indexOf(":") == -1) { 37 | return inetAddress.getHostAddress(); 38 | } 39 | } 40 | } 41 | 42 | return null; 43 | 44 | } catch (Exception e) { 45 | 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | 50 | /** 51 | * 获取内网IP 52 | * 53 | * @return 54 | */ 55 | public static String intranetIp() { 56 | try { 57 | return InetAddress.getLocalHost().getHostAddress(); 58 | } catch (Exception e) { 59 | throw new RuntimeException(e); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /go-push-common/src/main/java/com/gopush/common/utils/zk/listener/ZkStateListener.java: -------------------------------------------------------------------------------- 1 | package com.gopush.common.utils.zk.listener; 2 | 3 | import org.apache.curator.framework.CuratorFramework; 4 | import org.apache.curator.framework.state.ConnectionState; 5 | 6 | /** 7 | * @author 喝咖啡的囊地鼠 8 | * @date 2017/9/11 下午8:58 9 | */ 10 | public interface ZkStateListener { 11 | 12 | default void connectedEvent(CuratorFramework curator, ConnectionState state) { 13 | } 14 | 15 | default void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 16 | } 17 | 18 | default void lostEvent(CuratorFramework curator, ConnectionState state) { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /go-push-common/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-common/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-common/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-common/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-data-center/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | go-push-data-center 13 | jar 14 | 15 | DataCenter 服务 16 | 17 | 18 | 19 | 20 | com.gopush 21 | go-push-common 22 | ${project.version} 23 | 24 | 25 | com.gopush 26 | go-push-infos 27 | ${project.version} 28 | 29 | 30 | com.gopush 31 | go-push-protocol-node 32 | ${project.version} 33 | 34 | 35 | 36 | com.gopush 37 | go-push-handler-node 38 | ${project.version} 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-aop 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-data-redis 54 | 55 | 56 | 57 | com.didispace 58 | spring-boot-starter-swagger 59 | 60 | 61 | 62 | org.projectlombok 63 | lombok 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/DataCenterApplication.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter; 2 | 3 | import com.didispace.swagger.EnableSwagger2Doc; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.scheduling.annotation.EnableAsync; 7 | 8 | /** 9 | * go-push 10 | * 11 | * @类功能说明: 12 | * @作者:喝咖啡的囊地鼠 13 | * @创建时间:2017/6/11 下午1:28 14 | * @VERSION: 15 | */ 16 | @EnableSwagger2Doc 17 | @EnableAsync 18 | @SpringBootApplication 19 | public class DataCenterApplication { 20 | 21 | public static void main(String[] args) { 22 | SpringApplication.run(DataCenterApplication.class, args); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/config/GoPushDataCenterConfig.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明: 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/21 下午1:28 13 | * @VERSION: 14 | */ 15 | @Configuration 16 | @ConfigurationProperties(prefix = "go-push.data-center") 17 | @Data 18 | public class GoPushDataCenterConfig { 19 | private String name; 20 | } 21 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/config/ZookeeperConfig.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/11 下午11:44 10 | */ 11 | @Data 12 | @Configuration 13 | @ConfigurationProperties(prefix = "go-push.zookeeper") 14 | public class ZookeeperConfig { 15 | 16 | private String servers; 17 | 18 | private String namespace; 19 | 20 | private String listenNamespace; 21 | 22 | private int sessionTimeout; 23 | 24 | private int connectionTimeout; 25 | 26 | private int maxRetries; 27 | 28 | private int retriesSleepTime; 29 | } 30 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/dymic/discovery/NodeServerDiscoveryService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.dymic.discovery; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.gopush.common.constants.ZkGroupEnum; 5 | import com.gopush.common.utils.zk.ZkUtils; 6 | import com.gopush.common.utils.zk.listener.ZkStateListener; 7 | import com.gopush.datacenter.config.ZookeeperConfig; 8 | import com.gopush.datacenter.nodes.manager.NodeManager; 9 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.curator.framework.CuratorFramework; 12 | import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; 13 | import org.apache.curator.framework.state.ConnectionState; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Component; 16 | 17 | import javax.annotation.PostConstruct; 18 | import javax.annotation.PreDestroy; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | import java.util.concurrent.ConcurrentHashMap; 22 | 23 | /** 24 | * @author 喝咖啡的囊地鼠 25 | * @date 2017/9/12 上午3:13 26 | */ 27 | 28 | @Slf4j 29 | @Component 30 | public class NodeServerDiscoveryService { 31 | 32 | /** 33 | * 缓存的本地服务列表 34 | */ 35 | private Map nodeServerPool = new ConcurrentHashMap<>(); 36 | 37 | @Autowired 38 | private ZookeeperConfig zookeeperConfig; 39 | 40 | @Autowired 41 | private NodeManager nodeManager; 42 | 43 | 44 | private ZkUtils zkUtils; 45 | 46 | @PostConstruct 47 | public void init() { 48 | zkUtils = new ZkUtils(); 49 | zkUtils.init( 50 | zookeeperConfig.getServers(), 51 | zookeeperConfig.getConnectionTimeout(), 52 | zookeeperConfig.getSessionTimeout(), 53 | zookeeperConfig.getMaxRetries(), 54 | zookeeperConfig.getRetriesSleepTime(), 55 | zookeeperConfig.getListenNamespace(), 56 | new ZkStateListener() { 57 | @Override 58 | public void connectedEvent(CuratorFramework curator, ConnectionState state) { 59 | log.info("NodeServerDiscovery 链接zk成功"); 60 | initNodeServerDiscovery(); 61 | 62 | } 63 | 64 | @Override 65 | public void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 66 | log.info("NodeServerDiscovery 重新链接zk成功"); 67 | initNodeServerDiscovery(); 68 | } 69 | 70 | @Override 71 | public void lostEvent(CuratorFramework curator, ConnectionState state) { 72 | log.info("NodeServerDiscovery 链接zk丢失"); 73 | nodeServerPool.clear(); 74 | nodeManager.clear(); 75 | } 76 | }); 77 | 78 | listenNodeServerDiscovery(); 79 | } 80 | 81 | @PreDestroy 82 | public void destory() { 83 | nodeServerPool.clear(); 84 | zkUtils.destory(); 85 | } 86 | 87 | /** 88 | * 获取当前现在的Node -Server 服务列表 89 | * 90 | * @return 91 | */ 92 | public Map nodeServerPool() { 93 | return new HashMap<>(nodeServerPool); 94 | } 95 | 96 | /** 97 | * 初始化node-server列表 98 | */ 99 | private void initNodeServerDiscovery() { 100 | nodeServerPool.clear(); 101 | Map datas = zkUtils.readTargetChildsData(ZkGroupEnum.NODE_SERVER.getValue()); 102 | if (datas != null) { 103 | datas.forEach((k, v) -> nodeServerPool.put(k, JSON.parseObject(v, NodeServerInfo.class))); 104 | } 105 | nodeServerPool().forEach((k, v) -> nodeManager.put(k, v.getIntranetIp(), v.getNodePort(), v.getInternetIp(), v.getDevicePort())); 106 | 107 | } 108 | 109 | /** 110 | * 设置监听发生更新,更新缓存数据,发生新增,删除,更新 111 | */ 112 | private void listenNodeServerDiscovery() { 113 | zkUtils.listenerPathChildrenCache(ZkGroupEnum.NODE_SERVER.getValue(), ((client, event) -> { 114 | switch (event.getType()) { 115 | case CHILD_ADDED: 116 | addEvent(event); 117 | break; 118 | case CHILD_REMOVED: 119 | removeEvent(event); 120 | break; 121 | case CHILD_UPDATED: 122 | updateEvent(event); 123 | break; 124 | default: 125 | break; 126 | } 127 | })); 128 | } 129 | 130 | private void updateEvent(PathChildrenCacheEvent event) { 131 | String key = toKey(event); 132 | NodeServerInfo data = toNodeServerInfo(event); 133 | log.debug("node event update! key:{}, data:{}", key, data); 134 | //只需要更新缓存数据就可以了 135 | if (nodeServerPool.containsKey(key)) { 136 | nodeServerPool.put(key, data); 137 | } 138 | } 139 | 140 | private void removeEvent(PathChildrenCacheEvent event) { 141 | String key = toKey(event); 142 | NodeServerInfo data = toNodeServerInfo(event); 143 | log.info("node event remove! key:{}, data:{}", key, data); 144 | if (nodeServerPool.containsKey(key)) { 145 | //检测Node是否还存在,存在的话移除该Node 146 | nodeManager.remove(key); 147 | nodeServerPool.remove(key); 148 | } 149 | 150 | } 151 | 152 | private void addEvent(PathChildrenCacheEvent event) { 153 | String key = toKey(event); 154 | NodeServerInfo data = toNodeServerInfo(event); 155 | log.info("node event add! key:{}, data:{}", key, data); 156 | if (!nodeServerPool.containsKey(key)) { 157 | //开启node,加入到管理器 158 | nodeManager.put(key, data.getIntranetIp(), data.getNodePort(), data.getInternetIp(), data.getDevicePort()); 159 | nodeServerPool.put(key, data); 160 | } else { 161 | log.error("node already! {},{}", key, data); 162 | } 163 | } 164 | 165 | 166 | private String toKey(PathChildrenCacheEvent event) { 167 | String path = event.getData().getPath(); 168 | return path.substring(path.lastIndexOf("/")).replaceAll("/", ""); 169 | } 170 | 171 | private NodeServerInfo toNodeServerInfo(PathChildrenCacheEvent event) { 172 | return JSON.parseObject(event.getData().getData(), NodeServerInfo.class); 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/dymic/register/DataCenterRegisterService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.dymic.register; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.gopush.common.constants.ZkGroupEnum; 5 | import com.gopush.common.utils.zk.ZkUtils; 6 | import com.gopush.common.utils.zk.listener.ZkStateListener; 7 | import com.gopush.datacenter.config.GoPushDataCenterConfig; 8 | import com.gopush.datacenter.config.ZookeeperConfig; 9 | import com.gopush.datacenter.infos.watchdog.DataCenterInfoWatchdog; 10 | import com.gopush.infos.datacenter.bo.DataCenterInfo; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.curator.framework.CuratorFramework; 13 | import org.apache.curator.framework.state.ConnectionState; 14 | import org.apache.curator.utils.ZKPaths; 15 | import org.apache.zookeeper.CreateMode; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Component; 18 | 19 | import javax.annotation.PostConstruct; 20 | import javax.annotation.PreDestroy; 21 | 22 | /** 23 | * @author 喝咖啡的囊地鼠 24 | * @date 2017/9/12 下午2:20 25 | */ 26 | 27 | @Slf4j 28 | @Component 29 | public class DataCenterRegisterService { 30 | 31 | @Autowired 32 | private ZookeeperConfig zookeeperConfig; 33 | 34 | @Autowired 35 | private GoPushDataCenterConfig goPushDataCenterConfig; 36 | 37 | @Autowired 38 | private DataCenterInfoWatchdog watchdog; 39 | 40 | private ZkUtils zkUtils; 41 | 42 | @PostConstruct 43 | public void init() { 44 | zkUtils = new ZkUtils(); 45 | zkUtils.init( 46 | zookeeperConfig.getServers(), 47 | zookeeperConfig.getConnectionTimeout(), 48 | zookeeperConfig.getSessionTimeout(), 49 | zookeeperConfig.getMaxRetries(), 50 | zookeeperConfig.getRetriesSleepTime(), 51 | zookeeperConfig.getNamespace(), 52 | new ZkStateListener() { 53 | @Override 54 | public void connectedEvent(CuratorFramework curator, ConnectionState state) { 55 | log.info("DataCenterRegister 链接zk成功"); 56 | registerDataCenter(); 57 | 58 | } 59 | 60 | @Override 61 | public void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 62 | log.info("DataCenterRegister 重新链接zk成功"); 63 | registerDataCenter(); 64 | } 65 | 66 | @Override 67 | public void lostEvent(CuratorFramework curator, ConnectionState state) { 68 | log.info("DataCenterRegister 链接zk丢失"); 69 | } 70 | }); 71 | 72 | 73 | } 74 | 75 | @PreDestroy 76 | public void destory() { 77 | zkUtils.destory(); 78 | } 79 | 80 | 81 | public void postNewData(DataCenterInfo data) { 82 | zkUtils.setNodeData( 83 | ZKPaths.makePath(ZkGroupEnum.DATA_CENTER.getValue(), goPushDataCenterConfig.getName()), 84 | JSON.toJSONString(data)); 85 | } 86 | 87 | /** 88 | * 注册datacenter服务 89 | */ 90 | private void registerDataCenter() { 91 | 92 | if (!zkUtils.checkExists(ZkGroupEnum.DATA_CENTER.getValue())) { 93 | boolean flag; 94 | do { 95 | flag = zkUtils.createNode(ZkGroupEnum.DATA_CENTER.getValue(), null, CreateMode.PERSISTENT); 96 | } while (!flag); 97 | } 98 | registerDataCenterInfo(); 99 | } 100 | 101 | private void registerDataCenterInfo() { 102 | zkUtils.createNode( 103 | ZKPaths.makePath(ZkGroupEnum.DATA_CENTER.getValue(), goPushDataCenterConfig.getName()), 104 | JSON.toJSONString(watchdog.watch()), 105 | CreateMode.EPHEMERAL); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/infos/watchdog/DataCenterInfoWatchdog.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.infos.watchdog; 2 | 3 | import com.gopush.common.utils.ip.IpUtils; 4 | import com.gopush.datacenter.config.GoPushDataCenterConfig; 5 | import com.gopush.datacenter.infos.watchdog.listener.event.DataCenterInfoEvent; 6 | import com.gopush.datacenter.nodes.manager.NodeManager; 7 | import com.gopush.datacenter.restfuls.loader.LoaderService; 8 | import com.gopush.infos.datacenter.bo.DataCenterInfo; 9 | import lombok.Setter; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.context.ApplicationEventPublisher; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.util.StringUtils; 16 | 17 | import javax.annotation.PostConstruct; 18 | import java.util.concurrent.ScheduledExecutorService; 19 | import java.util.concurrent.ScheduledThreadPoolExecutor; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | /** 23 | * @author 喝咖啡的囊地鼠 24 | * @date 2017/9/15 上午8:28 25 | */ 26 | 27 | @Slf4j 28 | @Component 29 | public class DataCenterInfoWatchdog { 30 | 31 | @Autowired 32 | private GoPushDataCenterConfig goPushDataCenterConfig; 33 | 34 | @Autowired 35 | private ApplicationEventPublisher applicationEventPublisher; 36 | 37 | @Autowired 38 | private NodeManager nodeManager; 39 | 40 | @Autowired 41 | private LoaderService loaderService; 42 | 43 | @Setter 44 | private int delay = 5000; 45 | 46 | private ScheduledExecutorService scheduledExecutorService; 47 | 48 | @PostConstruct 49 | public void init() { 50 | scheduledExecutorService = new ScheduledThreadPoolExecutor(1, 51 | new BasicThreadFactory.Builder().namingPattern("SendDataCenterInfo-schedule-pool-%d").daemon(true).build()); 52 | scheduledExecutorService.scheduleAtFixedRate(() -> applicationEventPublisher.publishEvent(DataCenterInfoEvent.builder() 53 | .name(goPushDataCenterConfig.getName()) 54 | .dataCenterInfo(watch()) 55 | .build()), delay, delay, TimeUnit.MILLISECONDS); 56 | } 57 | 58 | 59 | /** 60 | * 获取系统负载信息 61 | * 62 | * @return 63 | */ 64 | public DataCenterInfo watch() { 65 | 66 | 67 | String internetIp = IpUtils.internetIp(); 68 | String intranetIp = IpUtils.intranetIp(); 69 | 70 | return DataCenterInfo.builder() 71 | .name(goPushDataCenterConfig.getName()) 72 | .internetIp(StringUtils.isEmpty(internetIp) ? intranetIp : internetIp) 73 | .intranetIp(intranetIp) 74 | .nodeClientLoaderInfos(nodeManager.loaders()) 75 | .restfulLoaderInfos(loaderService.restfulLoader()) 76 | .build(); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/infos/watchdog/listener/DataCenterInfoDataListener.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.infos.watchdog.listener; 2 | 3 | import com.gopush.datacenter.dymic.register.DataCenterRegisterService; 4 | import com.gopush.datacenter.infos.watchdog.listener.event.DataCenterInfoEvent; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.event.EventListener; 8 | import org.springframework.scheduling.annotation.Async; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @author 喝咖啡的囊地鼠 13 | * @date 2017/9/15 上午8:39 14 | */ 15 | @Slf4j 16 | @Component 17 | public class DataCenterInfoDataListener { 18 | @Autowired 19 | private DataCenterRegisterService dataCenterRegisterService; 20 | 21 | @Async 22 | @EventListener(condition = "#event.dataCenterInfo != null") 23 | public void postDataToZk(DataCenterInfoEvent event) { 24 | dataCenterRegisterService.postNewData(event.getDataCenterInfo()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/infos/watchdog/listener/event/DataCenterInfoEvent.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.infos.watchdog.listener.event; 2 | 3 | import com.gopush.infos.datacenter.bo.DataCenterInfo; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * @author 喝咖啡的囊地鼠 11 | * @date 2017/9/15 上午8:42 12 | */ 13 | @Data 14 | @Builder 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class DataCenterInfoEvent { 18 | private String name; 19 | private DataCenterInfo dataCenterInfo; 20 | } 21 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/DeviceDisconnectHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.common.constants.NodeMessageEnum; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.protocol.node.DeviceDisconReq; 6 | import com.gopush.protocol.node.DeviceDisconResp; 7 | import com.gopush.protocol.node.NodeMessage; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * go-push 15 | * 16 | * @类功能说明: 17 | * @作者:喝咖啡的囊地鼠 18 | * @创建时间:2017/6/21 下午11:03 19 | * @VERSION: 20 | */ 21 | 22 | @Slf4j 23 | @Component 24 | public class DeviceDisconnectHandler implements INodeMessageHandler { 25 | 26 | @Override 27 | public boolean support(NodeMessage message) { 28 | return message instanceof DeviceDisconReq; 29 | } 30 | 31 | @Override 32 | public void call(ChannelHandlerContext ctx, DeviceDisconReq message) { 33 | Channel channel = ctx.channel(); 34 | channel.writeAndFlush(DeviceDisconResp.builder().result(NodeMessageEnum.OK.getCode()).build().encode()); 35 | log.debug("receive DeviceDisconReq, channel:{}", channel); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/DeviceDockedHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.common.constants.NodeMessageEnum; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.protocol.node.DeviceDockedReq; 6 | import com.gopush.protocol.node.DeviceDockedResp; 7 | import com.gopush.protocol.node.NodeMessage; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * go-push 15 | * 16 | * @类功能说明: 17 | * @作者:喝咖啡的囊地鼠 18 | * @创建时间:2017/6/21 下午11:05 19 | * @VERSION: 20 | */ 21 | 22 | @Slf4j 23 | @Component 24 | public class DeviceDockedHandler implements INodeMessageHandler { 25 | @Override 26 | public boolean support(NodeMessage message) { 27 | return message instanceof DeviceDockedReq; 28 | } 29 | 30 | @Override 31 | public void call(ChannelHandlerContext ctx, DeviceDockedReq message) { 32 | Channel channel = ctx.channel(); 33 | channel.writeAndFlush(DeviceDockedResp.builder().result(NodeMessageEnum.OK.getCode()).build().encode()); 34 | log.debug("receive DeviceDockedReq, channel:{}", channel); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/MessageToMultiDeviceHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.nodes.handlers.INodeMessageHandler; 4 | import com.gopush.protocol.node.MessageToMultiDeviceResp; 5 | import com.gopush.protocol.node.NodeMessage; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明: 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/21 下午11:07 17 | * @VERSION: 18 | */ 19 | 20 | @Slf4j 21 | @Component 22 | public class MessageToMultiDeviceHandler implements INodeMessageHandler { 23 | @Override 24 | public boolean support(NodeMessage message) { 25 | return message instanceof MessageToMultiDeviceResp; 26 | } 27 | 28 | @Override 29 | public void call(ChannelHandlerContext ctx, MessageToMultiDeviceResp message) { 30 | Channel channel = ctx.channel(); 31 | 32 | 33 | log.debug("receive MessageToMultiDeviceResp, channel:{}", channel); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/MultiMessageToDeviceHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.nodes.handlers.INodeMessageHandler; 4 | import com.gopush.protocol.node.MultiMessageToDeviceResp; 5 | import com.gopush.protocol.node.NodeMessage; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明: 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/21 下午11:06 17 | * @VERSION: 18 | */ 19 | 20 | @Slf4j 21 | @Component 22 | public class MultiMessageToDeviceHandler implements INodeMessageHandler { 23 | @Override 24 | public boolean support(NodeMessage message) { 25 | return message instanceof MultiMessageToDeviceResp; 26 | } 27 | 28 | @Override 29 | public void call(ChannelHandlerContext ctx, MultiMessageToDeviceResp message) { 30 | Channel channel = ctx.channel(); 31 | 32 | log.debug("receive MessageToMultiDeviceResp, channel:{}", channel); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/NodeInfoHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.common.constants.NodeMessageEnum; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.protocol.node.NodeInfoReq; 6 | import com.gopush.protocol.node.NodeInfoResp; 7 | import com.gopush.protocol.node.NodeMessage; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * go-push 15 | * 16 | * @类功能说明: 17 | * @作者:喝咖啡的囊地鼠 18 | * @创建时间:2017/6/21 下午11:09 19 | * @VERSION: 20 | */ 21 | 22 | @Slf4j 23 | @Component 24 | public class NodeInfoHandler implements INodeMessageHandler { 25 | @Override 26 | public boolean support(NodeMessage message) { 27 | 28 | return message instanceof NodeInfoReq; 29 | } 30 | 31 | @Override 32 | public void call(ChannelHandlerContext ctx, NodeInfoReq message) { 33 | Channel channel = ctx.channel(); 34 | channel.writeAndFlush(NodeInfoResp.builder().result(NodeMessageEnum.OK.getCode()).build().encode()); 35 | log.debug("receive nodeInfoReq,channel:{}", channel); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/PingHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.nodes.handlers.INodeMessageHandler; 4 | import com.gopush.protocol.node.NodeMessage; 5 | import com.gopush.protocol.node.Ping; 6 | import com.gopush.protocol.node.Pong; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Component; 11 | 12 | 13 | /** 14 | * go-push 15 | * 16 | * @类功能说明: 17 | * @作者:喝咖啡的囊地鼠 18 | * @创建时间:2017/6/21 19 | * @VERSION: 20 | */ 21 | @Slf4j 22 | @Component 23 | public class PingHandler implements INodeMessageHandler { 24 | 25 | private static final String PONG = Pong.builder().build().encode(); 26 | 27 | @Override 28 | public boolean support(NodeMessage message) { 29 | return message instanceof Ping; 30 | } 31 | 32 | @Override 33 | public void call(ChannelHandlerContext ctx, Ping message) { 34 | Channel channel = ctx.channel(); 35 | channel.writeAndFlush(PONG); 36 | log.debug("receive ping,channel:{}", channel); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/handlers/PongHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.handlers; 2 | 3 | import com.gopush.nodes.handlers.INodeMessageHandler; 4 | import com.gopush.protocol.node.NodeMessage; 5 | import com.gopush.protocol.node.Pong; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | 12 | /** 13 | * go-push 14 | * 15 | * @类功能说明: 16 | * @作者:喝咖啡的囊地鼠 17 | * @创建时间:2017/6/21 18 | * @VERSION: 19 | */ 20 | 21 | @Slf4j 22 | @Component 23 | public class PongHandler implements INodeMessageHandler { 24 | @Override 25 | public boolean support(NodeMessage message) { 26 | return message instanceof Pong; 27 | } 28 | 29 | @Override 30 | public void call(ChannelHandlerContext ctx, Pong message) { 31 | Channel channel = ctx.channel(); 32 | 33 | 34 | log.debug("receive pong! channel:{}", channel); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/inbound/NodeChannelInBoundHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.inbound; 2 | 3 | import com.gopush.datacenter.nodes.manager.Node; 4 | import com.gopush.protocol.node.NodeMessage; 5 | import com.gopush.protocol.node.Ping; 6 | import com.gopush.protocol.node.Pong; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandler; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.SimpleChannelInboundHandler; 11 | import io.netty.handler.timeout.IdleState; 12 | import io.netty.handler.timeout.IdleStateEvent; 13 | import lombok.Data; 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | /** 17 | * go-push 18 | * 19 | * @类功能说明: 20 | * @作者:喝咖啡的囊地鼠 21 | * @创建时间:2017/6/24 上午12:23 22 | * @VERSION: 23 | */ 24 | 25 | @Slf4j 26 | @Data 27 | @ChannelHandler.Sharable 28 | public class NodeChannelInBoundHandler extends SimpleChannelInboundHandler { 29 | 30 | private static String PING = Ping.builder().build().encode(); 31 | 32 | /** 33 | * 对应的Node节点 34 | */ 35 | private Node node; 36 | 37 | public NodeChannelInBoundHandler(Node node) { 38 | this.node = node; 39 | } 40 | 41 | 42 | @Override 43 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 44 | log.debug("channel active, channel:{}", ctx.channel()); 45 | node.active(); 46 | //有发送失败的补发 47 | node.retrySendFail(); 48 | } 49 | 50 | @Override 51 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 52 | log.debug("channel inactive, channel:{}", ctx.channel()); 53 | node.inactive(); 54 | } 55 | 56 | @Override 57 | protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception { 58 | NodeMessage nodeMessage = NodeMessage.decode(message); 59 | //是心跳的,设置节点存活 60 | if (nodeMessage instanceof Ping || nodeMessage instanceof Pong) { 61 | node.active(); 62 | } 63 | node.handle(ctx, nodeMessage); 64 | } 65 | 66 | 67 | @Override 68 | public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { 69 | node.reconnect(ctx); 70 | } 71 | 72 | @Override 73 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 74 | log.error("exception error:{}, channel:{}", cause, ctx.channel()); 75 | ctx.close(); 76 | } 77 | 78 | @Override 79 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 80 | Channel channel = ctx.channel(); 81 | if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) { 82 | IdleStateEvent event = (IdleStateEvent) evt; 83 | if (event.state() == IdleState.ALL_IDLE) { 84 | //发送心跳 85 | channel.writeAndFlush(PING); 86 | } 87 | if (event.state() == IdleState.READER_IDLE) { 88 | //发送心跳 89 | channel.writeAndFlush(PING); 90 | } 91 | if (event.state() == IdleState.WRITER_IDLE) { 92 | channel.writeAndFlush(PING); 93 | } 94 | } else { 95 | super.userEventTriggered(ctx, evt); 96 | } 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/manager/INode.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.manager; 2 | 3 | import com.gopush.protocol.node.NodeMessage; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | /** 7 | * go-push 8 | * 9 | * @类功能说明: 10 | * @作者:喝咖啡的囊地鼠 11 | * @创建时间:2017/7/1 上午8:35 12 | * @VERSION: 13 | */ 14 | public interface INode { 15 | 16 | void init(); 17 | 18 | void destroy(); 19 | 20 | 21 | void active(); 22 | 23 | void inactive(); 24 | 25 | 26 | void send(NodeMessage message); 27 | 28 | void send(NodeMessage message, boolean retry); 29 | 30 | 31 | void retrySendFail(); 32 | 33 | void reconnect(ChannelHandlerContext ctx); 34 | 35 | void handle(ChannelHandlerContext ctx, NodeMessage message); 36 | 37 | 38 | int receiveCounter(); 39 | 40 | int sendCounter(); 41 | } 42 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/nodes/manager/NodeManager.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.nodes.manager; 2 | 3 | import com.gopush.infos.datacenter.bo.NodeClientLoaderInfo; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.annotation.PreDestroy; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.concurrent.ConcurrentHashMap; 15 | import java.util.stream.Collectors; 16 | 17 | /** 18 | * go-push 19 | * 20 | * @类功能说明: 21 | * @作者:喝咖啡的囊地鼠 22 | * @创建时间:2017/6/24 下午3:33 23 | * @VERSION: 24 | */ 25 | 26 | @Slf4j 27 | @Component 28 | public class NodeManager { 29 | 30 | private EventLoopGroup group = new NioEventLoopGroup(); 31 | 32 | private Map nodeChannelPool = new ConcurrentHashMap<>(); 33 | 34 | @Autowired 35 | private List nodeMessageHandlers; 36 | 37 | @PreDestroy 38 | public void destory() { 39 | nodeChannelPool.forEach((k, node) -> node.destroy()); 40 | nodeChannelPool.clear(); 41 | nodeChannelPool = null; 42 | group.shutdownGracefully(); 43 | } 44 | 45 | 46 | public void clear() { 47 | nodeChannelPool.forEach((k, node) -> node.destroy()); 48 | nodeChannelPool.clear(); 49 | 50 | } 51 | 52 | 53 | public void remove(String nodeName) { 54 | // log.info("node remove---------{}",nodeName); 55 | if (nodeChannelPool.containsKey(nodeName)) { 56 | nodeChannelPool.get(nodeName).destroy(); 57 | nodeChannelPool.remove(nodeName); 58 | } 59 | } 60 | 61 | public void put(String nodeName, 62 | String intranetIp, int nodePort, 63 | String internetIp, int devicePort) { 64 | remove(nodeName); 65 | // log.info("node add---------",nodeName); 66 | Node node = new Node(nodeName + "-client", intranetIp, nodePort, internetIp, devicePort, group, nodeMessageHandlers); 67 | node.init(); 68 | nodeChannelPool.put(nodeName, node); 69 | // log.info("{}", JSON.toJSONString(nodeChannelPool)); 70 | } 71 | 72 | public List loaders() { 73 | return nodeChannelPool.values().stream().map(e -> NodeClientLoaderInfo.builder().name(e.getName()).receiveCounter(e.receiveCounter()).sendCounter(e.sendCounter()).build()).collect(Collectors.toList()); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/aop/RestfulLoaderAspect.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.aop; 2 | 3 | import com.gopush.datacenter.restfuls.loader.LoaderService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | import org.aspectj.lang.reflect.MethodSignature; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.core.annotation.Order; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | /** 17 | * @author 喝咖啡的囊地鼠 18 | * @date 2017/9/15 下午12:35 19 | */ 20 | @Aspect 21 | @Component 22 | @Order(0) 23 | @Slf4j 24 | public class RestfulLoaderAspect { 25 | 26 | @Autowired 27 | private LoaderService loaderService; 28 | 29 | @Pointcut("execution(public * com.gopush.datacenter.restfuls.controller..*.*(..))") 30 | public void loaderPoint() { 31 | 32 | } 33 | 34 | @Around("loaderPoint()") 35 | public Object loaderAround(ProceedingJoinPoint pjp) throws Throwable { 36 | Method method = ((MethodSignature) pjp.getSignature()).getMethod(); 37 | loaderService.count(method); 38 | return pjp.proceed(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/controller/ApisDeviceController.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.controller; 2 | 3 | import com.gopush.common.constants.IdleEnum; 4 | import com.gopush.datacenter.dymic.discovery.NodeServerDiscoveryService; 5 | import com.gopush.datacenter.restfuls.pojo.BaseResp; 6 | import com.gopush.datacenter.restfuls.pojo.bo.Device; 7 | import com.gopush.datacenter.restfuls.pojo.bo.LoadbanceNode; 8 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import io.swagger.annotations.ApiParam; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.util.CollectionUtils; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import java.util.Comparator; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | import java.util.UUID; 21 | 22 | /** 23 | * @author 喝咖啡的囊地鼠 24 | * @date 2017/9/14 下午3:18 25 | */ 26 | 27 | @RestController 28 | @RequestMapping(value = "/apis/device") 29 | @Api(tags = "设备|链接相关") 30 | public class ApisDeviceController { 31 | 32 | @Autowired 33 | private NodeServerDiscoveryService nodeServerDiscoveryService; 34 | 35 | @ApiOperation(value = "设备注册", notes = "注册设备(一台设备只注册一次,但是可以增加APPCode)") 36 | @RequestMapping(value = "/register", method = RequestMethod.POST) 37 | public ResponseEntity> register(@RequestBody Device device) { 38 | //内部生产一个设备号给注册的设备 39 | //查找缓存,设置注册设备,没有设备的话注册,有的话检查appcode,没有的加入appcode 有的话直接返回已经注册的设备号 40 | //todo 41 | return ResponseEntity.ok(BaseResp.ok(token())); 42 | } 43 | 44 | @ApiOperation(value = "设备取消注册", notes = "取消注册设备(一台设备只注册一次)") 45 | @RequestMapping(value = "/unregister/{deviceNo}", method = RequestMethod.DELETE) 46 | public ResponseEntity unregister(@PathVariable("deviceNo") @ApiParam("设备号") String deviceNo) { 47 | //查找缓存,没有设备的话直接返回,有的话 取消注册的设备,清空设备的有效期(从而导致sdk端或者服务端关闭链接) 48 | //todo 49 | return ResponseEntity.ok(BaseResp.ok()); 50 | } 51 | 52 | @ApiOperation(value = "查询设备状态", notes = "查询设备状态") 53 | @RequestMapping(value = "/{deviceNo}/state", method = RequestMethod.GET) 54 | public ResponseEntity deviceState(@PathVariable("deviceNo") @ApiParam("设备号") String deviceNo) { 55 | //查找缓存,没有设备的话直接返回,有的话 取消注册的设备,清空设备的有效期(从而导致sdk端或者服务端关闭链接) 56 | //todo 查询设备状态 57 | return ResponseEntity.ok(BaseResp.ok()); 58 | } 59 | 60 | 61 | @ApiOperation(value = "设备选择链接节点", notes = "设备选择链接节点") 62 | @RequestMapping(value = "/select", method = RequestMethod.GET) 63 | public ResponseEntity> selectNode() { 64 | Map maps = new HashMap<>(nodeServerDiscoveryService.nodeServerPool()); 65 | if (!CollectionUtils.isEmpty(maps)) { 66 | NodeServerInfo info = maps.values().stream() 67 | .min(Comparator.comparingInt(e -> e.getNodeLoaderInfo().getOnlineDeviceCounter())) 68 | .get(); 69 | return ResponseEntity.ok( 70 | BaseResp.ok( 71 | LoadbanceNode.builder() 72 | .ip(info.getInternetIp()) 73 | .port(info.getDevicePort()) 74 | .readInterval(IdleEnum.READ_IDLE.getValue()) 75 | .writeInterval(IdleEnum.WRITE_IDLE.getValue()) 76 | .allInterval(IdleEnum.ALL_IDLE.getValue()) 77 | .build() 78 | )); 79 | } 80 | return ResponseEntity.ok(BaseResp.fail(400, "无可链接节点")); 81 | } 82 | 83 | 84 | private String token() { 85 | return UUID.randomUUID().toString().replaceAll("\\-", ""); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/controller/ApisPushController.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.controller; 2 | 3 | import com.gopush.datacenter.restfuls.pojo.BaseResp; 4 | import com.gopush.datacenter.restfuls.pojo.bo.Device; 5 | import io.swagger.annotations.Api; 6 | import io.swagger.annotations.ApiOperation; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | /** 14 | * @author 喝咖啡的囊地鼠 15 | * @date 2017/9/14 下午10:57 16 | */ 17 | 18 | 19 | @RestController 20 | @RequestMapping(value = "/apis/push") 21 | @Api(tags = "推送消息相关") 22 | public class ApisPushController { 23 | 24 | @ApiOperation(value = "向单个设备推送消息", notes = "向单个设备推送消息") 25 | @RequestMapping(value = "/one", method = RequestMethod.POST) 26 | public ResponseEntity pushOne(@RequestBody Device device) { 27 | //todo 28 | return ResponseEntity.ok(BaseResp.ok()); 29 | } 30 | 31 | @ApiOperation(value = "向多个设备推送消息", notes = "向多个设备推送消息") 32 | @RequestMapping(value = "/numerous", method = RequestMethod.POST) 33 | public ResponseEntity pushNumerous(@RequestBody Device device) { 34 | //todo 35 | return ResponseEntity.ok(BaseResp.ok()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/loader/LoaderService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.loader; 2 | 3 | import com.gopush.infos.datacenter.bo.RestfulLoaderInfo; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.method.HandlerMethod; 8 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo; 9 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 10 | 11 | import javax.annotation.PostConstruct; 12 | import javax.annotation.PreDestroy; 13 | import java.lang.reflect.Method; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.concurrent.ConcurrentHashMap; 18 | import java.util.concurrent.atomic.AtomicInteger; 19 | import java.util.stream.Collectors; 20 | 21 | /** 22 | * @author 喝咖啡的囊地鼠 23 | * @date 2017/9/15 下午12:56 24 | */ 25 | @Slf4j 26 | @Component 27 | public class LoaderService { 28 | 29 | private static final int INT_ZERO = 0; 30 | private static final int INT_MAX_VAL = Integer.MAX_VALUE - 1; 31 | 32 | @Autowired 33 | private RequestMappingHandlerMapping requestMappingHandlerMapping; 34 | 35 | private Map, AtomicInteger> restfulUrlCounters = new ConcurrentHashMap<>(); 36 | private Map> methodRestfulUrls = new ConcurrentHashMap<>(); 37 | 38 | @PostConstruct 39 | public void init() { 40 | Map handlerMethods = requestMappingHandlerMapping.getHandlerMethods(); 41 | 42 | handlerMethods.forEach((k, v) -> { 43 | List urls = k.getPatternsCondition().getPatterns().stream().sorted().collect(Collectors.toList()); 44 | methodRestfulUrls.put(v.getMethod(), urls); 45 | restfulUrlCounters.put(urls, new AtomicInteger(INT_ZERO)); 46 | }); 47 | 48 | } 49 | 50 | @PreDestroy 51 | public void destory() { 52 | methodRestfulUrls.clear(); 53 | methodRestfulUrls = null; 54 | restfulUrlCounters.clear(); 55 | restfulUrlCounters = null; 56 | } 57 | 58 | public List restfulLoader() { 59 | List list = new ArrayList<>(); 60 | restfulUrlCounters.forEach((k, v) -> list.add(RestfulLoaderInfo.builder().callCounter(v.get()).restfulUrl(new ArrayList(k)).build())); 61 | return list; 62 | } 63 | 64 | 65 | public void count(Method method) { 66 | if (methodRestfulUrls.containsKey(method)) { 67 | AtomicInteger count = restfulUrlCounters.get(methodRestfulUrls.get(method)); 68 | int c = count.incrementAndGet(); 69 | if (c >= INT_MAX_VAL) { 70 | count.set(INT_ZERO); 71 | } 72 | } 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/pojo/BaseResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.pojo; 2 | 3 | import com.gopush.common.constants.RestfulRespEnum; 4 | import lombok.*; 5 | 6 | /** 7 | * @author 喝咖啡的囊地鼠 8 | * @date 2017/9/14 下午5:27 9 | */ 10 | 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @EqualsAndHashCode 15 | @ToString 16 | @Getter 17 | public class BaseResp { 18 | private Integer code; 19 | private String description; 20 | private T data; 21 | 22 | public static BaseResp ok(T data) { 23 | return BaseResp.builder() 24 | .data(data) 25 | .code(RestfulRespEnum.OK.getKey()) 26 | .description(RestfulRespEnum.OK.getDescri()) 27 | .build(); 28 | } 29 | 30 | public static BaseResp ok() { 31 | return ok(null); 32 | } 33 | 34 | public static BaseResp fail(int failCode, String failMsg) { 35 | return fail(failCode, failMsg, null); 36 | } 37 | 38 | public static BaseResp fail(int failCode, String failMsg, T data) { 39 | return BaseResp.builder().code(failCode).description(failMsg).data(data).build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/pojo/bo/Device.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.pojo.bo; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | /** 11 | * @author 喝咖啡的囊地鼠 12 | * @date 2017/9/14 下午3:32 13 | */ 14 | @Data 15 | @Builder 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @ApiModel("设备") 19 | public class Device { 20 | 21 | @ApiModelProperty(value = "设备号", required = true, example = "IMEI99999") 22 | private String deviceNo; 23 | 24 | @ApiModelProperty(value = "设备类型", required = true, example = "ios,android,other") 25 | private String type; 26 | 27 | @ApiModelProperty(value = "应用Code", example = "com.baidu") 28 | private String appCode; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/java/com/gopush/datacenter/restfuls/pojo/bo/LoadbanceNode.java: -------------------------------------------------------------------------------- 1 | package com.gopush.datacenter.restfuls.pojo.bo; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | /** 11 | * @author 喝咖啡的囊地鼠 12 | * @date 2017/9/14 下午10:15 13 | */ 14 | 15 | @Data 16 | @Builder 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @ApiModel("选择节点") 20 | public class LoadbanceNode { 21 | @ApiModelProperty(value = "链接IP", example = "192.168.1.1") 22 | private String ip; 23 | 24 | @ApiModelProperty(value = "链接PORT", example = "9999") 25 | private int port; 26 | @ApiModelProperty(value = "读周期", example = "10") 27 | private int readInterval; 28 | @ApiModelProperty(value = "写周期", example = "30") 29 | private int writeInterval; 30 | @ApiModelProperty(value = "读写周期", example = "50") 31 | private int allInterval; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /go-push-data-center/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | 2 | server: 3 | port: ${random.int[5001,5999]} 4 | 5 | spring: 6 | redis: 7 | cluster: 8 | nodes: 9 | - 127.0.0.1:6379 10 | - 127.0.0.1:6379 11 | 12 | 13 | go-push: 14 | data-center: 15 | name: DataCenter-${random.int(100)} 16 | zookeeper: 17 | servers: 192.168.99.100:32773 18 | listen-namespace: namespace-node-server 19 | namespace: namespace-data-center 20 | session-timeout: 6000 21 | connection-timeout: 6000 22 | max-retries: 1000 23 | retries-sleep-time: 2000 24 | 25 | swagger: 26 | title: GoPush Restful接口 27 | description: ${swagger.title}文档说明 28 | version: ${application.version} 29 | license: GoPush 许可 30 | license-url: https://gitee.com/openWolf/gopush/blob/master/LICENSE 31 | terms-of-service-url: https://gitee.com/openWolf/gopush/issues/new 32 | contact: 33 | name: 喝咖啡的囊地鼠 34 | url: https://gitee.com/openWolf/gopush 35 | email: null_hello@qq.com 36 | base-package: com.gopush.datacenter.restful 37 | base-path: /** 38 | exclude-path: /error,/ops/** -------------------------------------------------------------------------------- /go-push-data-center/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_GREEN} 2 | _____ _ _____ _ 3 | | __ \ | | / ____| | | 4 | | | | | __ _| |_ __ _| | ___ _ __ | |_ ___ _ __ 5 | | | | |/ _` | __/ _` | | / _ \ '_ \| __/ _ \ '__| 6 | | |__| | (_| | || (_| | |___| __/ | | | || __/ | _____ _____ _ 7 | |_____/ \__,_|\__\__,_|\_____\___|_| |_|\__\___|_| / ____| | __ \ | | 8 | ______ ______ ______ ______ ______ ______ ______ ______ ______ ______ ______ | | __ ___ | |__) | _ ___| |__ 9 | |______|______|______|______|______|______|______|______|______|______|______| | | |_ |/ _ \| ___/ | | / __| '_ \ 10 | | |__| | (_) | | | |_| \__ \ | | | 11 | \_____|\___/|_| \__,_|___/_| |_| 12 | ${AnsiColor.BRIGHT_RED} 13 | Application Version: ${application.version}${application.formatted-version} 14 | Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} -------------------------------------------------------------------------------- /go-push-data-center/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-data-center/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-handler-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | go-push-handler-device 12 | jar 13 | GoPush业务handler 14 | 15 | 16 | 17 | com.gopush 18 | go-push-protocol-device 19 | ${project.version} 20 | 21 | 33 | 34 | io.netty 35 | netty-all 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /go-push-handler-device/src/main/java/com/gopush/devices/handlers/IDeviceDisconnectHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.devices.handlers; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | /** 6 | * go-push 7 | * 8 | * @类功能说明:设备断连处理接口 9 | * @作者:喝咖啡的囊地鼠 10 | * @创建时间:2017/6/19 上午12:20 11 | * @VERSION: 12 | */ 13 | public interface IDeviceDisconnectHandler { 14 | 15 | 16 | /** 17 | * channel关闭,触发 18 | * 19 | * @param channel 20 | */ 21 | void channelClosed(Channel channel); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /go-push-handler-device/src/main/java/com/gopush/devices/handlers/IDeviceDockedHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.devices.handlers; 2 | 3 | /** 4 | * go-push 5 | * 6 | * @类功能说明:设备上线报告 7 | * @作者:喝咖啡的囊地鼠 8 | * @创建时间:2017/6/19 上午12:51 9 | * @VERSION: 10 | */ 11 | public interface IDeviceDockedHandler { 12 | 13 | void upReport(String device, int channelHashCode, int[] idles); 14 | } 15 | -------------------------------------------------------------------------------- /go-push-handler-device/src/main/java/com/gopush/devices/handlers/IDeviceMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.devices.handlers; 2 | 3 | import com.gopush.protocol.device.DeviceMessage; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | /** 7 | * go-push 8 | * 9 | * @类功能说明: 10 | * @作者:喝咖啡的囊地鼠 11 | * @创建时间:2017/6/11 上午11:43 12 | * @VERSION: 13 | */ 14 | 15 | 16 | public interface IDeviceMessageHandler { 17 | 18 | /** 19 | * 根据各个handler 判断是不是各个handler对应处理的消息 20 | * 21 | * @param message 节点消息 22 | * @return 是否各个NodeMessage 子类的类型 23 | */ 24 | boolean support(DeviceMessage message); 25 | 26 | /** 27 | * 各个消息处理句柄调用方法 28 | * 29 | * @param message 节点消息 30 | */ 31 | void call(ChannelHandlerContext context, R message); 32 | } 33 | -------------------------------------------------------------------------------- /go-push-handler-device/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-handler-device/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-handler-device/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-handler-device/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-handler-node/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | go-push-handler-node 13 | jar 14 | GoPush业务handler 15 | 16 | 17 | 18 | com.gopush 19 | go-push-protocol-node 20 | ${project.version} 21 | 22 | 23 | 34 | 35 | io.netty 36 | netty-all 37 | 38 | 39 | -------------------------------------------------------------------------------- /go-push-handler-node/src/main/java/com/gopush/nodes/handlers/INodeMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodes.handlers; 2 | 3 | 4 | import com.gopush.protocol.node.NodeMessage; 5 | import io.netty.channel.ChannelHandlerContext; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:node 节点业务抽象接口 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/12 上午12:28 13 | * @VERSION: 14 | */ 15 | public interface INodeMessageHandler { 16 | 17 | /** 18 | * 根据各个handler 判断是不是各个handler对应处理的消息 19 | * 20 | * @param message 节点消息 21 | * @return 是否各个NodeMessage 子类的类型 22 | */ 23 | boolean support(NodeMessage message); 24 | 25 | 26 | /** 27 | * 各个消息处理句柄调用方法 28 | * 29 | * @param message 节点消息 30 | */ 31 | void call(ChannelHandlerContext ctx, R message); 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /go-push-handler-node/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-handler-node/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-handler-node/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-handler-node/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-infos/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | go-push-infos 13 | 14 | 15 | 16 | com.alibaba 17 | fastjson 18 | 19 | 20 | org.projectlombok 21 | lombok 22 | provided 23 | 24 | 25 | -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/datacenter/bo/DataCenterInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.datacenter.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author 喝咖啡的囊地鼠 12 | * @date 2017/9/15 上午7:56 13 | */ 14 | @Builder 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class DataCenterInfo { 19 | private String name; 20 | //内网IP 21 | private String intranetIp; 22 | //外网IP 23 | private String internetIp; 24 | 25 | private List restfulLoaderInfos; 26 | 27 | private List nodeClientLoaderInfos; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/datacenter/bo/NodeClientLoaderInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.datacenter.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * @author 喝咖啡的囊地鼠 10 | * @date 2017/9/15 上午11:39 11 | */ 12 | @Builder 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class NodeClientLoaderInfo { 17 | private String name; 18 | private int receiveCounter; 19 | private int sendCounter; 20 | } 21 | -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/datacenter/bo/RestfulLoaderInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.datacenter.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author 喝咖啡的囊地鼠 12 | * @date 2017/9/15 上午11:17 13 | */ 14 | 15 | @Builder 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class RestfulLoaderInfo { 20 | 21 | private int callCounter; 22 | 23 | private List restfulUrl; 24 | 25 | } -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/nodeserver/bo/HandlerInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.nodeserver.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * go-push 12 | * 13 | * @类功能说明: 14 | * @作者:喝咖啡的囊地鼠 15 | * @创建时间:2017/6/20 下午8:41 16 | * @VERSION: 17 | */ 18 | @Builder 19 | @Data 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | public class HandlerInfo { 23 | 24 | private String batchExecutorName; 25 | 26 | private int receiveCounter; 27 | 28 | private int failCounter; 29 | 30 | private int retryCounter; 31 | 32 | private List processorInfos; 33 | } 34 | -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/nodeserver/bo/NodeLoaderInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.nodeserver.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author 喝咖啡的囊地鼠 12 | * @date 2017/9/10 下午1:59 13 | */ 14 | 15 | @Builder 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class NodeLoaderInfo { 20 | private int onlineDeviceCounter; 21 | private int onlineDcCounter; 22 | private List handlerInfos; 23 | } 24 | -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/nodeserver/bo/NodeServerInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.nodeserver.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * @author 喝咖啡的囊地鼠 10 | * @date 2017/9/12 上午12:17 11 | */ 12 | @Builder 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class NodeServerInfo { 17 | //名称 18 | private String name; 19 | //内网IP 20 | private String intranetIp; 21 | //外网IP 22 | private String internetIp; 23 | //对设备监听端口 24 | private int devicePort; 25 | //对内监听端口 26 | private int nodePort; 27 | //系统负载信息 28 | private NodeLoaderInfo nodeLoaderInfo; 29 | } 30 | -------------------------------------------------------------------------------- /go-push-infos/src/main/java/com/gopush/infos/nodeserver/bo/ProcessorInfo.java: -------------------------------------------------------------------------------- 1 | package com.gopush.infos.nodeserver.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * go-push 10 | * 11 | * @类功能说明:每个批处理机内部处理器 信息 12 | * @作者:喝咖啡的囊地鼠 13 | * @创建时间:2017/6/20 下午8:37 14 | * @VERSION: 15 | */ 16 | @Builder 17 | @Data 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public class ProcessorInfo { 21 | 22 | private String batchName; 23 | 24 | private int index; 25 | 26 | private int loader; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /go-push-infos/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-infos/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-infos/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-infos/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-monitor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | go-push-monitor 12 | jar 13 | GoPush监控服务 14 | 15 | 16 | 17 | 18 | 19 | com.gopush 20 | go-push-common 21 | ${project.version} 22 | 23 | 24 | com.gopush 25 | go-push-infos 26 | ${project.version} 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-data-redis 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-thymeleaf 48 | 49 | 50 | 51 | 52 | com.didispace 53 | spring-boot-starter-swagger 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/MonitorApplication.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor; 2 | 3 | import com.didispace.swagger.EnableSwagger2Doc; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:监控中心 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/10 上午4:43 13 | * @VERSION: 14 | */ 15 | @EnableSwagger2Doc 16 | @SpringBootApplication 17 | public class MonitorApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(MonitorApplication.class, args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/config/ZookeeperConfig.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/11 下午11:44 10 | */ 11 | @Data 12 | @Configuration 13 | @ConfigurationProperties(prefix = "go-push.zookeeper") 14 | public class ZookeeperConfig { 15 | 16 | private String servers; 17 | 18 | private String listenNamespaceDataCenter; 19 | 20 | private String listenNamespaceNodeServer; 21 | 22 | private int sessionTimeout; 23 | 24 | private int connectionTimeout; 25 | 26 | private int maxRetries; 27 | 28 | private int retriesSleepTime; 29 | } 30 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/controller/MonitorController.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor.controller; 2 | 3 | import io.swagger.annotations.Api; 4 | import io.swagger.annotations.ApiOperation; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | 9 | /** 10 | * @author 喝咖啡的囊地鼠 11 | * @date 2017/9/15 下午5:15 12 | */ 13 | @Controller 14 | @Api(tags = "监控中心") 15 | public class MonitorController { 16 | 17 | @ApiOperation("首页跳转") 18 | @RequestMapping(value = "/", method = RequestMethod.GET) 19 | public String index() { 20 | return "redirect:/monitor"; 21 | } 22 | 23 | @ApiOperation("监控中心") 24 | @RequestMapping(value = "/monitor", method = RequestMethod.GET) 25 | public String monitor() { 26 | return "monitor"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/controller/MonitorDataController.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor.controller; 2 | 3 | import com.gopush.infos.datacenter.bo.DataCenterInfo; 4 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 5 | import com.gopush.monitor.controller.pojo.BaseResp; 6 | import com.gopush.monitor.dymic.discovery.MonitorDataCenterService; 7 | import com.gopush.monitor.dymic.discovery.MonitorNodeServerService; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * @author 喝咖啡的囊地鼠 20 | * @date 2017/9/15 下午5:09 21 | */ 22 | @RestController 23 | @RequestMapping("/monitor") 24 | @Api(tags = "监控数据") 25 | public class MonitorDataController { 26 | 27 | @Autowired 28 | private MonitorDataCenterService monitorDataCenterService; 29 | 30 | @Autowired 31 | private MonitorNodeServerService monitorNodeServerService; 32 | 33 | @ApiOperation(value = "数据中心监控", notes = "DataCenter 数据中心 监控数据") 34 | @RequestMapping(value = "/dc", method = RequestMethod.GET) 35 | public ResponseEntity>> dataCenterInfos() { 36 | return ResponseEntity.ok(BaseResp.ok(monitorDataCenterService.dataCenterLoader())); 37 | } 38 | 39 | @ApiOperation(value = "节点服务监控", notes = "NodeServer 节点服务 监控数据") 40 | @RequestMapping(value = "/node", method = RequestMethod.GET) 41 | public ResponseEntity>> nodeServceInfos() { 42 | return ResponseEntity.ok(BaseResp.ok(monitorNodeServerService.nodeServerLoader())); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/controller/pojo/BaseResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor.controller.pojo; 2 | 3 | import com.gopush.common.constants.RestfulRespEnum; 4 | import lombok.*; 5 | 6 | /** 7 | * @author 喝咖啡的囊地鼠 8 | * @date 2017/9/14 下午5:27 9 | */ 10 | 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @EqualsAndHashCode 15 | @ToString 16 | @Getter 17 | public class BaseResp { 18 | private Integer code; 19 | private String description; 20 | private T data; 21 | 22 | public static BaseResp ok(T data) { 23 | return BaseResp.builder() 24 | .data(data) 25 | .code(RestfulRespEnum.OK.getKey()) 26 | .description(RestfulRespEnum.OK.getDescri()) 27 | .build(); 28 | } 29 | 30 | public static BaseResp ok() { 31 | return ok(null); 32 | } 33 | 34 | public static BaseResp fail(int failCode, String failMsg) { 35 | return fail(failCode, failMsg, null); 36 | } 37 | 38 | public static BaseResp fail(int failCode, String failMsg, T data) { 39 | return BaseResp.builder().code(failCode).description(failMsg).data(data).build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/dymic/discovery/MonitorDataCenterService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor.dymic.discovery; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.gopush.common.constants.ZkGroupEnum; 5 | import com.gopush.common.utils.zk.ZkUtils; 6 | import com.gopush.common.utils.zk.listener.ZkStateListener; 7 | import com.gopush.infos.datacenter.bo.DataCenterInfo; 8 | import com.gopush.monitor.config.ZookeeperConfig; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.curator.framework.CuratorFramework; 11 | import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; 12 | import org.apache.curator.framework.state.ConnectionState; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Component; 15 | 16 | import javax.annotation.PostConstruct; 17 | import javax.annotation.PreDestroy; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | import java.util.stream.Collectors; 22 | 23 | /** 24 | * @author 喝咖啡的囊地鼠 25 | * @date 2017/9/15 下午3:50 26 | */ 27 | 28 | @Slf4j 29 | @Component 30 | public class MonitorDataCenterService { 31 | 32 | //缓存的本地服务列表 33 | private Map monitorDataCenterPool = new ConcurrentHashMap<>(); 34 | 35 | 36 | @Autowired 37 | private ZookeeperConfig zookeeperConfig; 38 | 39 | private ZkUtils zkUtils; 40 | 41 | @PostConstruct 42 | public void init() { 43 | zkUtils = new ZkUtils(); 44 | zkUtils.init( 45 | zookeeperConfig.getServers(), 46 | zookeeperConfig.getConnectionTimeout(), 47 | zookeeperConfig.getSessionTimeout(), 48 | zookeeperConfig.getMaxRetries(), 49 | zookeeperConfig.getRetriesSleepTime(), 50 | zookeeperConfig.getListenNamespaceDataCenter(), 51 | new ZkStateListener() { 52 | @Override 53 | public void connectedEvent(CuratorFramework curator, ConnectionState state) { 54 | log.info("MonitorDataCenter 链接zk成功"); 55 | initDataCenterPool(); 56 | 57 | } 58 | 59 | @Override 60 | public void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 61 | log.info("MonitorDataCenter 重新链接zk成功"); 62 | initDataCenterPool(); 63 | } 64 | 65 | @Override 66 | public void lostEvent(CuratorFramework curator, ConnectionState state) { 67 | log.info("MonitorDataCenter 链接zk丢失"); 68 | monitorDataCenterPool.clear(); 69 | } 70 | }); 71 | 72 | listenDataCenter(); 73 | } 74 | 75 | @PreDestroy 76 | public void destory() { 77 | monitorDataCenterPool.clear(); 78 | zkUtils.destory(); 79 | } 80 | 81 | 82 | public List dataCenterLoader() { 83 | return monitorDataCenterPool.values().stream().collect(Collectors.toList()); 84 | } 85 | 86 | private void initDataCenterPool() { 87 | monitorDataCenterPool.clear(); 88 | Map datas = zkUtils.readTargetChildsData(ZkGroupEnum.DATA_CENTER.getValue()); 89 | if (datas != null) { 90 | datas.forEach((k, v) -> monitorDataCenterPool.put(k, JSON.parseObject(v, DataCenterInfo.class))); 91 | } 92 | } 93 | 94 | /** 95 | * 设置监听发生更新,更新缓存数据,发生新增,删除,更新 96 | */ 97 | private void listenDataCenter() { 98 | zkUtils.listenerPathChildrenCache(ZkGroupEnum.DATA_CENTER.getValue(), ((client, event) -> { 99 | switch (event.getType()) { 100 | case CHILD_ADDED: 101 | addEvent(event); 102 | break; 103 | case CHILD_REMOVED: 104 | removeEvent(event); 105 | break; 106 | case CHILD_UPDATED: 107 | updateEvent(event); 108 | break; 109 | default: 110 | break; 111 | } 112 | })); 113 | } 114 | 115 | private void updateEvent(PathChildrenCacheEvent event) { 116 | String key = toKey(event); 117 | DataCenterInfo data = toDataCenterInfo(event); 118 | log.debug(" Monitor data center event update! key:{}, data:{}", key, data); 119 | if (monitorDataCenterPool.containsKey(key)) { 120 | monitorDataCenterPool.put(key, data); 121 | } 122 | } 123 | 124 | private void removeEvent(PathChildrenCacheEvent event) { 125 | String key = toKey(event); 126 | DataCenterInfo data = toDataCenterInfo(event); 127 | log.debug(" Monitor data center event remove! key:{}, data:{}", key, data); 128 | if (monitorDataCenterPool.containsKey(key)) { 129 | monitorDataCenterPool.remove(key); 130 | } 131 | 132 | } 133 | 134 | private void addEvent(PathChildrenCacheEvent event) { 135 | String key = toKey(event); 136 | DataCenterInfo data = toDataCenterInfo(event); 137 | log.debug(" Monitor data center event add! key:{}, data:{}", key, data); 138 | if (!monitorDataCenterPool.containsKey(key)) { 139 | //开启node,加入到管理器 140 | monitorDataCenterPool.put(key, data); 141 | } else { 142 | log.error(" Monitor data center already! {},{}", key, data); 143 | } 144 | } 145 | 146 | 147 | private String toKey(PathChildrenCacheEvent event) { 148 | String path = event.getData().getPath(); 149 | return path.substring(path.lastIndexOf("/")).replaceAll("/", ""); 150 | } 151 | 152 | private DataCenterInfo toDataCenterInfo(PathChildrenCacheEvent event) { 153 | return JSON.parseObject(event.getData().getData(), DataCenterInfo.class); 154 | } 155 | 156 | 157 | } 158 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/java/com/gopush/monitor/dymic/discovery/MonitorNodeServerService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.monitor.dymic.discovery; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.gopush.common.constants.ZkGroupEnum; 5 | import com.gopush.common.utils.zk.ZkUtils; 6 | import com.gopush.common.utils.zk.listener.ZkStateListener; 7 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 8 | import com.gopush.monitor.config.ZookeeperConfig; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.curator.framework.CuratorFramework; 11 | import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; 12 | import org.apache.curator.framework.state.ConnectionState; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Component; 15 | 16 | import javax.annotation.PostConstruct; 17 | import javax.annotation.PreDestroy; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | import java.util.stream.Collectors; 22 | 23 | /** 24 | * @author 喝咖啡的囊地鼠 25 | * @date 2017/9/15 下午3:49 26 | */ 27 | 28 | @Slf4j 29 | @Component 30 | public class MonitorNodeServerService { 31 | 32 | //缓存的本地服务列表 33 | private Map monitorNodeServerPool = new ConcurrentHashMap<>(); 34 | 35 | 36 | @Autowired 37 | private ZookeeperConfig zookeeperConfig; 38 | 39 | private ZkUtils zkUtils; 40 | 41 | 42 | @PostConstruct 43 | public void init() { 44 | zkUtils = new ZkUtils(); 45 | zkUtils.init( 46 | zookeeperConfig.getServers(), 47 | zookeeperConfig.getConnectionTimeout(), 48 | zookeeperConfig.getSessionTimeout(), 49 | zookeeperConfig.getMaxRetries(), 50 | zookeeperConfig.getRetriesSleepTime(), 51 | zookeeperConfig.getListenNamespaceNodeServer(), 52 | new ZkStateListener() { 53 | @Override 54 | public void connectedEvent(CuratorFramework curator, ConnectionState state) { 55 | log.info("MonitorNodeServer 链接zk成功"); 56 | initNodeServerPool(); 57 | 58 | } 59 | 60 | @Override 61 | public void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 62 | log.info("MonitorNodeServer 重新链接zk成功"); 63 | initNodeServerPool(); 64 | } 65 | 66 | @Override 67 | public void lostEvent(CuratorFramework curator, ConnectionState state) { 68 | log.info("MonitorNodeServer 链接zk丢失"); 69 | monitorNodeServerPool.clear(); 70 | } 71 | }); 72 | listenNodeServer(); 73 | 74 | } 75 | 76 | @PreDestroy 77 | public void destory() { 78 | monitorNodeServerPool.clear(); 79 | zkUtils.destory(); 80 | } 81 | 82 | 83 | public List nodeServerLoader() { 84 | return monitorNodeServerPool.values().stream().collect(Collectors.toList()); 85 | } 86 | 87 | 88 | private void initNodeServerPool() { 89 | monitorNodeServerPool.clear(); 90 | Map datas = zkUtils.readTargetChildsData(ZkGroupEnum.NODE_SERVER.getValue()); 91 | if (datas != null) { 92 | datas.forEach((k, v) -> monitorNodeServerPool.put(k, JSON.parseObject(v, NodeServerInfo.class))); 93 | } 94 | } 95 | 96 | private void listenNodeServer() { 97 | zkUtils.listenerPathChildrenCache(ZkGroupEnum.NODE_SERVER.getValue(), ((zkclient, event) -> { 98 | switch (event.getType()) { 99 | case CHILD_ADDED: 100 | addEvent(event); 101 | break; 102 | case CHILD_REMOVED: 103 | removeEvent(event); 104 | break; 105 | case CHILD_UPDATED: 106 | updateEvent(event); 107 | break; 108 | default: 109 | break; 110 | 111 | } 112 | })); 113 | } 114 | 115 | private void updateEvent(PathChildrenCacheEvent event) { 116 | String key = toKey(event); 117 | NodeServerInfo data = toNodeServerInfo(event); 118 | log.debug(" Monitor node event update! key:{}, data:{}", key, data); 119 | if (monitorNodeServerPool.containsKey(key)) { 120 | monitorNodeServerPool.put(key, data); 121 | } 122 | } 123 | 124 | private void removeEvent(PathChildrenCacheEvent event) { 125 | String key = toKey(event); 126 | NodeServerInfo data = toNodeServerInfo(event); 127 | log.debug(" Monitor node event remove! key:{}, data:{}", key, data); 128 | if (monitorNodeServerPool.containsKey(key)) { 129 | monitorNodeServerPool.remove(key); 130 | } 131 | 132 | } 133 | 134 | private void addEvent(PathChildrenCacheEvent event) { 135 | String key = toKey(event); 136 | NodeServerInfo data = toNodeServerInfo(event); 137 | log.debug(" Monitor node event add! key:{}, data:{}", key, data); 138 | if (!monitorNodeServerPool.containsKey(key)) { 139 | //开启node,加入到管理器 140 | monitorNodeServerPool.put(key, data); 141 | } else { 142 | log.error(" Monitor node already! {},{}", key, data); 143 | } 144 | } 145 | 146 | 147 | private String toKey(PathChildrenCacheEvent event) { 148 | String path = event.getData().getPath(); 149 | return path.substring(path.lastIndexOf("/")).replaceAll("/", ""); 150 | } 151 | 152 | private NodeServerInfo toNodeServerInfo(PathChildrenCacheEvent event) { 153 | return JSON.parseObject(event.getData().getData(), NodeServerInfo.class); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /go-push-monitor/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | go-push: 5 | zookeeper: 6 | servers: 192.168.99.100:32773 7 | listen-namespace-node-server: namespace-node-server 8 | listen-namespace-data-center: namespace-data-center 9 | session-timeout: 6000 10 | connection-timeout: 6000 11 | max-retries: 1000 12 | retries-sleep-time: 2000 13 | 14 | 15 | spring: 16 | thymeleaf: 17 | cache: false 18 | 19 | swagger: 20 | title: GoPush 监控中心接口 21 | description: ${swagger.title}文档说明 22 | version: ${application.version} 23 | license: GoPush 许可 24 | license-url: https://gitee.com/openWolf/gopush/blob/master/LICENSE 25 | terms-of-service-url: https://gitee.com/openWolf/gopush/issues/new 26 | contact: 27 | name: 喝咖啡的囊地鼠 28 | url: https://gitee.com/openWolf/gopush 29 | email: null_hello@qq.com 30 | base-package: com.gopush.monitor.controller 31 | base-path: /** 32 | exclude-path: /error,/ops/** -------------------------------------------------------------------------------- /go-push-monitor/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_GREEN} 2 | __ __ _ _ 3 | | \/ | (_) | 4 | | \ / | ___ _ __ _| |_ ___ _ __ 5 | | |\/| |/ _ \| '_ \| | __/ _ \| '__| _____ _____ _ 6 | | | | | (_) | | | | | || (_) | | / ____| | __ \ | | 7 | |_|__|_|\___/|_|_|_|_|\__\___/|_|__ ______ ______ ______ ______ ______ ______ | | __ ___ | |__) | _ ___| |__ 8 | |______|______|______|______|______|______|______|______|______|______|______| | | |_ |/ _ \| ___/ | | / __| '_ \ 9 | | |__| | (_) | | | |_| \__ \ | | | 10 | \_____|\___/|_| \__,_|___/_| |_| 11 | 12 | ${AnsiColor.BRIGHT_RED} 13 | Application Version: ${application.version}${application.formatted-version} 14 | Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} -------------------------------------------------------------------------------- /go-push-monitor/src/main/resources/templates/monitor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 监控中心 6 | 7 | 8 |

Hello World

9 | 10 | -------------------------------------------------------------------------------- /go-push-monitor/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-monitor/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-node-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | go-push-node-server 12 | jar 13 | NodeServer 服务 14 | 15 | 16 | 17 | 18 | com.gopush 19 | go-push-common 20 | ${project.version} 21 | 22 | 23 | com.gopush 24 | go-push-handler-node 25 | ${project.version} 26 | 27 | 28 | com.gopush 29 | go-push-handler-device 30 | ${project.version} 31 | 32 | 33 | com.gopush 34 | go-push-infos 35 | ${project.version} 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-data-redis 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-web 51 | 52 | 53 | 54 | org.projectlombok 55 | lombok 56 | 57 | 58 | 59 | io.netty 60 | netty-all 61 | 62 | 63 | 64 | commons-collections 65 | commons-collections 66 | 67 | 68 | 69 | org.apache.commons 70 | commons-lang3 71 | 72 | 73 | 74 | org.apache.curator 75 | curator-recipes 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/NodeServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明: 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/11 上午11:43 13 | * @VERSION: 14 | */ 15 | @EnableAsync 16 | @SpringBootApplication 17 | public class NodeServerApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(NodeServerApplication.class, args); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/config/BatchProcessorConfig.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/11 下午11:33 10 | */ 11 | @Data 12 | @Configuration 13 | @ConfigurationProperties(prefix = "go-push.node-server.batch-processor") 14 | public class BatchProcessorConfig { 15 | /** 16 | * 批量处理的定时器延时 17 | */ 18 | private int delay; 19 | /** 20 | * 批量处理的大小 21 | */ 22 | private int batchSize; 23 | /** 24 | * 消息队列里面超过这个大小就要进行告警 25 | */ 26 | private int warnThreshold; 27 | /** 28 | * 子处理器的个数 29 | */ 30 | private int processorSize; 31 | 32 | /** 33 | * 不指定线程池的时候,指定初始化默认创建的线程池的大小 34 | */ 35 | private int corePoolSize; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/config/GoPushNodeServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/11 下午11:02 10 | */ 11 | @Data 12 | @Configuration 13 | @ConfigurationProperties(prefix = "go-push.node-server") 14 | public class GoPushNodeServerConfig { 15 | private String name; 16 | private int nodePort; 17 | private int devicePort; 18 | } 19 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/config/ZookeeperConfig.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * @author 喝咖啡的囊地鼠 9 | * @date 2017/9/11 下午11:44 10 | */ 11 | @Data 12 | @Configuration 13 | @ConfigurationProperties(prefix = "go-push.zookeeper") 14 | public class ZookeeperConfig { 15 | 16 | private String servers; 17 | 18 | private String namespace; 19 | 20 | private String listenNamespace; 21 | 22 | private int sessionTimeout; 23 | 24 | private int connectionTimeout; 25 | 26 | private int maxRetries; 27 | 28 | private int retriesSleepTime; 29 | } 30 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/DeviceServerBootstrap.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices; 2 | 3 | import com.gopush.nodeserver.config.GoPushNodeServerConfig; 4 | import com.gopush.nodeserver.devices.inbound.DeviceChannelInboundHandler; 5 | import io.netty.bootstrap.ServerBootstrap; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.channel.EventLoopGroup; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.SocketChannel; 12 | import io.netty.channel.socket.nio.NioServerSocketChannel; 13 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 14 | import io.netty.handler.codec.LengthFieldPrepender; 15 | import io.netty.handler.codec.string.StringDecoder; 16 | import io.netty.handler.codec.string.StringEncoder; 17 | import io.netty.handler.logging.LoggingHandler; 18 | import io.netty.handler.timeout.IdleStateHandler; 19 | import io.netty.util.CharsetUtil; 20 | import lombok.extern.slf4j.Slf4j; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.stereotype.Component; 23 | 24 | import javax.annotation.PostConstruct; 25 | import javax.annotation.PreDestroy; 26 | 27 | /** 28 | * go-push 29 | * 30 | * @类功能说明:设备服务启动器 31 | * @作者:喝咖啡的囊地鼠 32 | * @创建时间:2017/6/18 下午10:59 33 | * @VERSION: 34 | */ 35 | 36 | @Slf4j 37 | @Component 38 | public class DeviceServerBootstrap { 39 | 40 | private EventLoopGroup bossGroup = new NioEventLoopGroup(); 41 | private EventLoopGroup workGroup = new NioEventLoopGroup(); 42 | 43 | @Autowired 44 | private GoPushNodeServerConfig goPushNodeServerConfig; 45 | 46 | @Autowired 47 | private DeviceChannelInboundHandler deviceChannelInboundHandler; 48 | 49 | @PostConstruct 50 | public void start() throws Exception { 51 | 52 | 53 | ServerBootstrap bootstrap = new ServerBootstrap(); 54 | bootstrap.group(bossGroup, workGroup) 55 | .channelFactory(NioServerSocketChannel::new) 56 | .childHandler(new ChannelInitializer() { 57 | @Override 58 | protected void initChannel(SocketChannel socketChannel) throws Exception { 59 | 60 | ChannelPipeline pipeline = socketChannel.pipeline(); 61 | pipeline.addLast("logHandler", new LoggingHandler()); 62 | pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); 63 | pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8)); 64 | pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); 65 | pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8)); 66 | pipeline.addLast("idleStateHandler", new IdleStateHandler(300, 0, 0)); 67 | 68 | pipeline.addLast("handler", deviceChannelInboundHandler); 69 | } 70 | }) 71 | 72 | .option(ChannelOption.SO_BACKLOG, 1000000) //连接队列深度 73 | .option(ChannelOption.TCP_NODELAY, true) //设置 no_delay 74 | .option(ChannelOption.SO_SNDBUF, 2048).option(ChannelOption.SO_RCVBUF, 1024) 75 | .childOption(ChannelOption.TCP_NODELAY, true) 76 | .childOption(ChannelOption.SO_REUSEADDR, true) 77 | .childOption(ChannelOption.SO_SNDBUF, 2048).childOption(ChannelOption.SO_RCVBUF, 1024) 78 | .childOption(ChannelOption.SO_LINGER, 0); 79 | 80 | bootstrap.bind(goPushNodeServerConfig.getDevicePort()).sync(); 81 | log.info("device server start successful! listening port: {}", goPushNodeServerConfig.getDevicePort()); 82 | } 83 | 84 | 85 | @PreDestroy 86 | public void destory() { 87 | bossGroup.shutdownGracefully(); 88 | workGroup.shutdownGracefully(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/DeviceDeviceDisconnectHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.common.constants.RedisKeyEnum; 5 | import com.gopush.common.utils.ip.IpUtils; 6 | import com.gopush.devices.handlers.IDeviceDisconnectHandler; 7 | import com.gopush.nodeserver.devices.BatchProcessor; 8 | import com.gopush.nodeserver.devices.stores.IDeviceChannelStore; 9 | import com.gopush.nodeserver.nodes.senders.INodeSender; 10 | import com.gopush.protocol.node.DeviceDisconReq; 11 | import io.netty.channel.Channel; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.apache.commons.collections.CollectionUtils; 14 | import org.apache.commons.lang3.StringUtils; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.data.redis.core.RedisTemplate; 17 | import org.springframework.stereotype.Component; 18 | 19 | import java.util.List; 20 | 21 | /** 22 | * go-push 23 | * 24 | * @类功能说明: 批处理设备断连接后需要触发上报 25 | * @作者:喝咖啡的囊地鼠 26 | * @创建时间:2017/6/19 上午12:25 27 | * @VERSION: 28 | */ 29 | 30 | @Slf4j 31 | @Component 32 | public class DeviceDeviceDisconnectHandler extends BatchProcessor implements IDeviceDisconnectHandler { 33 | 34 | @Autowired 35 | private RedisTemplate redisTemplate; 36 | 37 | @Autowired 38 | private IDeviceChannelStore deviceChannelStore; 39 | 40 | @Autowired 41 | private INodeSender nodeSender; 42 | 43 | 44 | @Override 45 | public void channelClosed(Channel channel) { 46 | String device = (String) channel.attr(Constants.CHANNEL_ATTR_DEVICE).get(); 47 | if (StringUtils.isNotEmpty(device)) { 48 | //移除设备-channel 映射 49 | deviceChannelStore.removeChannel(device, channel); 50 | putMsg(new Object[]{device, channel.hashCode()}); 51 | } 52 | log.info("channel closed , channel:{}, device:{}", channel, device); 53 | } 54 | 55 | @Override 56 | protected String getBatchExecutorName() { 57 | return "DeviceDisconnect-BatchExecutor"; 58 | } 59 | 60 | @Override 61 | protected boolean retryFailure() { 62 | return false; 63 | } 64 | 65 | @Override 66 | protected void batchHandler(List batchReq) throws Exception { 67 | 68 | // 因为异步,要求 channel id 一样才能移除,防止 异步时间差删除了新建的Channel 69 | if (CollectionUtils.isNotEmpty(batchReq)) { 70 | String nodeIp = IpUtils.intranetIp(); 71 | DeviceDisconReq req = DeviceDisconReq.builder().node(nodeIp).build(); 72 | final boolean[] flag = {Boolean.FALSE}; 73 | batchReq.stream().forEach((ele) -> { 74 | String device = (String) ele[0]; 75 | int channelHashCode = (int) ele[1]; 76 | 77 | String channel = (String) redisTemplate.opsForHash().get( 78 | RedisKeyEnum.DEVICE_KEY.getValue() + device, 79 | RedisKeyEnum.DEVICE_CHANNEL_FIELD.getValue()); 80 | if (channel != null && Integer.parseInt(channel) == channelHashCode) { 81 | if (!flag[0]) { 82 | flag[0] = Boolean.TRUE; 83 | } 84 | req.addDevice(device); 85 | redisTemplate.opsForHash().delete(RedisKeyEnum.DEVICE_KEY.getValue() + device, RedisKeyEnum.DEVICE_CHANNEL_FIELD.getValue()); 86 | redisTemplate.opsForHash().delete(RedisKeyEnum.DEVICE_KEY.getValue() + device, RedisKeyEnum.DEVICE_NODE_FIELD.getValue()); 87 | } 88 | }); 89 | 90 | if (flag[0]) { 91 | nodeSender.sendShuffle(req); 92 | } 93 | 94 | } 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/DeviceDeviceDockedHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.constants.RedisKeyEnum; 4 | import com.gopush.common.utils.ip.IpUtils; 5 | import com.gopush.devices.handlers.IDeviceDockedHandler; 6 | import com.gopush.nodeserver.devices.BatchProcessor; 7 | import com.gopush.nodeserver.nodes.senders.INodeSender; 8 | import com.gopush.protocol.node.DeviceDockedReq; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.collections.CollectionUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.data.redis.core.RedisTemplate; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.util.Arrays; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | /** 21 | * go-push 22 | * 23 | * @类功能说明: 24 | * @作者:喝咖啡的囊地鼠 25 | * @创建时间:2017/6/19 上午12:58 26 | * @VERSION: 27 | */ 28 | 29 | @Slf4j 30 | @Component 31 | public class DeviceDeviceDockedHandler extends BatchProcessor implements IDeviceDockedHandler { 32 | 33 | 34 | @Autowired 35 | private INodeSender nodeSender; 36 | 37 | @Autowired 38 | private RedisTemplate redisTemplate; 39 | 40 | @Override 41 | public void upReport(String device, int channelHashCode, int[] idles) { 42 | putMsg(new Object[]{device, channelHashCode, idles}); 43 | log.info("up report device docked, device:{}, channelHashCode:{}, idles:{}", device, channelHashCode, Arrays.toString(idles)); 44 | } 45 | 46 | @Override 47 | protected String getBatchExecutorName() { 48 | return "DeviceDocked-BatchExecutor"; 49 | } 50 | 51 | @Override 52 | protected boolean retryFailure() { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected void batchHandler(List batchReq) throws Exception { 58 | //添加缓存 设备-节点-channel 绑定 59 | if (CollectionUtils.isNotEmpty(batchReq)) { 60 | String nodeIp = IpUtils.intranetIp(); 61 | DeviceDockedReq req = DeviceDockedReq.builder().node(nodeIp).build(); 62 | batchReq.stream().forEach((ele) -> { 63 | req.addDevice((String) ele[0]); 64 | Map hash = new HashMap<>(); 65 | hash.put(RedisKeyEnum.DEVICE_CHANNEL_FIELD.getValue(), String.valueOf(ele[1])); 66 | hash.put(RedisKeyEnum.DEVICE_NODE_FIELD.getValue(), nodeIp); 67 | int[] idles = (int[]) ele[2]; 68 | redisTemplate.opsForHash().put(RedisKeyEnum.DEVICE_KEY.getValue() + ele[0], hash, idles[0]); 69 | }); 70 | //将需要上报的device 加到list 构造上报请求 使用 nodeSender 发送出去 71 | nodeSender.sendShuffle(req); 72 | } 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/DevicePingHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.devices.handlers.IDeviceMessageHandler; 5 | import com.gopush.protocol.device.DeviceMessage; 6 | import com.gopush.protocol.device.Ping; 7 | import com.gopush.protocol.device.Pong; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * go-push 17 | * 18 | * @类功能说明:PING请求批处理器 19 | * @作者:喝咖啡的囊地鼠 20 | * @创建时间:2017/6/12 下午10:03 21 | * @VERSION: 22 | */ 23 | 24 | @Slf4j 25 | @Component 26 | public class DevicePingHandler extends PingPongProcessor implements IDeviceMessageHandler { 27 | 28 | 29 | //响应 30 | private static final String PONG = Pong.builder().build().encode(); 31 | 32 | 33 | @Override 34 | public boolean support(DeviceMessage message) { 35 | return message instanceof Ping; 36 | } 37 | 38 | @Override 39 | public void call(ChannelHandlerContext context, Ping message) { 40 | 41 | Channel channel = context.channel(); 42 | if (!checkHandShake(channel)) { 43 | context.close(); 44 | return; 45 | } 46 | channel.writeAndFlush(PONG); 47 | putMsg(new Object[]{ 48 | channel.attr(Constants.CHANNEL_ATTR_DEVICE).get(), 49 | channel.attr(Constants.CHANNEL_ATTR_IDLE).get()}); 50 | 51 | log.debug("receive ping, channel:{}, device:{}", channel, channel.attr(Constants.CHANNEL_ATTR_DEVICE).get()); 52 | } 53 | 54 | 55 | @Override 56 | protected String getBatchExecutorName() { 57 | return "Ping-BatchExecutor"; 58 | } 59 | 60 | @Override 61 | protected boolean retryFailure() { 62 | return false; 63 | } 64 | 65 | 66 | /** 67 | * 设置设备在线的过期时间 68 | * 69 | * @param batchReq 70 | * @throws Exception 71 | */ 72 | @Override 73 | protected void batchHandler(List batchReq) throws Exception { 74 | //收到设备发送过来的 PING 请求 75 | liveHandShake(batchReq); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/DevicePongHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.devices.handlers.IDeviceMessageHandler; 5 | import com.gopush.protocol.device.DeviceMessage; 6 | import com.gopush.protocol.device.Pong; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * go-push 16 | * 17 | * @类功能说明:PONG请求批处理器 18 | * @作者:喝咖啡的囊地鼠 19 | * @创建时间:2017/6/12 下午10:03 20 | * @VERSION: 21 | */ 22 | 23 | @Slf4j 24 | @Component 25 | public class DevicePongHandler extends PingPongProcessor implements IDeviceMessageHandler { 26 | 27 | @Override 28 | public boolean support(DeviceMessage message) { 29 | return message instanceof Pong; 30 | } 31 | 32 | @Override 33 | public void call(ChannelHandlerContext context, Pong message) { 34 | 35 | Channel channel = context.channel(); 36 | if (!checkHandShake(channel)) { 37 | context.close(); 38 | return; 39 | } 40 | putMsg(new Object[]{ 41 | channel.attr(Constants.CHANNEL_ATTR_DEVICE).get(), 42 | channel.attr(Constants.CHANNEL_ATTR_IDLE).get()}); 43 | log.debug("receive pong, channel:{}, device:{}", channel, channel.attr(Constants.CHANNEL_ATTR_DEVICE).get()); 44 | 45 | } 46 | 47 | @Override 48 | protected String getBatchExecutorName() { 49 | return "Pong-BatchExecutor"; 50 | } 51 | 52 | @Override 53 | protected boolean retryFailure() { 54 | return false; 55 | } 56 | 57 | @Override 58 | protected void batchHandler(List batchReq) throws Exception { 59 | 60 | //发出去的PING请求的响应 61 | //也可以设置 保活设置 62 | liveHandShake(batchReq); 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/HandShakeHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.common.constants.HandshakeEnum; 5 | import com.gopush.common.constants.IdleEnum; 6 | import com.gopush.common.constants.RedisKeyEnum; 7 | import com.gopush.devices.handlers.IDeviceDockedHandler; 8 | import com.gopush.devices.handlers.IDeviceMessageHandler; 9 | import com.gopush.nodeserver.devices.BatchProcessor; 10 | import com.gopush.nodeserver.devices.stores.IDeviceChannelStore; 11 | import com.gopush.protocol.device.DeviceMessage; 12 | import com.gopush.protocol.device.HandShakeReq; 13 | import com.gopush.protocol.device.HandShakeResp; 14 | import io.netty.channel.Channel; 15 | import io.netty.channel.ChannelFutureListener; 16 | import io.netty.channel.ChannelHandlerContext; 17 | import io.netty.handler.timeout.IdleStateHandler; 18 | import lombok.extern.slf4j.Slf4j; 19 | import org.apache.commons.collections.CollectionUtils; 20 | import org.apache.commons.lang3.StringUtils; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.data.redis.core.RedisTemplate; 23 | import org.springframework.stereotype.Component; 24 | 25 | import java.util.List; 26 | import java.util.concurrent.TimeUnit; 27 | 28 | /** 29 | * go-push 30 | * 31 | * @类功能说明:握手请求批处理器 32 | * @作者:喝咖啡的囊地鼠 33 | * @创建时间:2017/6/12 下午10:03 34 | * @VERSION: 35 | */ 36 | 37 | @Slf4j 38 | @Component 39 | public class HandShakeHandler extends BatchProcessor implements IDeviceMessageHandler { 40 | 41 | 42 | @Autowired 43 | private RedisTemplate redisTemplate; 44 | 45 | @Autowired 46 | private IDeviceDockedHandler deviceDockedHandler; 47 | 48 | @Autowired 49 | private IDeviceChannelStore deviceChannelStore; 50 | 51 | @Override 52 | public boolean support(DeviceMessage message) { 53 | return message instanceof HandShakeReq; 54 | } 55 | 56 | @Override 57 | public void call(ChannelHandlerContext context, HandShakeReq message) { 58 | putMsg(new Object[]{context.channel(), message}); 59 | log.info("handshake request received, message:{}, channel:{}", message, context.channel()); 60 | } 61 | 62 | 63 | @Override 64 | protected String getBatchExecutorName() { 65 | return "HandShake-BatchExecutor"; 66 | } 67 | 68 | @Override 69 | protected boolean retryFailure() { 70 | return false; 71 | } 72 | 73 | 74 | //握手成功 75 | // public static final int HANDSAHKE_OK = 200; 76 | 77 | //非法设备 78 | // public static final int HANDSHAKE_INVALID_DEVICE = 300; 79 | 80 | //非法token 81 | // public static final int HANDSHAKE_INVALID_TOKEN = 301; 82 | 83 | @Override 84 | protected void batchHandler(List batchReq) throws Exception { 85 | if (CollectionUtils.isNotEmpty(batchReq)) { 86 | //先全部取出redis 中存储的要处理的设备的列表 87 | batchReq.stream().forEach((e) -> { 88 | 89 | try { 90 | Channel channel = (Channel) e[0]; 91 | HandShakeReq req = (HandShakeReq) e[1]; 92 | 93 | String devcieId = req.getDevice(); 94 | //建立 握手响应 95 | HandShakeResp.HandShakeRespBuilder respBuilder = 96 | HandShakeResp.builder(); 97 | if (StringUtils.isEmpty(req.getDevice())) { 98 | respBuilder.result(HandshakeEnum.HANDSHAKE_INVALID_DEVICE.getKey()); 99 | } else { 100 | String token = (String) redisTemplate.opsForHash().get( 101 | RedisKeyEnum.DEVICE_KEY.getValue() + devcieId, 102 | RedisKeyEnum.DEIVCE_TOKEN_FIELD.getValue()); 103 | //所有的token 都不为空 且 两个token相等 104 | if (StringUtils.isAnyEmpty(token, req.getToken()) || !StringUtils.equals(req.getToken(), token)) { 105 | respBuilder.result(HandshakeEnum.HANDSHAKE_INVALID_TOKEN.getKey()); 106 | } else { 107 | respBuilder.result(HandshakeEnum.HANDSAHKE_OK.getKey()); 108 | } 109 | } 110 | HandShakeResp resp = respBuilder.build(); 111 | 112 | String respEncode = resp.encode(); 113 | //握手不成功 114 | 115 | if (resp.getResult() != HandshakeEnum.HANDSAHKE_OK.getKey()) { 116 | //将写出握手响应后关闭链接 117 | channel.writeAndFlush(respEncode).addListener(ChannelFutureListener.CLOSE); 118 | log.info("handshake fail, channel:{}, device:{}, response:{}", channel, req.getDevice(), respEncode); 119 | } else { 120 | 121 | 122 | //将已经存在的链接关闭 123 | Channel exist = deviceChannelStore.getChannel(devcieId); 124 | if (exist != null) { 125 | log.warn("exist channel - device in cache, channel:{},device:{}", exist, devcieId); 126 | exist.close(); 127 | } 128 | 129 | 130 | //将握手结果, 设备信息 绑定到 通道属性里面 131 | Integer[] idles = new Integer[]{ 132 | req.getReadInterval() + IdleEnum.READ_IDLE.getValue(), 133 | req.getWriteInterval() + IdleEnum.WRITE_IDLE.getValue(), 134 | req.getAllInterval() + IdleEnum.ALL_IDLE.getValue() 135 | }; 136 | channel.attr(Constants.CHANNEL_ATTR_IDLE).set(idles); 137 | channel.attr(Constants.CHANNEL_ATTR_DEVICE).set(devcieId); 138 | channel.attr(Constants.CHANNEL_ATTR_HANDSHAKE).set(Boolean.TRUE); 139 | 140 | //重设读写超时器 141 | channel.pipeline().replace("idleStateHandler", "idleStateHandler", new IdleStateHandler(idles[0], idles[1], idles[2], TimeUnit.SECONDS)); 142 | 143 | //添加本地 设备-channel 绑定 144 | deviceChannelStore.addChannel(devcieId, channel); 145 | 146 | //报告设备上线 147 | deviceDockedHandler.upReport(devcieId, channel.hashCode(), new int[]{idles[0], idles[1], idles[2]}); 148 | 149 | //写出握手响应 150 | channel.writeAndFlush(respEncode); 151 | log.info("handshake successful, channel:{}, device:{}, message:{}", channel, req.getDevice(), respEncode); 152 | 153 | 154 | } 155 | } catch (Exception ex) { 156 | log.error("handshake error:{}", ex); 157 | } 158 | 159 | }); 160 | 161 | } 162 | 163 | } 164 | 165 | 166 | } 167 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/PingPongProcessor.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.common.constants.RedisKeyEnum; 5 | import com.gopush.nodeserver.devices.BatchProcessor; 6 | import io.netty.channel.Channel; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.apache.commons.collections.CollectionUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.List; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * go-push 18 | * 19 | * @类功能说明: 20 | * @作者:喝咖啡的囊地鼠 21 | * @创建时间:2017/6/22 上午1:28 22 | * @VERSION: 23 | */ 24 | @Slf4j 25 | @Component 26 | public abstract class PingPongProcessor extends BatchProcessor { 27 | 28 | 29 | @Autowired 30 | private RedisTemplate redisTemplate; 31 | 32 | /** 33 | * 检测是否已经握手 34 | * 35 | * @param channel 36 | * @return 37 | */ 38 | protected boolean checkHandShake(Channel channel) { 39 | if (!channel.hasAttr(Constants.CHANNEL_ATTR_HANDSHAKE)) { 40 | log.warn("channel not handshake, channel:{}", channel); 41 | return Boolean.FALSE; 42 | } 43 | return Boolean.TRUE; 44 | } 45 | 46 | 47 | protected void liveHandShake(List batchReq) { 48 | if (CollectionUtils.isNotEmpty(batchReq)) { 49 | 50 | batchReq.stream().forEach((ele) -> { 51 | String device = (String) ele[0]; 52 | int[] idles = (int[]) ele[1]; 53 | redisTemplate.expire(RedisKeyEnum.DEVICE_KEY.getValue() + device, idles[0], TimeUnit.SECONDS); 54 | }); 55 | 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/handlers/PushRespHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.devices.handlers.IDeviceMessageHandler; 5 | import com.gopush.nodeserver.devices.BatchProcessor; 6 | import com.gopush.protocol.device.DeviceMessage; 7 | import com.gopush.protocol.device.PushResp; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.List; 14 | 15 | 16 | /** 17 | * go-push 18 | * 19 | * @类功能说明:推送消息后的响应批处理器 20 | * @作者:喝咖啡的囊地鼠 21 | * @创建时间:2017/6/12 下午10:08 22 | * @VERSION: 23 | */ 24 | 25 | @Slf4j 26 | @Component 27 | public class PushRespHandler extends BatchProcessor implements IDeviceMessageHandler { 28 | @Override 29 | public boolean support(DeviceMessage message) { 30 | return message instanceof PushResp; 31 | } 32 | 33 | @Override 34 | public void call(ChannelHandlerContext context, PushResp message) { 35 | Channel channel = context.channel(); 36 | if (!channel.hasAttr(Constants.CHANNEL_ATTR_HANDSHAKE)) { 37 | log.warn("channel not handshake, channel:{}", channel); 38 | context.close(); 39 | return; 40 | } 41 | //接收成功后,将推送的消息置换成已读或删除等操作 42 | if (PushResp.Result.S.equals(message.getResult()) || PushResp.Result.D.equals(message.getResult())) { 43 | putMsg(message); 44 | log.info("receive pushResp, device:{}, msg_id:{}, result:{}!", message.getDevice(), message.getMsgId(), message.getResult()); 45 | } else { 46 | log.warn("receive pushResp, device:{}, msg_id:{}, result:{}", message.getDevice(), message.getMsgId(), message.getResult()); 47 | } 48 | 49 | } 50 | 51 | 52 | @Override 53 | protected String getBatchExecutorName() { 54 | return "Resp-Push-BatchExecutor"; 55 | } 56 | 57 | @Override 58 | protected boolean retryFailure() { 59 | return true; 60 | } 61 | 62 | @Override 63 | protected void batchHandler(List batchReq) throws Exception { 64 | // TODO: 2017/6/18 处理推送的消息的结果 65 | // 将消息从待发送移除 66 | // 更新消息已经被投递的数量 67 | // 将该消息置成已发送 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/inbound/DeviceChannelInboundHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.inbound; 2 | 3 | import com.gopush.devices.handlers.IDeviceMessageHandler; 4 | import com.gopush.nodeserver.devices.handlers.DeviceDeviceDisconnectHandler; 5 | import com.gopush.protocol.device.DeviceMessage; 6 | import com.gopush.protocol.device.Ping; 7 | import io.netty.channel.ChannelHandler; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.SimpleChannelInboundHandler; 10 | import io.netty.handler.timeout.IdleState; 11 | import io.netty.handler.timeout.IdleStateEvent; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.util.List; 17 | 18 | 19 | /** 20 | * go-push 21 | * 22 | * @类功能说明: 23 | * @作者:喝咖啡的囊地鼠 24 | * @创建时间:2017/6/20 上午12:46 25 | * @VERSION: 26 | */ 27 | 28 | @Slf4j 29 | @ChannelHandler.Sharable 30 | @Component 31 | public class DeviceChannelInboundHandler extends SimpleChannelInboundHandler { 32 | 33 | 34 | private static final String PING = Ping.builder().build().encode(); 35 | 36 | @Autowired 37 | private DeviceDeviceDisconnectHandler deviceDisconnectHandler; 38 | 39 | @Autowired 40 | private List deviceMessageHandlers; 41 | 42 | @Override 43 | protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception { 44 | 45 | log.debug("channel:{}, message:{}", ctx.channel(), message); 46 | DeviceMessage deviceMessage = DeviceMessage.decode(message); 47 | 48 | if (!deviceMessageHandlers.isEmpty()) { 49 | deviceMessageHandlers.stream().forEach((handler) -> { 50 | try { 51 | if (handler.support(deviceMessage)) { 52 | handler.call(ctx, deviceMessage); 53 | } 54 | } catch (Exception e) { 55 | log.error("exception error:{}", e); 56 | } 57 | }); 58 | } 59 | 60 | } 61 | 62 | @Override 63 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 64 | log.debug("channel active, channel:{}", ctx.channel()); 65 | } 66 | 67 | @Override 68 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 69 | log.debug("channel inactive, channel:{}", ctx.channel()); 70 | deviceDisconnectHandler.channelClosed(ctx.channel()); 71 | } 72 | 73 | @Override 74 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 75 | log.debug("exception error:{}, channel:{}", cause.getMessage(), ctx.channel()); 76 | ctx.close(); 77 | } 78 | 79 | 80 | @Override 81 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 82 | if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) { 83 | IdleStateEvent event = (IdleStateEvent) evt; 84 | if (event.state() == IdleState.READER_IDLE) { 85 | ctx.writeAndFlush(PING); 86 | } 87 | if (event.state() == IdleState.WRITER_IDLE) { 88 | ctx.writeAndFlush(PING); 89 | } 90 | if (event.state() == IdleState.ALL_IDLE) { 91 | ctx.writeAndFlush(PING); 92 | } 93 | } else { 94 | super.userEventTriggered(ctx, evt); 95 | } 96 | } 97 | 98 | 99 | } 100 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/senders/IPushSender.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.senders; 2 | 3 | 4 | import com.gopush.protocol.device.DeviceMessage; 5 | 6 | /** 7 | * go-push 8 | * 9 | * @类功能说明:推送消息给设备 10 | * @作者:喝咖啡的囊地鼠 11 | * @创建时间:2017/6/18 下午11:29 12 | * @VERSION: 13 | */ 14 | public interface IPushSender { 15 | 16 | /** 17 | * 发送消息给指定设备 18 | * 19 | * @param device 20 | * @param message 21 | */ 22 | void send(String device, T message); 23 | } 24 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/senders/PushSender.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.senders; 2 | 3 | import com.gopush.nodeserver.devices.stores.IDeviceChannelStore; 4 | import com.gopush.protocol.device.PushReq; 5 | import io.netty.channel.Channel; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * go-push 12 | * 13 | * @类功能说明: 14 | * @作者:喝咖啡的囊地鼠 15 | * @创建时间:2017/6/18 下午11:32 16 | * @VERSION: 17 | */ 18 | @Slf4j 19 | @Component 20 | public class PushSender implements IPushSender { 21 | 22 | 23 | @Autowired 24 | private IDeviceChannelStore deviceChannelStore; 25 | 26 | @Override 27 | public void send(String device, PushReq message) { 28 | 29 | Channel channel = deviceChannelStore.getChannel(device); 30 | if (channel == null) { 31 | log.warn("can not find channel, device :{}", device); 32 | //添加超时机制,将消息缓存 33 | return; 34 | } 35 | 36 | channel.writeAndFlush(message.encode()).addListener((channelFuture) -> { 37 | if (!channelFuture.isSuccess()) { 38 | log.error("send message error, device:{}, msg_id:{}, msg:{} ", device, message.getId(), message.getMsgs()); 39 | // TODO: 2017/6/19 这边可以做重试操作 40 | //并且记录错误次数 41 | 42 | } else { 43 | log.info("send message successful, device:{}, msg_id:{}, msg:{} ", device, message.getId(), message.getMsgs()); 44 | } 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/stores/DeviceChannelStore.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.stores; 2 | 3 | import io.netty.channel.Channel; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | 10 | /** 11 | * go-push 12 | * 13 | * @类功能说明:设备 - Channel 存储器 14 | * @作者:喝咖啡的囊地鼠 15 | * @创建时间:2017/6/18 下午11:42 16 | * @VERSION: 17 | */ 18 | 19 | @Slf4j 20 | @Component 21 | public class DeviceChannelStore implements IDeviceChannelStore { 22 | 23 | //计数器 24 | private AtomicInteger counter = new AtomicInteger(0); 25 | 26 | 27 | //设备-channel列表 28 | private ConcurrentHashMap deviceChannels = new ConcurrentHashMap<>(); 29 | 30 | @Override 31 | public Channel getChannel(String device) { 32 | return deviceChannels.get(device); 33 | } 34 | 35 | @Override 36 | public void removeChannel(String device) { 37 | deviceChannels.remove(device); 38 | int count = counter.decrementAndGet(); 39 | if (count < 0) { 40 | counter.set(0); 41 | } 42 | } 43 | 44 | @Override 45 | public void removeChannel(String device, Channel channel) { 46 | if (channel.equals(deviceChannels.get(device))) { 47 | removeChannel(device); 48 | } 49 | } 50 | 51 | @Override 52 | public void clear() { 53 | deviceChannels.clear(); 54 | counter.set(0); 55 | } 56 | 57 | @Override 58 | public void addChannel(String device, Channel channel) { 59 | deviceChannels.put(device, channel); 60 | counter.incrementAndGet(); 61 | } 62 | 63 | @Override 64 | public int count() { 65 | return counter.get(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/devices/stores/IDeviceChannelStore.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.devices.stores; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | /** 6 | * go-push 7 | * 8 | * @类功能说明:设备-Channel 存储器 9 | * @作者:喝咖啡的囊地鼠 10 | * @创建时间:2017/6/18 下午11:35 11 | * @VERSION: 12 | */ 13 | public interface IDeviceChannelStore { 14 | 15 | /** 16 | * 根据设备ID获取Channel 17 | * 18 | * @param device 19 | * @return 20 | */ 21 | Channel getChannel(String device); 22 | 23 | /** 24 | * 根据设备ID删除 channel 25 | * 26 | * @param device 27 | */ 28 | void removeChannel(String device); 29 | 30 | /** 31 | * 根据设备ID移除channel,对比 channel存不存在 32 | * 33 | * @param device 34 | * @param channel 35 | */ 36 | void removeChannel(String device, Channel channel); 37 | 38 | 39 | /** 40 | * 清空channel 41 | */ 42 | void clear(); 43 | 44 | /** 45 | * 添加设备-channel 46 | * 47 | * @param device 48 | * @param channel 49 | */ 50 | void addChannel(String device, Channel channel); 51 | 52 | 53 | /** 54 | * 设备-channel 计数 55 | * 56 | * @return 57 | */ 58 | int count(); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/dymic/discovery/DataCenterDiscoveryService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.dymic.discovery; 2 | 3 | import com.gopush.common.utils.zk.ZkUtils; 4 | import com.gopush.common.utils.zk.listener.ZkStateListener; 5 | import com.gopush.nodeserver.config.GoPushNodeServerConfig; 6 | import com.gopush.nodeserver.config.ZookeeperConfig; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.apache.curator.framework.CuratorFramework; 9 | import org.apache.curator.framework.state.ConnectionState; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.annotation.PostConstruct; 14 | import javax.annotation.PreDestroy; 15 | 16 | /** 17 | * @author 喝咖啡的囊地鼠 18 | * @date 2017/9/12 上午3:13 19 | */ 20 | 21 | @Slf4j 22 | @Component 23 | public class DataCenterDiscoveryService { 24 | 25 | @Autowired 26 | private ZookeeperConfig zookeeperConfig; 27 | 28 | @Autowired 29 | private GoPushNodeServerConfig goPushNodeServerConfig; 30 | 31 | private ZkUtils zkUtils; 32 | 33 | @PostConstruct 34 | public void init() { 35 | zkUtils = new ZkUtils(); 36 | zkUtils.init( 37 | zookeeperConfig.getServers(), 38 | zookeeperConfig.getConnectionTimeout(), 39 | zookeeperConfig.getSessionTimeout(), 40 | zookeeperConfig.getMaxRetries(), 41 | zookeeperConfig.getRetriesSleepTime(), 42 | zookeeperConfig.getListenNamespace(), 43 | new ZkStateListener() { 44 | @Override 45 | public void connectedEvent(CuratorFramework curator, ConnectionState state) { 46 | log.info("DataCenterDiscovery 链接zk成功"); 47 | } 48 | 49 | @Override 50 | public void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 51 | log.info("DataCenterDiscovery 重新链接zk成功"); 52 | } 53 | 54 | @Override 55 | public void lostEvent(CuratorFramework curator, ConnectionState state) { 56 | log.info("DataCenterDiscovery 链接zk丢失"); 57 | } 58 | }); 59 | 60 | } 61 | 62 | @PreDestroy 63 | public void destory() { 64 | zkUtils.destory(); 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/dymic/register/NodeServerRegisterService.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.dymic.register; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.gopush.common.constants.ZkGroupEnum; 5 | import com.gopush.common.utils.zk.ZkUtils; 6 | import com.gopush.common.utils.zk.listener.ZkStateListener; 7 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 8 | import com.gopush.nodeserver.config.GoPushNodeServerConfig; 9 | import com.gopush.nodeserver.config.ZookeeperConfig; 10 | import com.gopush.nodeserver.infos.watchdog.NodeServerInfoWatchdog; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.curator.framework.CuratorFramework; 13 | import org.apache.curator.framework.state.ConnectionState; 14 | import org.apache.curator.utils.ZKPaths; 15 | import org.apache.zookeeper.CreateMode; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Component; 18 | 19 | import javax.annotation.PostConstruct; 20 | import javax.annotation.PreDestroy; 21 | 22 | /** 23 | * @author 喝咖啡的囊地鼠 24 | * @date 2017/9/10 下午10:42 25 | */ 26 | @Slf4j 27 | @Component 28 | public class NodeServerRegisterService { 29 | 30 | @Autowired 31 | private ZookeeperConfig zookeeperConfig; 32 | 33 | @Autowired 34 | private GoPushNodeServerConfig goPushNodeServerConfig; 35 | 36 | @Autowired 37 | private NodeServerInfoWatchdog watchdog; 38 | 39 | private ZkUtils zkUtils; 40 | 41 | @PostConstruct 42 | public void init() { 43 | zkUtils = new ZkUtils(); 44 | zkUtils.init( 45 | zookeeperConfig.getServers(), 46 | zookeeperConfig.getConnectionTimeout(), 47 | zookeeperConfig.getSessionTimeout(), 48 | zookeeperConfig.getMaxRetries(), 49 | zookeeperConfig.getRetriesSleepTime(), 50 | zookeeperConfig.getNamespace(), 51 | new ZkStateListener() { 52 | @Override 53 | public void connectedEvent(CuratorFramework curator, ConnectionState state) { 54 | log.info("NodeServerRegister 链接zk成功"); 55 | registerNodeServer(); 56 | 57 | } 58 | 59 | @Override 60 | public void reconnectedEvent(CuratorFramework curator, ConnectionState state) { 61 | log.info("NodeServerRegister 重新链接zk成功"); 62 | registerNodeServer(); 63 | } 64 | 65 | @Override 66 | public void lostEvent(CuratorFramework curator, ConnectionState state) { 67 | log.info("NodeServerRegister 链接zk丢失"); 68 | 69 | } 70 | }); 71 | 72 | 73 | } 74 | 75 | @PreDestroy 76 | public void destory() { 77 | zkUtils.destory(); 78 | } 79 | 80 | 81 | /** 82 | * 提交最新的数据 83 | * 84 | * @param data 85 | */ 86 | public void postNewData(NodeServerInfo data) { 87 | zkUtils.setNodeData( 88 | ZKPaths.makePath(ZkGroupEnum.NODE_SERVER.getValue(), goPushNodeServerConfig.getName()), 89 | JSON.toJSONString(data)); 90 | } 91 | 92 | /** 93 | * 注册node-server服务 94 | */ 95 | private void registerNodeServer() { 96 | 97 | if (!zkUtils.checkExists(ZkGroupEnum.NODE_SERVER.getValue())) { 98 | boolean flag; 99 | do { 100 | flag = zkUtils.createNode(ZkGroupEnum.NODE_SERVER.getValue(), null, CreateMode.PERSISTENT); 101 | } while (!flag); 102 | } 103 | registerNodeInfo(); 104 | } 105 | 106 | private void registerNodeInfo() { 107 | zkUtils.createNode( 108 | ZKPaths.makePath(ZkGroupEnum.NODE_SERVER.getValue(), goPushNodeServerConfig.getName()), 109 | JSON.toJSONString(watchdog.watch()), 110 | CreateMode.EPHEMERAL); 111 | } 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/infos/watchdog/NodeServerInfoWatchdog.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.infos.watchdog; 2 | 3 | import com.gopush.common.utils.ip.IpUtils; 4 | import com.gopush.infos.nodeserver.bo.NodeLoaderInfo; 5 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 6 | import com.gopush.nodeserver.config.GoPushNodeServerConfig; 7 | import com.gopush.nodeserver.devices.BatchProcessor; 8 | import com.gopush.nodeserver.devices.stores.IDeviceChannelStore; 9 | import com.gopush.nodeserver.infos.watchdog.listener.event.NodeServerInfoEvent; 10 | import com.gopush.nodeserver.nodes.senders.INodeSender; 11 | import com.gopush.nodeserver.nodes.stores.IDataCenterChannelStore; 12 | import com.gopush.protocol.node.NodeInfoReq; 13 | import lombok.Setter; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.context.ApplicationEventPublisher; 18 | import org.springframework.stereotype.Component; 19 | import org.springframework.util.CollectionUtils; 20 | import org.springframework.util.StringUtils; 21 | 22 | import javax.annotation.PostConstruct; 23 | import java.util.List; 24 | import java.util.concurrent.ScheduledExecutorService; 25 | import java.util.concurrent.ScheduledThreadPoolExecutor; 26 | import java.util.concurrent.TimeUnit; 27 | import java.util.stream.Collectors; 28 | 29 | /** 30 | * @author 喝咖啡的囊地鼠 31 | * @date 2017/9/10 下午2:16 32 | */ 33 | @Slf4j 34 | @Component 35 | public class NodeServerInfoWatchdog { 36 | 37 | @Autowired 38 | private GoPushNodeServerConfig goPushNodeServerConfig; 39 | 40 | @Autowired 41 | private INodeSender nodeSender; 42 | 43 | @Autowired 44 | private IDeviceChannelStore deviceChannelStore; 45 | 46 | @Autowired 47 | private IDataCenterChannelStore dataCenterChannelStore; 48 | 49 | @Autowired 50 | private List deviceMessageHandlers; 51 | 52 | @Autowired 53 | private ApplicationEventPublisher applicationEventPublisher; 54 | 55 | @Setter 56 | private int delay = 5000; 57 | 58 | private ScheduledExecutorService scheduledExecutorService; 59 | 60 | @PostConstruct 61 | public void init() { 62 | 63 | scheduledExecutorService = new ScheduledThreadPoolExecutor(1, 64 | new BasicThreadFactory.Builder().namingPattern("SendNodeServerInfo-schedule-pool-%d").daemon(true).build()); 65 | scheduledExecutorService.scheduleAtFixedRate(() -> 66 | { 67 | //将负载加载到ZK中 68 | if (!CollectionUtils.isEmpty(dataCenterChannelStore.getAllChannels())) { 69 | dataCenterChannelStore.getAllChannels().stream().forEach(e -> { 70 | log.info("channel id:{}, {}", e.id(), e); 71 | }); 72 | } 73 | applicationEventPublisher.publishEvent( 74 | NodeServerInfoEvent.builder() 75 | .name(goPushNodeServerConfig.getName()) 76 | .nodeServerInfo(watch()) 77 | .build()); 78 | // 写入zk 其实不需要发送 NodeInfoReq 79 | nodeSender.send(NodeInfoReq.builder().build()); 80 | } 81 | , delay, delay, TimeUnit.MILLISECONDS); 82 | 83 | } 84 | 85 | 86 | /** 87 | * 获取系统负载信息 88 | * 89 | * @return 90 | */ 91 | public NodeServerInfo watch() { 92 | String internetIp = IpUtils.internetIp(); 93 | String intranetIp = IpUtils.intranetIp(); 94 | 95 | return NodeServerInfo.builder() 96 | .name(goPushNodeServerConfig.getName()) 97 | .internetIp(StringUtils.isEmpty(internetIp) ? intranetIp : internetIp) 98 | .intranetIp(intranetIp) 99 | .devicePort(goPushNodeServerConfig.getDevicePort()) 100 | .nodePort(goPushNodeServerConfig.getNodePort()) 101 | .nodeLoaderInfo(NodeLoaderInfo.builder() 102 | .onlineDcCounter(dataCenterChannelStore.count()) 103 | .onlineDeviceCounter(deviceChannelStore.count()) 104 | .handlerInfos(deviceMessageHandlers.stream().map(BatchProcessor::getHandlerInfo).collect(Collectors.toList())) 105 | .build() 106 | ) 107 | .build(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/infos/watchdog/listener/PostNodeServerInfoDataListener.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.infos.watchdog.listener; 2 | 3 | import com.gopush.nodeserver.dymic.register.NodeServerRegisterService; 4 | import com.gopush.nodeserver.infos.watchdog.listener.event.NodeServerInfoEvent; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.event.EventListener; 8 | import org.springframework.scheduling.annotation.Async; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @author 喝咖啡的囊地鼠 13 | * @date 2017/9/12 上午12:39 14 | */ 15 | @Slf4j 16 | @Component 17 | public class PostNodeServerInfoDataListener { 18 | 19 | @Autowired 20 | private NodeServerRegisterService nodeServerRegisterService; 21 | 22 | @Async 23 | @EventListener(condition = "#event.nodeServerInfo != null") 24 | public void postDataToZk(NodeServerInfoEvent event) { 25 | nodeServerRegisterService.postNewData(event.getNodeServerInfo()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/infos/watchdog/listener/event/NodeServerInfoEvent.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.infos.watchdog.listener.event; 2 | 3 | import com.gopush.infos.nodeserver.bo.NodeServerInfo; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * @author 喝咖啡的囊地鼠 11 | * @date 2017/9/12 上午12:40 12 | */ 13 | @Data 14 | @Builder 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class NodeServerInfoEvent { 18 | private String name; 19 | private NodeServerInfo nodeServerInfo; 20 | } 21 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/NodeServerBootstrap.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes; 2 | 3 | import com.gopush.nodeserver.config.GoPushNodeServerConfig; 4 | import com.gopush.nodeserver.nodes.inbound.NodeChannelInBoundHandler; 5 | import io.netty.bootstrap.ServerBootstrap; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.channel.EventLoopGroup; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.SocketChannel; 12 | import io.netty.channel.socket.nio.NioServerSocketChannel; 13 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 14 | import io.netty.handler.codec.LengthFieldPrepender; 15 | import io.netty.handler.codec.string.StringDecoder; 16 | import io.netty.handler.codec.string.StringEncoder; 17 | import io.netty.handler.timeout.IdleStateHandler; 18 | import io.netty.util.CharsetUtil; 19 | import lombok.extern.slf4j.Slf4j; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.stereotype.Component; 22 | 23 | import javax.annotation.PostConstruct; 24 | import javax.annotation.PreDestroy; 25 | 26 | /** 27 | * go-push 28 | * 29 | * @类功能说明: 30 | * @作者:喝咖啡的囊地鼠 31 | * @创建时间:2017/6/20 下午9:08 32 | * @VERSION: 33 | */ 34 | 35 | @Slf4j 36 | @Component 37 | public class NodeServerBootstrap { 38 | 39 | private EventLoopGroup bossGroup = new NioEventLoopGroup(); 40 | private EventLoopGroup workGroup = new NioEventLoopGroup(); 41 | 42 | @Autowired 43 | private GoPushNodeServerConfig goPushNodeServerConfig; 44 | 45 | @Autowired 46 | private NodeChannelInBoundHandler nodeChannelInBoundHandler; 47 | 48 | @PostConstruct 49 | public void start() throws Exception { 50 | 51 | ServerBootstrap bootstrap = new ServerBootstrap(); 52 | bootstrap.group(bossGroup, workGroup) 53 | .channelFactory(NioServerSocketChannel::new) 54 | .childHandler(new ChannelInitializer() { 55 | @Override 56 | protected void initChannel(SocketChannel socketChannel) throws Exception { 57 | 58 | ChannelPipeline pipeline = socketChannel.pipeline(); 59 | pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); 60 | pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8)); 61 | pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); 62 | pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8)); 63 | pipeline.addLast("idleStateHandler", new IdleStateHandler(300, 0, 0)); 64 | pipeline.addLast("handler", nodeChannelInBoundHandler); 65 | } 66 | }) 67 | .option(ChannelOption.TCP_NODELAY, true) 68 | .childOption(ChannelOption.SO_REUSEADDR, true) 69 | .option(ChannelOption.SO_SNDBUF, 2048) 70 | .option(ChannelOption.SO_RCVBUF, 1024); 71 | bootstrap.bind(goPushNodeServerConfig.getNodePort()).sync(); 72 | log.info("Node server start successful! listening port: {}", goPushNodeServerConfig.getNodePort()); 73 | } 74 | 75 | 76 | @PreDestroy 77 | public void destory() { 78 | log.info("Node Server will be stoped!"); 79 | bossGroup.shutdownGracefully(); 80 | workGroup.shutdownGracefully(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/MessageToMultiDeviceHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.common.constants.NodeMessageEnum; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.nodeserver.devices.senders.IPushSender; 6 | import com.gopush.protocol.device.PushReq; 7 | import com.gopush.protocol.node.MessageToMultiDeviceReq; 8 | import com.gopush.protocol.node.MessageToMultiDeviceResp; 9 | import com.gopush.protocol.node.NodeMessage; 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.apache.commons.collections.CollectionUtils; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Component; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | 21 | /** 22 | * go-push 23 | * 24 | * @类功能说明: 25 | * @作者:喝咖啡的囊地鼠 26 | * @创建时间:2017/6/20 下午11:00 27 | * @VERSION: 28 | */ 29 | @Slf4j 30 | @Component 31 | public class MessageToMultiDeviceHandler implements INodeMessageHandler { 32 | 33 | @Autowired 34 | private IPushSender pushSender; 35 | 36 | @Override 37 | public boolean support(NodeMessage message) { 38 | return message instanceof MessageToMultiDeviceReq; 39 | } 40 | 41 | @Override 42 | public void call(ChannelHandlerContext ctx, MessageToMultiDeviceReq message) { 43 | //找寻到对应设备的channel 将消息全部推送给这个设备 44 | if (message != null) { 45 | if (CollectionUtils.isNotEmpty(message.getDevices())) { 46 | List devcies = message.getDevices(); 47 | devcies.stream().forEach((e) -> { 48 | List msgList = new ArrayList<>(); 49 | PushReq pushReq = PushReq.builder().msgs(msgList).build(); 50 | pushSender.send(e, pushReq); 51 | }); 52 | 53 | Channel channel = ctx.channel(); 54 | channel.writeAndFlush(MessageToMultiDeviceResp.builder().result(NodeMessageEnum.OK.getCode()).build().encode()); 55 | } 56 | } 57 | 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/MultiMessageToDeviceHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.common.constants.NodeMessageEnum; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.nodeserver.devices.senders.IPushSender; 6 | import com.gopush.protocol.device.PushReq; 7 | import com.gopush.protocol.node.MultiMessageToDeviceReq; 8 | import com.gopush.protocol.node.MultiMessageToDeviceResp; 9 | import com.gopush.protocol.node.NodeMessage; 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Component; 15 | 16 | 17 | /** 18 | * go-push 19 | * 20 | * @类功能说明: 21 | * @作者:喝咖啡的囊地鼠 22 | * @创建时间:2017/6/20 下午11:00 23 | * @VERSION: 24 | */ 25 | @Slf4j 26 | @Component 27 | public class MultiMessageToDeviceHandler implements INodeMessageHandler { 28 | 29 | @Autowired 30 | private IPushSender pushSender; 31 | 32 | @Override 33 | public boolean support(NodeMessage message) { 34 | return message instanceof MultiMessageToDeviceReq; 35 | } 36 | 37 | @Override 38 | public void call(ChannelHandlerContext ctx, MultiMessageToDeviceReq message) { 39 | //找寻到对应设备的channel 将消息全部推送给这个设备 40 | if (message != null) { 41 | pushSender.send(message.getDevice(), PushReq.builder().msgs(message.getMessages()).build()); 42 | Channel channel = ctx.channel(); 43 | channel.writeAndFlush(MultiMessageToDeviceResp.builder().result(NodeMessageEnum.OK.getCode()).build().encode()); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/NodeBaseHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.nodeserver.nodes.stores.IDataCenterChannelStore; 4 | import io.netty.channel.Channel; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明: 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/22 上午1:34 13 | * @VERSION: 14 | */ 15 | public abstract class NodeBaseHandler { 16 | 17 | 18 | @Autowired 19 | private IDataCenterChannelStore dataCenterChannelStore; 20 | 21 | protected void saveLiveDc(Channel channel) { 22 | dataCenterChannelStore.isDcChannelToSave(channel); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/NodeDeviceDisconnectHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.protocol.node.DeviceDisconResp; 6 | import com.gopush.protocol.node.NodeMessage; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明: 处理 data center 返回的 设备断连的响应 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/20 下午11:00 17 | * @VERSION: 18 | */ 19 | @Slf4j 20 | @Component 21 | public class NodeDeviceDisconnectHandler extends NodeBaseHandler implements INodeMessageHandler { 22 | @Override 23 | public boolean support(NodeMessage message) { 24 | return message instanceof DeviceDisconResp; 25 | } 26 | 27 | @Override 28 | public void call(ChannelHandlerContext ctx, DeviceDisconResp message) { 29 | saveLiveDc(ctx.channel()); 30 | log.info("receive DeviceDockedResp, channel:{}, node:{}", ctx.channel(), ctx.channel().attr(Constants.CHANNEL_ATTR_DATACENTER).get()); 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/NodeDeviceDockedHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.protocol.node.DeviceDockedResp; 6 | import com.gopush.protocol.node.NodeMessage; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明:处理 dataCenter 返回 的数据上报响应 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/20 下午11:00 17 | * @VERSION: 18 | */ 19 | 20 | @Slf4j 21 | @Component 22 | public class NodeDeviceDockedHandler extends NodeBaseHandler implements INodeMessageHandler { 23 | @Override 24 | public boolean support(NodeMessage message) { 25 | return message instanceof DeviceDockedResp; 26 | } 27 | 28 | @Override 29 | public void call(ChannelHandlerContext ctx, DeviceDockedResp message) { 30 | saveLiveDc(ctx.channel()); 31 | log.info("receive DeviceDockedResp, channel:{}, node:{}", ctx.channel(), ctx.channel().attr(Constants.CHANNEL_ATTR_DATACENTER).get()); 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/NodeInfoHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | 4 | import com.gopush.common.Constants; 5 | import com.gopush.nodes.handlers.INodeMessageHandler; 6 | import com.gopush.protocol.node.NodeInfoResp; 7 | import com.gopush.protocol.node.NodeMessage; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * go-push 14 | * 15 | * @类功能说明: 16 | * @作者:喝咖啡的囊地鼠 17 | * @创建时间:2017/6/20 下午11:00 18 | * @VERSION: 19 | */ 20 | 21 | @Slf4j 22 | @Component 23 | public class NodeInfoHandler extends NodeBaseHandler implements INodeMessageHandler { 24 | @Override 25 | public boolean support(NodeMessage message) { 26 | return message instanceof NodeInfoResp; 27 | } 28 | 29 | @Override 30 | public void call(ChannelHandlerContext ctx, NodeInfoResp message) { 31 | saveLiveDc(ctx.channel()); 32 | log.debug("receive NodeInfoResp, channel:{}, node:{}", ctx.channel(), ctx.channel().attr(Constants.CHANNEL_ATTR_DATACENTER).get()); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/NodePingHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.nodes.handlers.INodeMessageHandler; 4 | import com.gopush.protocol.node.NodeMessage; 5 | import com.gopush.protocol.node.Ping; 6 | import com.gopush.protocol.node.Pong; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * go-push 14 | * 15 | * @类功能说明: 16 | * @作者:喝咖啡的囊地鼠 17 | * @创建时间:2017/6/20 下午11:00 18 | * @VERSION: 19 | */ 20 | @Slf4j 21 | @Component 22 | public class NodePingHandler extends NodeBaseHandler implements INodeMessageHandler { 23 | 24 | private static final String PONG = Pong.builder().build().encode(); 25 | 26 | 27 | @Override 28 | public boolean support(NodeMessage message) { 29 | return message instanceof Ping; 30 | } 31 | 32 | @Override 33 | public void call(ChannelHandlerContext ctx, Ping message) { 34 | Channel channel = ctx.channel(); 35 | channel.writeAndFlush(PONG); 36 | saveLiveDc(channel); 37 | log.debug("node send pong to data center, channel:{}", ctx.channel()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/handlers/NodePongHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.handlers; 2 | 3 | import com.gopush.common.Constants; 4 | import com.gopush.nodes.handlers.INodeMessageHandler; 5 | import com.gopush.protocol.node.NodeMessage; 6 | import com.gopush.protocol.node.Pong; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明: 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/21 下午11:00 17 | * @VERSION: 18 | */ 19 | 20 | @Slf4j 21 | @Component 22 | public class NodePongHandler extends NodeBaseHandler implements INodeMessageHandler { 23 | 24 | 25 | @Override 26 | public boolean support(NodeMessage message) { 27 | return message instanceof Pong; 28 | } 29 | 30 | @Override 31 | public void call(ChannelHandlerContext ctx, Pong message) { 32 | //可以做一些保活操作.其实就是确保活动 33 | //查询本地缓存是否存在该data center 的节点,有的话不做出来,没有的话加入新的节点 34 | saveLiveDc(ctx.channel()); 35 | log.debug("receive pong, channel:{}, node:{}", ctx.channel(), ctx.channel().attr(Constants.CHANNEL_ATTR_DATACENTER).get()); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/inbound/NodeChannelInBoundHandler.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.inbound; 2 | 3 | import com.gopush.nodes.handlers.INodeMessageHandler; 4 | import com.gopush.nodeserver.nodes.stores.IDataCenterChannelStore; 5 | import com.gopush.protocol.node.NodeMessage; 6 | import com.gopush.protocol.node.Ping; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandler; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.SimpleChannelInboundHandler; 11 | import io.netty.handler.timeout.IdleState; 12 | import io.netty.handler.timeout.IdleStateEvent; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Component; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * go-push 21 | * 22 | * @类功能说明: 23 | * @作者:喝咖啡的囊地鼠 24 | * @创建时间:2017/6/20 下午9:33 25 | * @VERSION: 26 | */ 27 | 28 | @Slf4j 29 | @ChannelHandler.Sharable 30 | @Component 31 | public class NodeChannelInBoundHandler extends SimpleChannelInboundHandler { 32 | 33 | private static String PING = Ping.builder().build().encode(); 34 | 35 | @Autowired 36 | private IDataCenterChannelStore dataCenterChannelStore; 37 | 38 | 39 | @Autowired 40 | private List nodeMessageHandlers; 41 | 42 | @Override 43 | protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception { 44 | log.debug("channel:{}, message:{}", ctx.channel(), message); 45 | NodeMessage nodeMessage = NodeMessage.decode(message); 46 | if (!nodeMessageHandlers.isEmpty()) { 47 | nodeMessageHandlers.stream().forEach((handler) -> { 48 | try { 49 | if (handler.support(nodeMessage)) { 50 | handler.call(ctx, nodeMessage); 51 | } 52 | } catch (Exception e) { 53 | log.error("Exception error:{}", e); 54 | } 55 | }); 56 | } 57 | } 58 | 59 | @Override 60 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 61 | log.debug("channel active, channel:{}", ctx.channel()); 62 | dataCenterChannelStore.isDcChannelToSave(ctx.channel()); 63 | } 64 | 65 | @Override 66 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 67 | log.debug("channel inactive, channel:{}", ctx.channel()); 68 | dataCenterChannelStore.isDcChannelToRemove(ctx.channel()); 69 | } 70 | 71 | 72 | @Override 73 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 74 | log.error("exception error:{}, channel:{}", cause, ctx.channel()); 75 | ctx.close(); 76 | } 77 | 78 | @Override 79 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 80 | Channel channel = ctx.channel(); 81 | dataCenterChannelStore.isDcChannelToSave(channel); 82 | if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) { 83 | IdleStateEvent event = (IdleStateEvent) evt; 84 | if (event.state() == IdleState.ALL_IDLE) { 85 | //发送心跳 86 | channel.writeAndFlush(PING); 87 | } 88 | if (event.state() == IdleState.READER_IDLE) { 89 | //发送心跳 90 | channel.writeAndFlush(PING); 91 | } 92 | if (event.state() == IdleState.WRITER_IDLE) { 93 | channel.writeAndFlush(PING); 94 | } 95 | } else { 96 | super.userEventTriggered(ctx, evt); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/senders/INodeSender.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.senders; 2 | 3 | 4 | import com.gopush.protocol.node.NodeMessage; 5 | 6 | /** 7 | * go-push 8 | * 9 | * @类功能说明:数据中心发生类 10 | * @作者:喝咖啡的囊地鼠 11 | * @创建时间:2017/6/19 上午1:01 12 | * @VERSION: 13 | */ 14 | public interface INodeSender { 15 | 16 | 17 | /** 18 | * 向指定的数据中心发送 19 | * 20 | * @param dcId 21 | * @param message 22 | */ 23 | void send(String dcId, T message); 24 | 25 | 26 | /** 27 | * 随机选择一台发送 28 | * 29 | * @param message 30 | */ 31 | void sendShuffle(T message); 32 | 33 | /** 34 | * 全部数据中心发送 35 | * 36 | * @param message 37 | */ 38 | void send(T message); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/stores/DataCenterChannelStore.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.stores; 2 | 3 | import com.gopush.common.Constants; 4 | import io.netty.channel.Channel; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | /** 14 | * go-push 15 | * 16 | * @类功能说明: 17 | * @作者:喝咖啡的囊地鼠 18 | * @创建时间:2017/6/19 上午1:10 19 | * @VERSION: 20 | */ 21 | 22 | @Slf4j 23 | @Component 24 | public class DataCenterChannelStore implements IDataCenterChannelStore { 25 | 26 | 27 | //计数器 28 | private AtomicInteger counter = new AtomicInteger(0); 29 | 30 | 31 | //DataCenter-channel列表 32 | private ConcurrentHashMap dataCenterChannels = new ConcurrentHashMap<>(); 33 | 34 | 35 | @Override 36 | public List getAllChannels() { 37 | List list = null; 38 | if (!dataCenterChannels.isEmpty()) { 39 | list = new ArrayList<>(); 40 | list.addAll(dataCenterChannels.values()); 41 | } 42 | return list; 43 | } 44 | 45 | @Override 46 | public boolean contains(String dcId) { 47 | return dataCenterChannels.containsKey(dcId); 48 | } 49 | 50 | @Override 51 | public Channel getChannel(String dcId) { 52 | return dataCenterChannels.get(dcId); 53 | } 54 | 55 | @Override 56 | public String getDcId(Channel channel) { 57 | final String[] dcId = {null}; 58 | dataCenterChannels.forEach((String key, Channel target) -> { 59 | if (channel.equals(target)) { 60 | dcId[0] = key; 61 | } 62 | }); 63 | return dcId[0]; 64 | } 65 | 66 | 67 | @Override 68 | public void clear() { 69 | dataCenterChannels.clear(); 70 | counter.set(0); 71 | } 72 | 73 | 74 | @Override 75 | public int count() { 76 | return counter.get(); 77 | } 78 | 79 | 80 | @Override 81 | public void isDcChannelToSave(Channel channel) { 82 | if (!channel.hasAttr(Constants.CHANNEL_ATTR_DATACENTER)) { 83 | //添加相应的值 84 | String dcId = dataCenterId(channel); 85 | channel.attr(Constants.CHANNEL_ATTR_DATACENTER).set(dcId); 86 | if (!contains(dcId)) { 87 | addChannel(dcId, channel); 88 | } 89 | } 90 | } 91 | 92 | @Override 93 | public void isDcChannelToRemove(Channel channel) { 94 | String dcId = null; 95 | if (!channel.hasAttr(Constants.CHANNEL_ATTR_DATACENTER)) { 96 | dcId = dataCenterId(channel); 97 | } else { 98 | dcId = channel.attr(Constants.CHANNEL_ATTR_DATACENTER).get(); 99 | } 100 | if (contains(dcId)) { 101 | removeChannel(dcId, channel); 102 | } 103 | } 104 | 105 | 106 | /** 107 | * 生产DC-ID 108 | * 109 | * @param channel 110 | * @return 111 | */ 112 | private String dataCenterId(Channel channel) { 113 | return new StringBuilder() 114 | .append(channel.id()) 115 | .append(channel.remoteAddress().toString()) 116 | .toString(); 117 | } 118 | 119 | 120 | /** 121 | * 根据DCID移除channel,对比 channel存不存在 122 | * 123 | * @param dcId 124 | * @param channel 125 | */ 126 | private void removeChannel(String dcId, Channel channel) { 127 | if (channel.equals(dataCenterChannels.get(dcId))) { 128 | removeChannel(dcId); 129 | } 130 | } 131 | 132 | 133 | /** 134 | * 添加DC 135 | * 136 | * @param dcId 137 | * @param channel 138 | */ 139 | private void addChannel(String dcId, Channel channel) { 140 | dataCenterChannels.put(dcId, channel); 141 | counter.incrementAndGet(); 142 | } 143 | 144 | /** 145 | * 根据DCID删除 channel 146 | * 147 | * @param dcId 148 | */ 149 | private void removeChannel(String dcId) { 150 | dataCenterChannels.remove(dcId); 151 | int count = counter.decrementAndGet(); 152 | if (count < 0) { 153 | counter.set(0); 154 | } 155 | } 156 | 157 | } 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/java/com/gopush/nodeserver/nodes/stores/IDataCenterChannelStore.java: -------------------------------------------------------------------------------- 1 | package com.gopush.nodeserver.nodes.stores; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明: 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/19 上午1:10 13 | * @VERSION: 14 | */ 15 | public interface IDataCenterChannelStore { 16 | 17 | 18 | List getAllChannels(); 19 | 20 | 21 | boolean contains(String dcId); 22 | 23 | /** 24 | * 根据 DCID 获取Channel 25 | * 26 | * @param dcId 27 | * @return 28 | */ 29 | Channel getChannel(String dcId); 30 | 31 | 32 | /** 33 | * 根据channel获取dcid 34 | * 35 | * @param channel 36 | * @return 37 | */ 38 | String getDcId(Channel channel); 39 | 40 | /** 41 | * 清空channel 42 | */ 43 | void clear(); 44 | 45 | 46 | /** 47 | * DC-channel 计数 48 | * 49 | * @return 50 | */ 51 | int count(); 52 | 53 | 54 | /** 55 | * 检测此channel是不是已经存在的channel,不是的话加入缓存中 56 | * 57 | * @param channel 58 | */ 59 | void isDcChannelToSave(Channel channel); 60 | 61 | 62 | /** 63 | * 检测此channel是不是已经存在的channel,是的话删除缓存中 64 | * 65 | * @param channel 66 | */ 67 | void isDcChannelToRemove(Channel channel); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${random.int[6001,6999]} 3 | 4 | spring: 5 | redis: 6 | cluster: 7 | nodes: 8 | - 127.0.0.1:6379 9 | - 127.0.0.1:6379 10 | 11 | go-push: 12 | node-server: 13 | name: NodeServer-${random.int(100)} 14 | node-port: ${random.int[7001,7999]} 15 | device-port: ${random.int[9001,9999]} 16 | batch-processor: 17 | delay: 1000 18 | batch-size: 300 19 | warn-threshold: 300 20 | processor-size: 2 21 | core-pool-size: 1 22 | 23 | zookeeper: 24 | servers: 192.168.99.100:32773 25 | listen-namespace: namespace-data-center 26 | namespace: namespace-node-server 27 | session-timeout: 6000 28 | connection-timeout: 6000 29 | max-retries: 1000 30 | retries-sleep-time: 2000 31 | 32 | 33 | -------------------------------------------------------------------------------- /go-push-node-server/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_GREEN} 2 | _ _ _ _____ 3 | | \ | | | | / ____| 4 | | \| | ___ __| | ___| (___ ___ _ ____ _____ _ __ 5 | | . ` |/ _ \ / _` |/ _ \\___ \ / _ \ '__\ \ / / _ \ '__| 6 | | |\ | (_) | (_| | __/____) | __/ | \ V / __/ | _____ _____ _ 7 | |_| \_|\___/ \__,_|\___|_____/ \___|_| \_/ \___|_| / ____| | __ \ | | 8 | ______ ______ ______ ______ ______ ______ ______ ______ ______ ______ ______ | | __ ___ | |__) | _ ___| |__ 9 | |______|______|______|______|______|______|______|______|______|______|______| | | |_ |/ _ \| ___/ | | / __| '_ \ 10 | | |__| | (_) | | | |_| \__ \ | | | 11 | \_____|\___/|_| \__,_|___/_| |_| 12 | 13 | ${AnsiColor.BRIGHT_RED} 14 | Application Version: ${application.version}${application.formatted-version} 15 | Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} -------------------------------------------------------------------------------- /go-push-node-server/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-node-server/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-protocol-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | go-push-protocol-device 12 | jar 13 | Device 与 NodeServer 传输协议 14 | 15 | 16 | 17 | com.alibaba 18 | fastjson 19 | 20 | 21 | org.projectlombok 22 | lombok 23 | provided 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/DeviceMessage.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.annotation.JSONField; 5 | import com.gopush.protocol.exceptions.DeviceProtocolException; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明:设备消息基类 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/9 17 | * @VERSION: 18 | */ 19 | 20 | public abstract class DeviceMessage { 21 | 22 | /** 23 | * 消息类型 24 | * 1)心跳请求 25 | * 2)心跳响应 26 | * 3)握手请求 27 | * 4)握手响应 28 | * 5)消息推送 29 | * 6)推送反馈 30 | */ 31 | protected enum Type { 32 | PI, // PING 33 | PO, // PONG 34 | HS, // HANDSHAKE_REQ 35 | HSR, // HANDSHAKE_RESP 36 | P, // PUSH_REQ 37 | PR // PUSH_RESP 38 | } 39 | 40 | /** 41 | * 获取设备消息类型 42 | * 43 | * @return 44 | */ 45 | protected abstract Type type(); 46 | 47 | 48 | protected abstract T getThis() throws Exception; 49 | 50 | /** 51 | * 节点消息转换 52 | * 53 | * @return 54 | * @throws Exception 55 | */ 56 | protected String toEncode() throws Exception { 57 | return JSON.toJSONString(getThis()); 58 | } 59 | 60 | 61 | /** 62 | * 设备消息编码 63 | * 64 | * @return 65 | */ 66 | public String encode() throws DeviceProtocolException { 67 | try { 68 | 69 | Message message = Message 70 | .builder() 71 | .type(type()) 72 | .message(toEncode()) 73 | .build(); 74 | return JSON.toJSONString(message); 75 | } catch (Exception e) { 76 | throw new DeviceProtocolException(e); 77 | } 78 | } 79 | 80 | 81 | /** 82 | * 设备消息解码 83 | * 84 | * @param json 85 | * @return 86 | * @throws DeviceProtocolException 87 | */ 88 | public static DeviceMessage decode(String json) throws DeviceProtocolException { 89 | try { 90 | 91 | Message msg = JSON.parseObject(json, Message.class); 92 | 93 | Class cls = null; 94 | 95 | switch (msg.type) { 96 | case PI: 97 | cls = Ping.class; 98 | break; 99 | case PO: 100 | cls = Pong.class; 101 | break; 102 | case HS: 103 | cls = HandShakeReq.class; 104 | break; 105 | case HSR: 106 | cls = HandShakeResp.class; 107 | break; 108 | case P: 109 | cls = PushReq.class; 110 | break; 111 | case PR: 112 | cls = PushResp.class; 113 | break; 114 | default: 115 | throw new DeviceProtocolException("Unknown Device type " + msg.type); 116 | } 117 | DeviceMessage message = (DeviceMessage) JSON.parseObject(msg.message, cls); 118 | return message; 119 | } catch (Exception e) { 120 | throw new DeviceProtocolException("Exception occur,Message is " + json, e); 121 | } 122 | } 123 | 124 | 125 | //真正的传递消息的类 126 | 127 | @Builder 128 | @Data 129 | @NoArgsConstructor 130 | @AllArgsConstructor 131 | private static class Message { 132 | @JSONField(name = "T") 133 | private Type type; 134 | 135 | @JSONField(name = "M") 136 | private String message; 137 | 138 | } 139 | 140 | 141 | } 142 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/DeviceMessageReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | 4 | /** 5 | * go-push 6 | * 7 | * @类功能说明:设备消息请求基类 8 | * @作者:喝咖啡的囊地鼠 9 | * @创建时间:2017/6/9 10 | * @VERSION: 11 | */ 12 | public abstract class DeviceMessageReq extends DeviceMessage { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/DeviceMessageResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | 4 | /** 5 | * go-push 6 | * 7 | * @类功能说明:设备消息响应基类 8 | * @作者:喝咖啡的囊地鼠 9 | * @创建时间:2017/6/9 10 | * @VERSION: 11 | */ 12 | public abstract class DeviceMessageResp extends DeviceMessage { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/HandShakeReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:握手请求 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | 18 | @Builder 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | public class HandShakeReq extends DeviceMessageReq { 23 | 24 | @JSONField(name = "D") 25 | private String device; 26 | 27 | @JSONField(name = "TK") 28 | private String token; 29 | 30 | @JSONField(name = "R_IDLE") 31 | private int readInterval; 32 | @JSONField(name = "W_IDLE") 33 | private int writeInterval; 34 | @JSONField(name = "A_IDLE") 35 | private int allInterval; 36 | 37 | 38 | @Override 39 | protected Type type() { 40 | return Type.HS; 41 | } 42 | 43 | @Override 44 | protected HandShakeReq getThis() throws Exception { 45 | return this; 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/HandShakeResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:握手响应 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | 18 | @Builder 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | public class HandShakeResp extends DeviceMessageResp { 23 | 24 | @JSONField(name = "R") 25 | private int result; 26 | 27 | @Override 28 | protected Type type() { 29 | return Type.HSR; 30 | } 31 | 32 | @Override 33 | protected HandShakeResp getThis() throws Exception { 34 | return this; 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/Ping.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:Ping-Pong 心跳 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/9 13 | * @VERSION: 14 | */ 15 | @Builder 16 | @Data 17 | @AllArgsConstructor 18 | public class Ping extends DeviceMessageReq { 19 | 20 | @Override 21 | protected Type type() { 22 | return Type.PI; 23 | } 24 | 25 | @Override 26 | protected Ping getThis() throws Exception { 27 | return this; 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/Pong.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:Ping-Pong 心跳 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/9 13 | * @VERSION: 14 | */ 15 | @Builder 16 | @Data 17 | @AllArgsConstructor 18 | public class Pong extends DeviceMessageResp { 19 | 20 | 21 | @Override 22 | protected Type type() { 23 | return Type.PO; 24 | } 25 | 26 | @Override 27 | protected Pong getThis() throws Exception { 28 | return this; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/PushReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明:推送消息请求 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/9 17 | * @VERSION: 18 | */ 19 | @Builder 20 | @Data 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | public class PushReq extends DeviceMessageReq { 24 | 25 | @JSONField(name = "ID") 26 | private String id; 27 | 28 | @JSONField(name = "MCS") 29 | private List msgs; 30 | 31 | @Override 32 | protected Type type() { 33 | return Type.P; 34 | } 35 | 36 | @Override 37 | protected PushReq getThis() throws Exception { 38 | return this; 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/device/PushResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.device; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:推送消息响应 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | @Builder 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class PushResp extends DeviceMessageResp { 22 | 23 | // private static final String DEVICE_KEY = "D"; 24 | // private final static String MSG_KEY = "ID"; 25 | // private final static String RESULT_KEY = "R"; 26 | 27 | 28 | public enum Result { 29 | S, //SUCCESS, 30 | D, //DUPLICATE, 31 | NR, //NOT_REGISTERED, 32 | IN //INTERNAL_ERROR 33 | } 34 | 35 | @JSONField(name = "D") 36 | private String device; 37 | 38 | @JSONField(name = "ID") 39 | private String msgId; 40 | 41 | @JSONField(name = "R") 42 | private Result result; 43 | 44 | @Override 45 | protected Type type() { 46 | return Type.PR; 47 | } 48 | 49 | @Override 50 | protected PushResp getThis() throws Exception { 51 | return this; 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/java/com/gopush/protocol/exceptions/DeviceProtocolException.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.exceptions; 2 | 3 | /** 4 | * go-push 5 | * 6 | * @类功能说明:设备协议异常 7 | * @作者:喝咖啡的囊地鼠 8 | * @创建时间:2017/6/9 9 | * @VERSION: 10 | */ 11 | public class DeviceProtocolException extends RuntimeException { 12 | public DeviceProtocolException() { 13 | } 14 | 15 | public DeviceProtocolException(String message) { 16 | super(message); 17 | } 18 | 19 | public DeviceProtocolException(Throwable cause) { 20 | super(cause); 21 | } 22 | 23 | public DeviceProtocolException(String message, Throwable cause) { 24 | super(message, cause); 25 | } 26 | 27 | 28 | public DeviceProtocolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 29 | super(message, cause, enableSuppression, writableStackTrace); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /go-push-protocol-device/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-protocol-device/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-protocol-device/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-protocol-device/src/test/java/.gitignore -------------------------------------------------------------------------------- /go-push-protocol-node/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | go-push 7 | com.gopush 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | go-push-protocol-node 12 | jar 13 | NodeServer 与 DataCenter 传输协议 14 | 15 | 16 | 17 | com.alibaba 18 | fastjson 19 | 20 | 21 | org.projectlombok 22 | lombok 23 | provided 24 | 25 | 26 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/exceptions/NodeProtocolException.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.exceptions; 2 | 3 | /** 4 | * go-push 5 | * 6 | * @类功能说明:服务节点协议异常 7 | * @作者:喝咖啡的囊地鼠 8 | * @创建时间:2017/6/9 9 | * @VERSION: 10 | */ 11 | public class NodeProtocolException extends RuntimeException { 12 | 13 | public NodeProtocolException() { 14 | } 15 | 16 | public NodeProtocolException(String message) { 17 | super(message); 18 | } 19 | 20 | public NodeProtocolException(String message, Throwable cause) { 21 | super(message, cause); 22 | } 23 | 24 | public NodeProtocolException(Throwable cause) { 25 | super(cause); 26 | } 27 | 28 | public NodeProtocolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 29 | super(message, cause, enableSuppression, writableStackTrace); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/DeviceDisconReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * go-push 14 | * 15 | * @类功能说明:设备下线上报请求 16 | * @作者:喝咖啡的囊地鼠 17 | * @创建时间:2017/6/9 18 | * @VERSION: 19 | */ 20 | 21 | 22 | @Builder 23 | @Data 24 | @AllArgsConstructor 25 | @NoArgsConstructor 26 | public class DeviceDisconReq extends NodeMessageReq { 27 | 28 | 29 | //需要上报的设备列表(是批量上报的) 30 | 31 | @JSONField(name = "DEVS") 32 | private List devices; 33 | 34 | @JSONField(name = "N") 35 | private String node; 36 | 37 | /** 38 | * 添加设备 39 | * 40 | * @param device 41 | */ 42 | 43 | public void addDevice(String device) { 44 | if (devices == null) { 45 | devices = new ArrayList<>(); 46 | } 47 | if (!devices.contains(device)) { 48 | devices.add(device); 49 | } 50 | } 51 | 52 | @Override 53 | protected Type type() { 54 | return Type.DI; 55 | } 56 | 57 | @Override 58 | protected DeviceDisconReq getThis() { 59 | return this; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/DeviceDisconResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:设备下线上报响应 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | @Builder 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class DeviceDisconResp extends NodeMessageResp { 22 | 23 | 24 | @JSONField(name = "R") 25 | private int result; 26 | 27 | @Override 28 | protected Type type() { 29 | return Type.DIS; 30 | } 31 | 32 | @Override 33 | protected DeviceDisconResp getThis() { 34 | return this; 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/DeviceDockedReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * go-push 14 | * 15 | * @类功能说明:设备上线上报请求 16 | * @作者:喝咖啡的囊地鼠 17 | * @创建时间:2017/6/9 18 | * @VERSION: 19 | */ 20 | @Builder 21 | @Data 22 | @AllArgsConstructor 23 | @NoArgsConstructor 24 | public class DeviceDockedReq extends NodeMessageReq { 25 | 26 | //需要上报的设备列表(是批量上报的) 27 | @JSONField(name = "DEVS") 28 | private List devices; 29 | 30 | 31 | @JSONField(name = "N") 32 | private String node; 33 | 34 | /** 35 | * 添加设备 36 | * 37 | * @param device 38 | */ 39 | 40 | public void addDevice(String device) { 41 | if (devices == null) { 42 | devices = new ArrayList<>(); 43 | } 44 | if (!devices.contains(device)) { 45 | devices.add(device); 46 | } 47 | } 48 | 49 | 50 | @Override 51 | protected Type type() { 52 | return Type.DO; 53 | } 54 | 55 | @Override 56 | protected DeviceDockedReq getThis() { 57 | return this; 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/DeviceDockedResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:设备上线上报响应 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | @Builder 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class DeviceDockedResp extends NodeMessageResp { 22 | 23 | 24 | @JSONField(name = "R") 25 | private int result; 26 | 27 | @Override 28 | protected Type type() { 29 | return Type.DOS; 30 | } 31 | 32 | @Override 33 | protected DeviceDockedResp getThis() { 34 | return this; 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/MessageToMultiDeviceReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明:单条消息发送给多个设备(连接在单个node上的) 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/9 17 | * @VERSION: 18 | */ 19 | @Builder 20 | @Data 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | public class MessageToMultiDeviceReq extends NodeMessageReq { 24 | 25 | @JSONField(name = "DEVS") 26 | private List devices; 27 | 28 | @JSONField(name = "MES") 29 | private String message; 30 | 31 | 32 | @Override 33 | protected Type type() { 34 | return Type.OTM; 35 | } 36 | 37 | @Override 38 | protected MessageToMultiDeviceReq getThis() { 39 | return this; 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/MessageToMultiDeviceResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:单条消息发送给多个设备(连接在单个node上的) 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | @Builder 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class MessageToMultiDeviceResp extends NodeMessageResp { 22 | 23 | @JSONField(name = "R") 24 | private int result; 25 | 26 | @Override 27 | protected Type type() { 28 | return Type.OTMS; 29 | } 30 | 31 | @Override 32 | protected MessageToMultiDeviceResp getThis() { 33 | return this; 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/MultiMessageToDeviceReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * go-push 13 | * 14 | * @类功能说明:多条消息发送给单个设备(连接在单个node上的) 15 | * @作者:喝咖啡的囊地鼠 16 | * @创建时间:2017/6/9 17 | * @VERSION: 18 | */ 19 | @Builder 20 | @Data 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | public class MultiMessageToDeviceReq extends NodeMessageReq { 24 | 25 | 26 | @JSONField(name = "MESS") 27 | private List messages; 28 | 29 | @JSONField(name = "DEV") 30 | private String device; 31 | 32 | @Override 33 | protected Type type() { 34 | return Type.MTO; 35 | } 36 | 37 | @Override 38 | protected MultiMessageToDeviceReq getThis() { 39 | return this; 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/MultiMessageToDeviceResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:多条消息发送给单个设备(连接在单个node上的) 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | @Builder 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class MultiMessageToDeviceResp extends NodeMessageResp { 22 | 23 | @JSONField(name = "R") 24 | private int result; 25 | 26 | @Override 27 | protected Type type() { 28 | return Type.MTOS; 29 | } 30 | 31 | @Override 32 | protected MultiMessageToDeviceResp getThis() { 33 | return this; 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/NodeInfoReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:节点运行信息请求 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/9 13 | * @VERSION: 14 | */ 15 | @Builder 16 | @Data 17 | @AllArgsConstructor 18 | public class NodeInfoReq extends NodeMessageReq { 19 | @Override 20 | protected Type type() { 21 | return Type.NI; 22 | } 23 | 24 | @Override 25 | protected NodeInfoReq getThis() { 26 | return this; 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/NodeInfoResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * go-push 11 | * 12 | * @类功能说明:节点运行信息响应 13 | * @作者:喝咖啡的囊地鼠 14 | * @创建时间:2017/6/9 15 | * @VERSION: 16 | */ 17 | @Builder 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | public class NodeInfoResp extends NodeMessageResp { 22 | 23 | 24 | @JSONField(name = "R") 25 | private int result; 26 | 27 | 28 | @Override 29 | protected Type type() { 30 | return Type.NIS; 31 | } 32 | 33 | @Override 34 | protected NodeInfoResp getThis() { 35 | return this; 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/NodeMessage.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.annotation.JSONField; 5 | import com.gopush.protocol.exceptions.NodeProtocolException; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * go-push 14 | * 15 | * @类功能说明:节点服务消息基类 16 | * @作者:喝咖啡的囊地鼠 17 | * @创建时间:2017/6/9 18 | * @VERSION: 19 | */ 20 | public abstract class NodeMessage { 21 | 22 | //消息 Type Key 23 | 24 | /** 25 | * 消息类型 26 | * 1)心跳请求 27 | * 2)心跳响应 28 | * 3)设备上线请求 29 | * 4)设备上线响应 30 | * 5)设备断线请求 31 | * 6)设备断线响应 32 | * 7)多条消息发送给一个设备请求 33 | * 8)多条消息发送给一个设备响应 34 | * 9)单条消息发送给多个设备请求 35 | * 10)单条消息发送给多个设备响应 36 | * 11)节点服务信息请求 37 | * 12)节点服务信息响应 38 | */ 39 | protected enum Type { 40 | PI, //PING 41 | PO, //PONG 42 | DO, //DEVICE_DOCKED_REQ 43 | DOS, //DEVICE_DOCKED_RESP 44 | DI, //DEVICE_DISCON_REQ 45 | DIS, //DEVICE_DISCON_RESP 46 | MTO, //MULTI_MSG_TO_ONE_DEVICE_REQ 47 | MTOS, //MULTI_MSG_TO_ONE_DEVICE_RESP 48 | OTM, //ONE_MSG_TO_MULTI_DEVICE_REQ 49 | OTMS, //ONE_MSG_TO_MULTI_DEVICE_RESP 50 | NI, //NODE_INFO_REQ 51 | NIS, //NODE_INFO_RESP 52 | } 53 | 54 | /** 55 | * 获取节点消息类型 56 | * 57 | * @return 58 | */ 59 | protected abstract Type type(); 60 | 61 | 62 | protected abstract T getThis(); 63 | 64 | /** 65 | * 节点消息转换 66 | * 67 | * @return 68 | * @throws Exception 69 | */ 70 | protected String toEncode() throws Exception { 71 | return JSON.toJSONString(getThis()); 72 | } 73 | 74 | 75 | /** 76 | * 节点消息编码 77 | * 78 | * @return 79 | */ 80 | public String encode() throws NodeProtocolException { 81 | try { 82 | Message message = Message 83 | .builder() 84 | .type(type()) 85 | .message(toEncode()) 86 | .build(); 87 | // System.out.println("Node message json: "+ JSON.toJSONString(message)); 88 | return JSON.toJSONString(message); 89 | } catch (Exception e) { 90 | throw new NodeProtocolException(e); 91 | } 92 | } 93 | 94 | 95 | /** 96 | * 节点消息解码 97 | * 98 | * @param json 99 | * @return 100 | * @throws NodeProtocolException 101 | */ 102 | public static NodeMessage decode(String json) throws NodeProtocolException { 103 | try { 104 | 105 | Message msg = JSON.parseObject(json, Message.class); 106 | NodeMessage message; 107 | 108 | Class cls; 109 | switch (msg.type) { 110 | case PI: 111 | cls = Ping.class; 112 | break; 113 | case PO: 114 | cls = Pong.class; 115 | break; 116 | case DO: 117 | cls = DeviceDockedReq.class; 118 | break; 119 | case DOS: 120 | cls = DeviceDockedResp.class; 121 | break; 122 | case DI: 123 | cls = DeviceDisconReq.class; 124 | break; 125 | case DIS: 126 | cls = DeviceDisconResp.class; 127 | break; 128 | case MTO: 129 | cls = MultiMessageToDeviceReq.class; 130 | break; 131 | case MTOS: 132 | cls = MultiMessageToDeviceResp.class; 133 | break; 134 | case OTM: 135 | cls = MessageToMultiDeviceReq.class; 136 | break; 137 | case OTMS: 138 | cls = MessageToMultiDeviceResp.class; 139 | break; 140 | case NI: 141 | cls = NodeInfoReq.class; 142 | break; 143 | case NIS: 144 | cls = NodeInfoResp.class; 145 | break; 146 | default: 147 | throw new NodeProtocolException("Unknown Node type " + msg.type); 148 | 149 | } 150 | message = (NodeMessage) JSON.parseObject(msg.message, cls); 151 | return message; 152 | } catch (Exception e) { 153 | throw new NodeProtocolException("Exception occur,Message is " + json, e); 154 | } 155 | } 156 | 157 | 158 | //真正的传递消息的类 159 | @Builder 160 | @Data 161 | @NoArgsConstructor 162 | @AllArgsConstructor 163 | private static class Message { 164 | @JSONField(name = "T") 165 | private Type type; 166 | 167 | @JSONField(name = "M") 168 | private String message; 169 | 170 | } 171 | 172 | 173 | } 174 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/NodeMessageReq.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | /** 4 | * go-push 5 | * 6 | * @类功能说明:节点服务请求消息基类 7 | * @作者:喝咖啡的囊地鼠 8 | * @创建时间:2017/6/9 9 | * @VERSION: 10 | */ 11 | public abstract class NodeMessageReq extends NodeMessage { 12 | } 13 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/NodeMessageResp.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | /** 4 | * go-push 5 | * 6 | * @类功能说明:节点服务响应消息基类 7 | * @作者:喝咖啡的囊地鼠 8 | * @创建时间:2017/6/9 9 | * @VERSION: 10 | */ 11 | public abstract class NodeMessageResp extends NodeMessage { 12 | } 13 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/Ping.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:Ping-Pong 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/9 13 | * @VERSION: 14 | */ 15 | @Builder 16 | @Data 17 | @AllArgsConstructor 18 | public class Ping extends NodeMessageReq { 19 | 20 | 21 | @Override 22 | protected Type type() { 23 | return Type.PI; 24 | } 25 | 26 | @Override 27 | protected Ping getThis() { 28 | return this; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/java/com/gopush/protocol/node/Pong.java: -------------------------------------------------------------------------------- 1 | package com.gopush.protocol.node; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | /** 8 | * go-push 9 | * 10 | * @类功能说明:Ping-Pong 11 | * @作者:喝咖啡的囊地鼠 12 | * @创建时间:2017/6/9 13 | * @VERSION: 14 | */ 15 | 16 | @Builder 17 | @Data 18 | @AllArgsConstructor 19 | public class Pong extends NodeMessageResp { 20 | 21 | 22 | @Override 23 | protected Type type() { 24 | return Type.PO; 25 | } 26 | 27 | @Override 28 | protected Pong getThis() { 29 | return this; 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /go-push-protocol-node/src/main/resources/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-protocol-node/src/main/resources/.gitignore -------------------------------------------------------------------------------- /go-push-protocol-node/src/test/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkhello/gopush/94bbbb40b2bc20196c0388a2a8482c6cb00909df/go-push-protocol-node/src/test/java/.gitignore -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Go Push 推送服务 6 | 7 | 8 | node server 完成度 95% 9 | data center 完成度 95% 10 | monitor 完成度 90% 11 | 12 | --------------------------------------------------------------------------------