是一款集成发布订阅、点对点通讯、pull拉取、定向通知功能,为用户提供及时、高效、稳定的消息交换推送服务产品
85 |├── docs ├── push.md ├── manager.md ├── region.md ├── architecture.png ├── user-guide │ ├── login.png │ ├── create_app.png │ ├── register.png │ ├── relations.png │ ├── create_entity.png │ ├── account.md │ └── application.md ├── architecture.md └── feature.md ├── .gitattributes ├── common ├── project │ └── assembly.sbt ├── src │ └── main │ │ ├── scala │ │ └── com │ │ │ └── msg │ │ │ └── common │ │ │ ├── util │ │ │ ├── JsonTest.scala │ │ │ ├── Md5.scala │ │ │ ├── JsonUtil.scala │ │ │ └── JsonElement.scala │ │ │ └── model │ │ │ ├── QueueEntity.scala │ │ │ ├── NotifyEntity.scala │ │ │ ├── TopicEntity.scala │ │ │ ├── TemplateEntity.scala │ │ │ ├── RegAddrEntity.scala │ │ │ └── Models.scala │ │ └── java │ │ └── com │ │ └── msg │ │ └── common │ │ └── util │ │ ├── FstUtil.java │ │ └── CommonUtil.java └── build.sbt ├── push ├── project │ └── assembly.sbt ├── src │ └── main │ │ ├── resources │ │ ├── mongdb-region.conf │ │ ├── log4j.properties │ │ └── push-config.conf │ │ ├── scala │ │ └── com │ │ │ └── msg │ │ │ └── push │ │ │ ├── util │ │ │ └── Constants.scala │ │ │ ├── actor │ │ │ ├── DeadLetterListener.scala │ │ │ ├── WebsoketCenter.scala │ │ │ ├── SocketCenter.scala │ │ │ ├── SocketIoCenter.scala │ │ │ ├── InitRegionBaseInfo.scala │ │ │ └── SubBaseActor.scala │ │ │ ├── socket │ │ │ ├── TcpSoketServer.scala │ │ │ └── ListeningHander.scala │ │ │ ├── ws │ │ │ ├── PushWsUserActor.scala │ │ │ └── PushWsServer.scala │ │ │ ├── PushServer.scala │ │ │ └── socketio │ │ │ ├── SoketioUserActor.scala │ │ │ └── SoketIoService.scala │ │ └── java │ │ └── com │ │ └── msg │ │ └── push │ │ └── socketio │ │ ├── RepData.java │ │ └── SoketIo.java └── build.sbt ├── region ├── project │ └── assembly.sbt ├── src │ └── main │ │ ├── resources │ │ ├── mongdb-region.conf │ │ └── log4j.properties │ │ └── scala │ │ └── com │ │ └── msg │ │ └── region │ │ ├── seed │ │ ├── cluster │ │ │ ├── ClusterDiscovery.scala │ │ │ ├── ClusterDiscoveryImpl.scala │ │ │ ├── ClusterDiscoverySettings.scala │ │ │ └── LeaderEntryActor.scala │ │ ├── streams │ │ │ └── FlowBreaker.scala │ │ └── etcd │ │ │ ├── EtcdJsonProtocol.scala │ │ │ ├── EtcdException.scala │ │ │ ├── EtcdClient.scala │ │ │ ├── EtcdMessage.scala │ │ │ └── EtcdOperationActor.scala │ │ ├── actor │ │ ├── InitRegionBaseInfo.scala │ │ ├── MsgObject.scala │ │ ├── DeadLetterListener.scala │ │ ├── MsgExchangeActor.scala │ │ └── ReceiveMsg.scala │ │ ├── RegionServer.scala │ │ ├── util │ │ └── Constants.scala │ │ └── http │ │ └── HttpGetRouter.scala └── build.sbt ├── manager ├── img │ ├── bg.png │ ├── demo.png │ ├── apply.png │ ├── demo1.png │ ├── demo2.png │ ├── demo3.png │ ├── module.png │ ├── stage.png │ ├── create_ds.png │ ├── ds_edit.png │ ├── operation.png │ ├── structure.png │ ├── notify_demo.png │ ├── notify_edit.png │ ├── notify_list.png │ ├── slide-left.png │ ├── slide-right.png │ ├── topic_edit.png │ ├── topic_list.png │ ├── topic_list1.png │ ├── topic_list2.png │ ├── business_list.png │ ├── business_list1.png │ ├── create_topic.png │ ├── modify_topic.png │ ├── modify_topic1.png │ ├── notify_create.png │ ├── notify_detail.png │ ├── notify_list1.png │ ├── notify_params.png │ ├── template_demo.png │ ├── template_demo1.png │ ├── template_edit.png │ ├── template_list.png │ ├── template_list1.png │ ├── topic_detail.png │ ├── dataSource_list.png │ ├── dataSource_list1.png │ ├── template_create.png │ ├── template_detail.png │ ├── template_params.png │ ├── notify_demo_param.png │ └── template_demo_param.png ├── WebSocketMain.swf ├── down │ ├── websoket.js.zip │ └── WebSocketMain.swf.zip ├── composer.json ├── mongoUtil.php ├── js │ ├── npm.js │ ├── msg-socketio.js │ └── msg-websoket.js ├── validateSession.php ├── postData.php ├── pullData.php ├── css │ ├── signin.css │ └── common.css ├── head.php ├── apply.php ├── apply_init.php ├── 5000.html ├── 4000.html ├── notify_detail.php ├── template_detail.php ├── sdk.php ├── business.php ├── login.php ├── demo │ ├── js │ │ └── msg-websoket.js │ └── http_demo.php ├── createtopic.php ├── user.php ├── topic_detail.php ├── notify_param.php ├── template_param.php ├── index.php ├── http_demo.php ├── main.php ├── template_modify.php ├── notify_modify.php └── dataSource.php └── README.md /docs/push.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/manager.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/region.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=Scala 2 | *.css linguist-language=Scala 3 | -------------------------------------------------------------------------------- /common/project/assembly.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.2") -------------------------------------------------------------------------------- /push/project/assembly.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.2") -------------------------------------------------------------------------------- /region/project/assembly.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.2") -------------------------------------------------------------------------------- /manager/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/bg.png -------------------------------------------------------------------------------- /manager/img/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/demo.png -------------------------------------------------------------------------------- /docs/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/docs/architecture.png -------------------------------------------------------------------------------- /manager/img/apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/apply.png -------------------------------------------------------------------------------- /manager/img/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/demo1.png -------------------------------------------------------------------------------- /manager/img/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/demo2.png -------------------------------------------------------------------------------- /manager/img/demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/demo3.png -------------------------------------------------------------------------------- /manager/img/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/module.png -------------------------------------------------------------------------------- /manager/img/stage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/stage.png -------------------------------------------------------------------------------- /docs/user-guide/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/docs/user-guide/login.png -------------------------------------------------------------------------------- /manager/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/WebSocketMain.swf -------------------------------------------------------------------------------- /manager/img/create_ds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/create_ds.png -------------------------------------------------------------------------------- /manager/img/ds_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/ds_edit.png -------------------------------------------------------------------------------- /manager/img/operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/operation.png -------------------------------------------------------------------------------- /manager/img/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/structure.png -------------------------------------------------------------------------------- /manager/img/notify_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_demo.png -------------------------------------------------------------------------------- /manager/img/notify_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_edit.png -------------------------------------------------------------------------------- /manager/img/notify_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_list.png -------------------------------------------------------------------------------- /manager/img/slide-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/slide-left.png -------------------------------------------------------------------------------- /manager/img/slide-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/slide-right.png -------------------------------------------------------------------------------- /manager/img/topic_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/topic_edit.png -------------------------------------------------------------------------------- /manager/img/topic_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/topic_list.png -------------------------------------------------------------------------------- /manager/img/topic_list1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/topic_list1.png -------------------------------------------------------------------------------- /manager/img/topic_list2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/topic_list2.png -------------------------------------------------------------------------------- /docs/user-guide/create_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/docs/user-guide/create_app.png -------------------------------------------------------------------------------- /docs/user-guide/register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/docs/user-guide/register.png -------------------------------------------------------------------------------- /docs/user-guide/relations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/docs/user-guide/relations.png -------------------------------------------------------------------------------- /manager/down/websoket.js.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/down/websoket.js.zip -------------------------------------------------------------------------------- /manager/img/business_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/business_list.png -------------------------------------------------------------------------------- /manager/img/business_list1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/business_list1.png -------------------------------------------------------------------------------- /manager/img/create_topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/create_topic.png -------------------------------------------------------------------------------- /manager/img/modify_topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/modify_topic.png -------------------------------------------------------------------------------- /manager/img/modify_topic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/modify_topic1.png -------------------------------------------------------------------------------- /manager/img/notify_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_create.png -------------------------------------------------------------------------------- /manager/img/notify_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_detail.png -------------------------------------------------------------------------------- /manager/img/notify_list1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_list1.png -------------------------------------------------------------------------------- /manager/img/notify_params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_params.png -------------------------------------------------------------------------------- /manager/img/template_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_demo.png -------------------------------------------------------------------------------- /manager/img/template_demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_demo1.png -------------------------------------------------------------------------------- /manager/img/template_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_edit.png -------------------------------------------------------------------------------- /manager/img/template_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_list.png -------------------------------------------------------------------------------- /manager/img/template_list1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_list1.png -------------------------------------------------------------------------------- /manager/img/topic_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/topic_detail.png -------------------------------------------------------------------------------- /manager/img/dataSource_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/dataSource_list.png -------------------------------------------------------------------------------- /manager/img/dataSource_list1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/dataSource_list1.png -------------------------------------------------------------------------------- /manager/img/template_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_create.png -------------------------------------------------------------------------------- /manager/img/template_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_detail.png -------------------------------------------------------------------------------- /manager/img/template_params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_params.png -------------------------------------------------------------------------------- /docs/user-guide/create_entity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/docs/user-guide/create_entity.png -------------------------------------------------------------------------------- /manager/down/WebSocketMain.swf.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/down/WebSocketMain.swf.zip -------------------------------------------------------------------------------- /manager/img/notify_demo_param.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/notify_demo_param.png -------------------------------------------------------------------------------- /manager/img/template_demo_param.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goodrain/realtime-message-system/HEAD/manager/img/template_demo_param.png -------------------------------------------------------------------------------- /docs/user-guide/account.md: -------------------------------------------------------------------------------- 1 | #register user account 2 | 3 |  4 | 5 | #login mnagement background 6 | 7 |  8 | 9 | -------------------------------------------------------------------------------- /manager/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "ext-xsl": "*", 4 | "ext-mongo": "*", 5 | "ext-memcached": "*", 6 | "ext-bcmath": "*" 7 | } 8 | } -------------------------------------------------------------------------------- /push/src/main/resources/mongdb-region.conf: -------------------------------------------------------------------------------- 1 | region_mongo.host="127.0.0.1" 2 | region_mongo.port="27017" 3 | region_mongo.db="msg-center" 4 | region_mongo.table="region_info" 5 | region_mongo.user="" 6 | region_mongo.passwd="" 7 | region_role="MsgRoleNode" -------------------------------------------------------------------------------- /region/src/main/resources/mongdb-region.conf: -------------------------------------------------------------------------------- 1 | region_mongo.host="127.0.0.1" 2 | region_mongo.port="27017" 3 | region_mongo.db="msg-center" 4 | region_mongo.table="region_info" 5 | region_mongo.user="" 6 | region_mongo.passwd="" 7 | region_role="MsgRoleNode" -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/util/Constants.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.util 2 | 3 | import java.text.SimpleDateFormat 4 | 5 | object Constants { 6 | val TOPIC_INFO = "topic_info" 7 | val REGION_INFO = "region_info" 8 | val SEC = "::::" 9 | } -------------------------------------------------------------------------------- /common/src/main/scala/com/msg/common/util/JsonTest.scala: -------------------------------------------------------------------------------- 1 | package com.msg.common.util 2 | 3 | import java.util.HashMap 4 | 5 | object JsonTest extends App { 6 | val map=new HashMap[String,String]() 7 | map.put("key", "value") 8 | println(JsonUtil.toJson(map)) 9 | } -------------------------------------------------------------------------------- /common/src/main/scala/com/msg/common/util/Md5.scala: -------------------------------------------------------------------------------- 1 | package com.msg.common.util 2 | 3 | object Md5{ 4 | 5 | def md5Hash(text: String) : String = java.security.MessageDigest.getInstance("MD5").digest(text.getBytes()).map(0xFF & _).map { "%02x".format(_) }.foldLeft(""){_ + _} 6 | 7 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # realtime-message-system 2 | 3 | It is an integrated publish-subscribe, point to point communication, pull, directional notification capabilities to provide timely, efficient and stable product push service message exchange 4 | 5 | 6 | [部署到好雨](http://app.goodrain.com/detail/34/ "一键部署") 7 | -------------------------------------------------------------------------------- /manager/mongoUtil.php: -------------------------------------------------------------------------------- 1 | mongo = new Mongo("$url"); 7 | $db = $this->mongo->selectDB("{$db_name}"); 8 | return $db->$collection; 9 | } 10 | 11 | } 12 | 13 | ?> -------------------------------------------------------------------------------- /manager/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 | # Overall structure 2 | 3 |  4 | 5 | # Manager 6 | Manger responsible for management topics, definitions 7 | 8 | #Push 9 | Push to define multiple client access protocols, such as websocket, longpoll, socketio ....; AKka actor used to manage each connection, a connection is a actor; 10 | 11 | #Region 12 | 13 | Region responsible topic partition, maintaining the connection status, message received, message exchange; http protocol which provides an interface to query each topic restfull inside information. -------------------------------------------------------------------------------- /manager/validateSession.php: -------------------------------------------------------------------------------- 1 | autoLogin($_COOKIE['id'], $_COOKIE['pass']); 9 | if($result == 0){ 10 | $session_user=$_SESSION["user"]; 11 | return; 12 | } 13 | } 14 | echo ""; 17 | } 18 | ?> -------------------------------------------------------------------------------- /manager/postData.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/actor/DeadLetterListener.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.actor 2 | 3 | import akka.actor.Actor 4 | import akka.actor.ActorLogging 5 | import akka.actor.DeadLetter 6 | import com.msg.common.model.Msg 7 | import com.msg.common.model.DeadMsg 8 | 9 | class DeadLetterListener extends Actor with ActorLogging { 10 | def receive = { 11 | case d: DeadLetter => { 12 | if (d.sender.toString.contains("ExRegion")) { 13 | d.message match { 14 | case msg: Msg => 15 | d.sender ! DeadMsg(msg.t, msg.r) 16 | case _ => 17 | } 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/seed/cluster/ClusterDiscovery.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.seed.cluster 2 | 3 | import akka.actor.ActorSystem 4 | import akka.actor.ExtendedActorSystem 5 | import akka.actor.ExtensionId 6 | import akka.actor.ExtensionIdProvider 7 | 8 | object ClusterDiscovery extends ExtensionId[ClusterDiscoveryImpl] with ExtensionIdProvider { 9 | 10 | override def lookup = ClusterDiscovery 11 | 12 | override def createExtension(system: ExtendedActorSystem) = new ClusterDiscoveryImpl(system) 13 | 14 | override def get(system: ActorSystem): ClusterDiscoveryImpl = super.get(system) 15 | 16 | } -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/actor/WebsoketCenter.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.actor 2 | 3 | import akka.actor.ActorLogging 4 | import akka.actor.Actor 5 | import com.msg.push.ws.PushWsServer 6 | import com.msg.push.Configuration 7 | 8 | class WebsoketCenter extends Actor with ActorLogging { 9 | 10 | override def preStart(): Unit = { 11 | val termrs = new PushWsServer(Configuration.newWebsocketUri, Configuration.newWebsocketPort, context.system) 12 | termrs.run() 13 | } 14 | 15 | def receive = { 16 | case msg: String => 17 | println("WebsoketCenter=" + msg) 18 | case _ => 19 | } 20 | } -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/actor/SocketCenter.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.actor 2 | 3 | import akka.actor.ActorLogging 4 | import akka.actor.Actor 5 | import com.msg.push.Configuration 6 | import akka.actor.Props 7 | import com.msg.push.socket.TcpSoketServer 8 | 9 | class SocketCenter extends Actor with ActorLogging { 10 | 11 | override def preStart(): Unit = { 12 | context.system.actorOf(Props(new TcpSoketServer(Configuration.socketIp, Configuration.socketPort)), "SoketServer") 13 | } 14 | 15 | def receive = { 16 | case msg: String => 17 | println("SocketCenter=" + msg) 18 | case _ => 19 | } 20 | } -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/actor/InitRegionBaseInfo.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.actor 2 | 3 | import akka.actor.Actor 4 | import scala.concurrent.duration._ 5 | import akka.actor.ActorLogging 6 | import com.msg.region.util.RegionInfoMongoHelper 7 | import com.msg.region.util.Constants 8 | 9 | class InitRegionBaseInfo extends Actor with ActorLogging { 10 | import context.dispatcher 11 | context.system.scheduler.schedule(1.milliseconds, 60.seconds, self, "init") 12 | def receive = { 13 | case "init" => 14 | RegionInfoMongoHelper.initTopicInfo(Constants.TOPIC_INFO) 15 | case _ => 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /push/src/main/java/com/msg/push/socketio/RepData.java: -------------------------------------------------------------------------------- 1 | package com.msg.push.socketio; 2 | 3 | public class RepData { 4 | String topic = ""; 5 | String msg = ""; 6 | 7 | public RepData(){ 8 | } 9 | public RepData(String t,String m){ 10 | this.topic=t; 11 | this.msg=m; 12 | } 13 | 14 | public String getTopic() { 15 | return topic; 16 | } 17 | 18 | public void setTopic(String topic) { 19 | this.topic = topic; 20 | } 21 | 22 | public String getMsg() { 23 | return msg; 24 | } 25 | 26 | public void setMsg(String msg) { 27 | this.msg = msg; 28 | } 29 | } -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/actor/SocketIoCenter.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.actor 2 | 3 | import akka.actor.ActorLogging 4 | import akka.actor.Actor 5 | import com.msg.push.socketio.SoketIoService 6 | import com.msg.push.Configuration 7 | 8 | class SocketIoCenter extends Actor with ActorLogging { 9 | 10 | override def preStart(): Unit = { 11 | val soketioServer = new SoketIoService(context.system) 12 | soketioServer.getSoketIoServer(Configuration.soketIoIp, Configuration.soketIoPort).start() 13 | } 14 | 15 | def receive = { 16 | case msg: String => 17 | println("SocketIoCenter=" + msg) 18 | case _ => 19 | } 20 | } -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/actor/InitRegionBaseInfo.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.actor 2 | 3 | import akka.actor.Actor 4 | import scala.concurrent.duration._ 5 | import akka.actor.ActorLogging 6 | import com.msg.push.util.RegionInfoMongoHelper 7 | import com.msg.push.util.Constants 8 | 9 | class InitRegionBaseInfo extends Actor with ActorLogging { 10 | import context.dispatcher 11 | context.system.scheduler.schedule(1.milliseconds, 60.seconds, self, "init") 12 | var num = 0 13 | def receive = { 14 | case "init" => 15 | RegionInfoMongoHelper.initAllRegionInfo(Constants.REGION_INFO) 16 | //RegionInfoMongoHelper.initTopicInfo(Constants.TOPIC_INFO) 17 | case _ => 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /push/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG,stdout 2 | log4j.logger.com.msg=DEBUG,stdout 3 | log4j.logger.com.goodrain=DEBUG,stdout 4 | 5 | # CONSOLE appender not used by default 6 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d %-50.50c{1} - %m%n 9 | 10 | # File appender %d [%-15.15t] %-5p %-30.30c{1} - %m%n 11 | log4j.appender.out=org.apache.log4j.DailyRollingFileAppender 12 | log4j.appender.out.layout=org.apache.log4j.PatternLayout 13 | log4j.appender.out.layout.ConversionPattern=%d %-20.20c{1} - %m%n 14 | log4j.appender.out.DatePattern='.'yyyy-MM-dd 15 | log4j.appender.out.file=log/akka-actor.log 16 | log4j.appender.out.append=true -------------------------------------------------------------------------------- /region/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG,stdout 2 | log4j.logger.com.msg=DEBUG,stdout 3 | log4j.logger.com.goodrain=DEBUG,stdout 4 | 5 | # CONSOLE appender not used by default 6 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d %-50.50c{1} - %m%n 9 | 10 | # File appender %d [%-15.15t] %-5p %-30.30c{1} - %m%n 11 | log4j.appender.out=org.apache.log4j.DailyRollingFileAppender 12 | log4j.appender.out.layout=org.apache.log4j.PatternLayout 13 | log4j.appender.out.layout.ConversionPattern=%d %-20.20c{1} - %m%n 14 | log4j.appender.out.DatePattern='.'yyyy-MM-dd 15 | log4j.appender.out.file=log/akka-actor.log 16 | log4j.appender.out.append=true -------------------------------------------------------------------------------- /manager/pullData.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/seed/streams/FlowBreaker.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.seed.streams 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean 4 | 5 | import akka.actor.Cancellable 6 | import akka.stream.scaladsl.Flow 7 | 8 | /** 9 | * Flow element with a materialized value of type `Cancellable` that allows 10 | * cancelling upstream and completing downstream flow on demand. 11 | */ 12 | object FlowBreaker { 13 | def apply[T]: Flow[T, T, Cancellable] = { 14 | val cancellable = new Cancellable { 15 | private val cancelled = new AtomicBoolean() 16 | override def cancel() = cancelled.compareAndSet(false, true) 17 | override def isCancelled() = cancelled.get 18 | } 19 | Flow[T].takeWhile(_ ⇒ !cancellable.isCancelled).mapMaterializedValue(_ ⇒ cancellable) 20 | } 21 | } -------------------------------------------------------------------------------- /docs/user-guide/application.md: -------------------------------------------------------------------------------- 1 | #What is Application? 2 | 3 | Applications on behalf of a project, or a functional module;Each application belongs to a company or a department. 4 | 5 | #What is Entity? 6 | 7 | Entity represents a theme or a topic,Each entity belongs to an organization;It contains name、exchange method、pattern matching, message template, persistence, state, state broadcast attributes.When create an entity, the system will generate a token, the user through the organization code, the topic name and token to subscribe to a topic 8 | 9 | #Application and Entity RelationShip 10 | 11 |  12 | 13 | An application has more than one entity;Each entity may use different ways to define the message 14 | 15 | #How to create Application? 16 |  17 | 18 | #How to create Entity? 19 |  20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /manager/css/signin.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 40px; 3 | padding-bottom: 40px; 4 | background-color: #eee; 5 | } 6 | 7 | .form-signin { 8 | max-width: 330px; 9 | padding: 15px; 10 | margin: 0 auto; 11 | } 12 | .form-signin .form-signin-heading, 13 | .form-signin .checkbox { 14 | margin-bottom: 10px; 15 | } 16 | .form-signin .checkbox { 17 | font-weight: normal; 18 | } 19 | .form-signin .form-control { 20 | position: relative; 21 | height: auto; 22 | -webkit-box-sizing: border-box; 23 | -moz-box-sizing: border-box; 24 | box-sizing: border-box; 25 | padding: 10px; 26 | font-size: 16px; 27 | } 28 | .form-signin .form-control:focus { 29 | z-index: 2; 30 | } 31 | .form-signin input[type="email"] { 32 | margin-bottom: 5px; 33 | border-bottom-right-radius: 0; 34 | border-bottom-left-radius: 0; 35 | } 36 | .form-signin input[type="password"] { 37 | margin-bottom: 10px; 38 | border-top-left-radius: 0; 39 | border-top-right-radius: 0; 40 | } 41 | -------------------------------------------------------------------------------- /push/src/main/scala/com/msg/push/socket/TcpSoketServer.scala: -------------------------------------------------------------------------------- 1 | package com.msg.push.socket 2 | 3 | import akka.actor.Actor 4 | import akka.io.Tcp 5 | import akka.io.IO 6 | import java.net.InetSocketAddress 7 | import akka.actor.Props 8 | import akka.actor.ActorRef 9 | 10 | class TcpSoketServer(host: String, port: Int) extends Actor { 11 | private var reactors = Map[Int, ActorRef]() 12 | import Tcp._ 13 | import context.system 14 | if (host.isEmpty()) { 15 | IO(Tcp) ! Bind(self, new InetSocketAddress(port)) 16 | } else { 17 | IO(Tcp) ! Bind(self, new InetSocketAddress(host, port)) 18 | } 19 | 20 | def receive = { 21 | case b @ Bound(localAddress) => 22 | case CommandFailed(x: Bind) => 23 | context stop self 24 | case c @ Connected(remote, local) => 25 | val handler = context.actorOf(Props[ListeningHander]) 26 | val connection = sender() 27 | connection ! Register(handler) 28 | } 29 | } -------------------------------------------------------------------------------- /manager/head.php: -------------------------------------------------------------------------------- 1 |
22 | 25 | -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/actor/MsgObject.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.actor 2 | 3 | import com.msg.common.model.MData 4 | import com.msg.common.model.ReplySubNum 5 | import com.msg.common.model.VisitMsg 6 | import akka.cluster.sharding.ShardRegion 7 | import com.msg.region.Configuration 8 | 9 | 10 | object MsgOject { 11 | 12 | val extractEntityId: ShardRegion.ExtractEntityId = { 13 | case msg @ MData(sender, receiver, msginfo, isSave) => (receiver, msg) 14 | case reply @ ReplySubNum(parentTopic, topic, num) => (parentTopic, reply) 15 | case visitMsg @ VisitMsg(topic, start, end) => (topic, visitMsg) 16 | } 17 | val extractShardId: ShardRegion.ExtractShardId = msg => msg match { 18 | case MData(sender, receiver, msginfo, isSave) => (receiver.hashCode % Configuration.modNum).toString 19 | case ReplySubNum(parentTopic, topic, num) => (parentTopic.hashCode % Configuration.modNum).toString 20 | case VisitMsg(topic, start, end) => (topic.hashCode() % Configuration.modNum).toString() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/actor/DeadLetterListener.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.actor 2 | 3 | import akka.actor.Actor 4 | import akka.actor.ActorLogging 5 | import akka.actor.DeadLetter 6 | import com.msg.common.model.Msg 7 | import com.msg.common.model.DeadMsg 8 | import com.msg.region.util.RegionInfoMongoHelper 9 | import com.msg.region.util.Constants 10 | 11 | class DeadLetterListener extends Actor with ActorLogging { 12 | def receive = { 13 | case d: DeadLetter => { 14 | if (d.sender.toString.contains("ExRegion")) { 15 | d.message match { 16 | case msg: Msg => 17 | d.sender ! DeadMsg(msg.t, msg.r) 18 | case _ => 19 | } 20 | } 21 | if (d.recipient.toString().contains("MsgExchangeSystem")) { 22 | val address = d.recipient.toString().split("-") 23 | if (address.length > 2) { 24 | val add = address(1).replace("%3A", ":").replace("%2F", "/").replace("%40", "@") 25 | val region = add + "/user/exchange/receivedata" 26 | RegionInfoMongoHelper.deleteRegion(Constants.REGION_INFO, region) 27 | } 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/seed/cluster/ClusterDiscoveryImpl.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.seed.cluster 2 | 3 | import akka.actor.ExtendedActorSystem 4 | import akka.actor.Extension 5 | import akka.cluster.Cluster 6 | import akka.http.ClientConnectionSettings 7 | import com.msg.region.seed.etcd.EtcdClient 8 | 9 | class ClusterDiscoveryImpl(extendedSystem: ExtendedActorSystem) extends Extension { 10 | 11 | private implicit val system = extendedSystem 12 | 13 | val discoverySettings = ClusterDiscoverySettings.load(system.settings.config) 14 | 15 | val httpClientSettings = ClientConnectionSettings(system).copy( 16 | connectingTimeout = discoverySettings.etcdConnectionTimeout, 17 | idleTimeout = discoverySettings.etcdRequestTimeout) 18 | 19 | private val etcd = EtcdClient(discoverySettings.etcdHost, discoverySettings.etcdPort, Some(httpClientSettings)) 20 | 21 | private val cluster = Cluster(system) 22 | 23 | private val discovery = system.actorOf(ClusterDiscoveryActor.props(etcd, cluster, discoverySettings)) 24 | 25 | def start(): Unit = { 26 | discovery ! ClusterDiscoveryActor.Start 27 | } 28 | 29 | start 30 | 31 | } -------------------------------------------------------------------------------- /docs/feature.md: -------------------------------------------------------------------------------- 1 | # Design goals 2 | 3 | To provide users with multi-scene news exchange service 4 | Allow the exchange of messages to become more efficient, faster and more stable. Allowing users easier and more convenient. 5 | 6 | # SiX Features 7 | 8 | ## Support a variety of scenarios 9 | 10 | It supports publish-subscribe, point to point communication, pull pull notification and orientation 11 | 12 | ## Flexible Configuration 13 | 14 | Users can customize the entity; entity or person may be the subject and there is a state of 15 | 16 | ## Message efficient and reliable 17 | 18 | Actor event-based system model, all messages pure asynchronous, non-blocking, support 1000w / min or more push message, the message accurately reach 99.99% 19 | 20 | ## Dynamic stretching 21 | 22 | The system supports dynamic partition and extended entity; and storing messages in real time to ensure that the message of disaster recovery 23 | 24 | ## Support multi-terminal access 25 | 26 | Enabling developers to easily use; support multi-terminal access, support for multiple protocols (socket, web) 27 | 28 | ## Statistical functions 29 | 30 | Provides instant messaging statistics, the amount of transmission, including online subscriptions, etc. 31 | -------------------------------------------------------------------------------- /manager/apply.php: -------------------------------------------------------------------------------- 1 | &$value ) { 9 | if (! empty ( $_POST [$key] )) 10 | $value = $_POST [$key]; 11 | } 12 | } 13 | 14 | public function updateStat($code,$_stat){ 15 | session_start(); 16 | $session_user = $_SESSION["user"]; 17 | $user=$session_user['email']; 18 | require_once ("mongoUtil.php"); 19 | $mongo = new Mongo_Util (); 20 | $collection = $mongo->getMongoDb('msg-center','topic_info'); 21 | 22 | $record = array (); // 字段存储列表 23 | $record ['code'] = $code; // 业务名称英文简写 24 | $value = array("\$set" => array ("check_status" =>1)); 25 | try { 26 | $collection->update ($record,$value); 27 | return "0"; 28 | } catch ( MongoCursorException $e ) { 29 | return "2"; 30 | } 31 | } 32 | } 33 | 34 | $method = $_POST ["method"]; 35 | $code = $_POST ["code"]; 36 | $topic = new apply(); 37 | $topic->setValues(); 38 | switch ($method) { 39 | case "updateStat": 40 | echo $topic->updateStat($code,$stat); 41 | break; 42 | } 43 | 44 | 45 | ?> -------------------------------------------------------------------------------- /manager/apply_init.php: -------------------------------------------------------------------------------- 1 | &$value ) { 9 | if (! empty ( $_POST [$key] )) 10 | $value = $_POST [$key]; 11 | } 12 | } 13 | 14 | public function updateStat($code,$_stat){ 15 | session_start(); 16 | $session_user = $_SESSION["user"]; 17 | $user=$session_user['email']; 18 | require_once ("mongoUtil.php"); 19 | $mongo = new Mongo_Util (); 20 | $collection = $mongo->getMongoDb('msg-center','topic_info'); 21 | 22 | $record = array (); // 字段存储列表 23 | $record ['code'] = $code; // 业务名称英文简写 24 | $value = array("\$set" => array ("check_status" =>1)); 25 | try { 26 | $collection->update ($record,$value); 27 | return "0"; 28 | } catch ( MongoCursorException $e ) { 29 | return "2"; 30 | } 31 | } 32 | } 33 | 34 | $method = $_GET ["method"]; 35 | $code = $_GET ["code"]; 36 | $topic = new apply(); 37 | $topic->setValues(); 38 | switch ($method) { 39 | case "updateStat": 40 | echo $topic->updateStat($code,$stat); 41 | break; 42 | } 43 | 44 | 45 | ?> -------------------------------------------------------------------------------- /region/src/main/scala/com/msg/region/seed/etcd/EtcdJsonProtocol.scala: -------------------------------------------------------------------------------- 1 | package com.msg.region.seed.etcd 2 | 3 | import java.time.ZonedDateTime 4 | import java.time.format.DateTimeFormatter 5 | 6 | import spray.json._ 7 | 8 | /** 9 | * Provides Spray JSON format implicits for `etcd` messages. 10 | */ 11 | object EtcdJsonProtocol extends DefaultJsonProtocol { 12 | 13 | /** Spray JSON format for [[EtcdError]] case class. */ 14 | implicit val etcdErrorFormat = jsonFormat4(EtcdError.apply) 15 | 16 | /** Spray JSON format for `java.time.ZonedDateTime` represented as `ISO_ZONED_DATE_TIME` string*/ 17 | implicit object InstantJsonFormat extends RootJsonFormat[ZonedDateTime] { 18 | val formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME 19 | 20 | def write(i: ZonedDateTime) = 21 | JsString(formatter.format(i)) 22 | 23 | def read(value: JsValue) = value match { 24 | case JsString(s) ⇒ ZonedDateTime.from(formatter.parse(s)) 25 | case _ ⇒ deserializationError("string expected") 26 | } 27 | } 28 | 29 | /** Spray JSON format for [[EtcdNode]] case class. */ 30 | implicit val etcNodeFormat: JsonFormat[EtcdNode] = lazyFormat(jsonFormat7(EtcdNode)) 31 | 32 | /** Spray JSON format for [[EtcdResponse]] case class. */ 33 | implicit val etcdResponseFormat = jsonFormat3(EtcdResponse) 34 | } -------------------------------------------------------------------------------- /common/src/main/scala/com/msg/common/model/QueueEntity.scala: -------------------------------------------------------------------------------- 1 | package com.msg.common.model 2 | 3 | import java.util.HashSet 4 | import scala.concurrent.forkjoin.ThreadLocalRandom 5 | import java.util.ArrayList 6 | import java.util.HashMap 7 | 8 | case class QueueInfo(topic: String, address: String, category: Int, status: Int, checkTime: Int) 9 | 10 | object QueueEntity { 11 | private val queueInfoMap = new HashMap[String, HashMap[String, QueueInfo]] 12 | def addQueueInfo(topic: String, queueInfo: QueueInfo) = { 13 | var map = queueInfoMap.get(topic) 14 | if (map == null) { 15 | map = new HashMap[String, QueueInfo] 16 | map.put(queueInfo.address + queueInfo.topic, queueInfo) 17 | queueInfoMap.put(topic, map) 18 | } else { 19 | map.put(queueInfo.address + queueInfo.topic, queueInfo) 20 | } 21 | } 22 | 23 | def getQueueInfo(topic: String): HashMap[String, QueueInfo] = { 24 | queueInfoMap.get(topic) 25 | } 26 | 27 | def removeQueueInfo(topic: String, queueInfo: QueueInfo) = { 28 | val map = queueInfoMap.get(topic) 29 | if (map != null) { 30 | map.remove(queueInfo.address + queueInfo.topic) 31 | } 32 | } 33 | 34 | def getAllQueue(): HashMap[String, HashMap[String, QueueInfo]] = { 35 | queueInfoMap 36 | } 37 | } -------------------------------------------------------------------------------- /manager/5000.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 || 应用代码 | " 16 | ."".$_POST ["code"]." | " 17 | ."
| 实体名称 | " 20 | ."".$_POST ["topicName"]." | " 21 | ."
| 通知名称 | " 24 | ."".$key." | " 25 | ."
| 通知内容 | " 28 | ."" 29 | ." |
| 描述 | " 32 | ."".$notify['desc']." | " 33 | ."
| 创建时间 | " 36 | ."".$notify['create_time']." | " 37 | ."
| 应用代码 | " 16 | ."".$_POST ["code"]." | " 17 | ."
| 实体名称 | " 20 | ."".$_POST ["topicName"]." | " 21 | ."
| 模版名称 | " 24 | ."".$key." | " 25 | ."
| 模板内容 | " 28 | ."" 29 | ." |
| 模板描述 | " 32 | ."".$template['desc']." | " 33 | ."
| 创建时间 | " 36 | ."".$template['create_time']." | " 37 | ."
| 版本名称 | 18 |版本时间 | 19 |20 | |
|---|---|---|
| websoket.js | 25 |2016-03-30 | 26 |下载 | 27 |
| 地址 | 48 |版本时间 | 49 |
|---|---|
| ws://有的正式使用地址:0000/websocket | 54 |2016-03-30 | 55 |
| ws://有的正式使用地址:0001/websocket | 58 |2016-03-30 | 59 |
| 应用代码 | " 48 | ."".$_POST ["code"]." | " 49 | ."
| 实体名称 | " 52 | ."".$key." | " 53 | ."
| Token | " 56 | ."".$topic["key"]." | " 57 | ."
| 交换方式 | " 60 | ."".$is_notify." | " 61 | ."
| 模式匹配 | " 65 | ."".$regx." | " 66 | ."
| 匹配参数 | " 69 | ."".$topic['regx_param']." | " 70 | ."
| 模板渲染 | " 73 | ."".$is_replace." | " 74 | ."
| 模板名称匹配 | " 77 | ."".$topic["template_regx"]." | " 78 | ."
| 定向通知匹配 | " 83 | ."".$topic["notify_regx"]." | " 84 | ."
| 持久化 | " 88 | ."".$store." | " 89 | ."
| 持久化类型 | " 93 | ."".$smethod." | " 94 | ."
| 持久化".$smethod." | " 97 | ."".$topic["store_num"]." | " 98 | ."
| 发送条数 | " 101 | ."".$topic["send_num"]." | " 102 | ."
| 订阅条数 | " 105 | ."".$topic["sub_num"]." | " 106 | ."
| 状态 | " 110 | ."".$stat." | " 111 | ."
| 状态通知 | " 114 | ."".$broad." | " 115 | ."
Defined resources:
85 |是一款集成发布订阅、点对点通讯、pull拉取、定向通知功能,为用户提供及时、高效、稳定的消息交换推送服务产品
85 |让消息交换变得更高效、更快捷、更稳定。让使用者变得更容易、更方便。
91 | 92 |支持发布订阅、点对点通讯、pull拉取和定向通知
98 |用户可以自定义实体;实体可以是主题或者是人并且是有状态的
102 |系统基于Actor事件模型,所有消息纯异步,无阻塞,支持1000w/分钟以上的消息推送,消息准确到达率99.99%
106 |系统中实体支持动态分区和扩容;并对消息进行实时存储,保证消息的容灾恢复
110 |方便开发者使用;支持多终端接入,支持多种协议(socket、web)
114 |提供消息的即时统计,包括发送量、在线订阅数等
118 |