mirror of
https://gitee.com/farsunset/cim.git
synced 2025-06-16 15:19:56 +08:00
版本升级到4.0.0
参见更新日志
This commit is contained in:
parent
57ae7a2426
commit
756ff96b8a
36
README.md
36
README.md
@ -1,5 +1,9 @@
|
||||
#### 项目介绍
|
||||
CIM项目是基于mina或者netty框架下的推送系统,我们平常使用第三方的推送SDK,如极光推送,百度推送,小米推送,以及腾讯信鸽等来支撑自己的移动端的业务,或许有一些用户自己实现即时通讯系统的需求,那么CIM为您提供了一个解决方案或者思路,目前CIM支持 websocket,android,ios,桌面应用,系统应用等多端接入支持,目前CIM服务端使用springboot搭建仅仅拥有消息推送的功能,关于数据缓存与持久化都需要使用者自己开发,但是配备了比较完整的使用文档。最后希望CIM能为您带来一些价值。
|
||||
CIM是一套完善的消息推送框架,可应用于信令推送,即时聊天,移动设备指令推送等领域。开发者可沉浸于业务开发,不用关心消息通道链接,消息编解码协议等繁杂处理。
|
||||
CIM采用业内主流开源技术构建,易于扩展和使用,并完美支持集群部署支持海量链接,目前支持websocket,android,ios,桌面应用,系统应用等多端接入持,可应用于移动应用,物联网,智能家居,嵌入式开发,桌面应用,WEB应用即时消服务。
|
||||
用时7年 基于CIM的项目已经运行在全国各个地方,包括上司公司,各地政务系统,警务系统等服务于上百家客户,希望CIM也能为您带来价值,如果您也希望加入项目成为贡献者,请联系我。
|
||||
#### 在线文档
|
||||
## [https://www.yuque.com/yuanfangxiyang/ma4ytb](https://www.yuque.com/yuanfangxiyang/ma4ytb)
|
||||
|
||||
---
|
||||
## 以下是基于CIM开发的2款产品,并不开源!!!
|
||||
@ -20,18 +24,6 @@ CIM项目是基于mina或者netty框架下的推送系统,我们平常使用
|
||||
|
||||
---
|
||||
|
||||
#### 目录说明
|
||||
|
||||
1.cim-use-examples是各个客户端使用示例
|
||||
|
||||
2.cim-client-sdk 是各个客户端的SDK源码
|
||||
|
||||
3.cim-server-sdk 是服务端SDK源码,分为 mina和netty 两个版本,二者任选其一
|
||||
|
||||
4.cim-boot-server是springboot服务端工程源码,使用Idea工具开发
|
||||
|
||||
其中所有的sdk均为IntelliJ IDEA工程,Maven打包成jar导出引入到对应的客户端或服务端工程
|
||||
|
||||
|
||||
#### 功能预览
|
||||
|
||||
@ -94,4 +86,22 @@ CIM项目是基于mina或者netty框架下的推送系统,我们平常使用
|
||||
4.所有sdk均使用maven构建,idea工具开发,发现多处代码单词拼写错误,使用阿里语法检测组件优化了部分代码
|
||||
|
||||
5.同步修改了文档
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------
|
||||
版本:4.0.0/时间:2021-04-30
|
||||
|
||||
1.websocket支持心跳机制
|
||||
|
||||
2.删除mina版本服务端sdk 、删除java版本客户端sdk
|
||||
|
||||
3.cim-boot-server重写、加入了推送集群实现。cim-android-client重写演示了更丰富的功能
|
||||
|
||||
4.客户端上行数据参数名修改
|
||||
account > uid
|
||||
device > deviceName
|
||||
CR > PONG
|
||||
|
||||
5.文档放到语雀在线文档
|
||||
6.其他30多处多处代码优化
|
||||
|
||||
|
@ -13,6 +13,16 @@
|
||||
</sourceRoots>
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="jpa" name="JPA">
|
||||
<configuration>
|
||||
<setting name="validation-enabled" value="true" />
|
||||
<setting name="provider-name" value="Hibernate" />
|
||||
<datasource-mapping>
|
||||
<factory-entry name="entityManagerFactory" />
|
||||
</datasource-mapping>
|
||||
<naming-strategy-map />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
@ -25,63 +35,114 @@
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.12.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.12.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.13.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.13.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.30" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.25" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.10.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.10.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.10.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.10.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.31" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.31" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.31" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.18.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.27" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.11.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.11.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.11.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.44" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.glassfish:jakarta.el:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.44" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-freemarker:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.31" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.4.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.4.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.0.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-jpa:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.4.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.transaction:jakarta.transaction-api:1.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.persistence:jakarta.persistence-api:2.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate:hibernate-core:5.4.29.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.javassist:javassist:3.27.0-GA" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: antlr:antlr:2.7.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss:jandex:2.2.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.dom4j:dom4j:2.1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.common:hibernate-commons-annotations:5.1.2.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.glassfish.jaxb:jaxb-runtime:2.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.glassfish.jaxb:txw2:2.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.istack:istack-commons-runtime:3.0.11" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-jpa:2.4.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.4.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-orm:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aspects:5.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-boot-starter:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-oas:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-annotations:2.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger.core.v3:swagger-models:2.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-core:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.github.classgraph:classgraph:4.8.83" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webmvc:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-webflux:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:3.0.0" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.mapstruct:mapstruct:1.3.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-data-rest:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:3.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-freemarker:2.2.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.29" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.2.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:2.0.0.RELEASE" level="project" />
|
||||
<orderEntry type="module-library">
|
||||
<library name="Maven: com.farsunset:cim-server-sdk:3.8.0">
|
||||
<library name="Maven: com.farsunset:cim-server-sdk:4.0.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/libs/cim-server-sdk-netty-3.8.0.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/libs/cim-server-sdk-netty-4.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="library" name="Maven: org.apache.mina:mina-core:2.1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec-http:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.35.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.8.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.22" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec-http:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.62.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.protobuf:protobuf-java:3.11.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: cn.teaey.apns4j:apns4j:1.1.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.6" level="project" />
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,8 +3,235 @@
|
||||
<component name="AnalysisUIOptions">
|
||||
<option name="GROUP_BY_SEVERITY" value="true" />
|
||||
</component>
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="bed47126-03b3-4370-a6c1-08503492974f" name="Default Changelist" comment="" />
|
||||
<list default="true" id="bed47126-03b3-4370-a6c1-08503492974f" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/jar.bat" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/jar.sh" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/libs/cim-server-sdk-netty-4.0.0.jar" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/run.bat" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/run.sh" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/BootApplication.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/handler/BindHandler.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/handler/annotation/CIMHandler.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/message/BindMessageListener.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/message/PushMessageListener.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/redis/KeyValueRedisTemplate.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/redis/SignalRedisTemplate.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/config/RedisConfig.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/config/SwaggerConfig.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/mvc/controller/api/APNsController.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/SessionService.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/impl/SessionServiceImpl.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/resources/apns/app.p12" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/resources/logback-spring.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../3.8.0.VERSION" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../README.md" beforeDir="false" afterPath="$PROJECT_DIR$/../README.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cim-boot-server.iml" beforeDir="false" afterPath="$PROJECT_DIR$/cim-boot-server.iml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cim-boot-server.ipr" beforeDir="false" afterPath="$PROJECT_DIR$/cim-boot-server.ipr" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cim-boot-server.iws" beforeDir="false" afterPath="$PROJECT_DIR$/cim-boot-server.iws" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/libs/cim-server-sdk-mina-3.8.0.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/libs/cim-server-sdk-netty-3.8.0.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/ServerLauncher.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/admin/controller/NavigationController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/mvc/controller/admin/NavigationController.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/admin/controller/SessionController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/mvc/controller/admin/SessionController.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/api/controller/MessageController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/mvc/controller/api/MessageController.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/config/CIMConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/config/CIMConfig.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/handler/BindHandler.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/handler/ClosedHandler.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/push/CIMMessagePusher.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/push/CIMMessagePusher.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/push/DefaultMessagePusher.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/push/DefaultMessagePusher.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/repository/SessionRepository.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/repository/SessionRepository.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/ApnsService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/APNsService.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/CIMSessionService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/constants/Constants.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/impl/CIMSessionServiceImpl.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/impl/JavaApnsServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/farsunset/cim/service/impl/APNsServiceImpl.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/resources/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/application.properties" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/resources/i18n/messages.properties" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/i18n/messages.properties" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/resources/page/console/nav.html" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/page/console/nav.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/resources/page/console/session/manage.html" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/page/console/session/manage.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/resources/page/console/webclient/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/page/console/webclient/index.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/resources/static/js/cim/cim.web.sdk.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/static/js/cim/cim.web.sdk.js" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk-libs/android/cim-android-sdk-3.8.2.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk-libs/java/cim-java-sdk-3.8.0.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk-libs/js/cim.web.sdk.js" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk-libs/js/cim.web.sdk.js" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/pom.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMCacheManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMCacheManager.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMConnectorManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMConnectorManager.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMEventBroadcastReceiver.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMEventBroadcastReceiver.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMEventListener.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMEventListener.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMListenerManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMListenerManager.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMPushManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/CIMPushManager.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/coder/ClientMessageDecoder.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/coder/ClientMessageDecoder.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/constant/CIMConstant.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/constant/CIMConstant.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/logger/CIMLogger.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/logger/CIMLogger.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/Message.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/Message.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/Ping.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/Ping.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/Pong.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/Pong.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/ReplyBody.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/ReplyBody.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/SentBody.java" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-android-sdk/src/main/java/com/farsunset/cim/sdk/android/model/SentBody.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-ios-sdk/CIMKit/CIMKit/Handler/CIMSendMessageData.m" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-client-sdk/cim-ios-sdk/CIMKit/CIMKit/Handler/CIMSendMessageData.m" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/cim-java-sdk.iml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/jar.bat" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/jar.sh" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/pom.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMCacheManager.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMConnectorManager.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMEventBroadcastReceiver.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMEventListener.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMListenerManager.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMPushManager.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/CIMPushService.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/coder/CIMLogger.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/coder/ClientMessageDecoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/coder/ClientMessageEncoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/constant/CIMConstant.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/HeartbeatRequest.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/HeartbeatResponse.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/Intent.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/Message.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/Protobufable.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/ReplyBody.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/client/model/SentBody.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/model/proto/Message.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/model/proto/MessageProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/model/proto/ReplyBody.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/model/proto/ReplyBodyProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/model/proto/SentBody.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-sdk/cim-java-sdk/src/main/java/com/farsunset/cim/sdk/model/proto/SentBodyProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-vue/Auto.vue" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-vue/websocket/cim.web.sdk.js" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-vue/websocket/message.js" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-vue/websocket/replybody.js" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-client-vue/websocket/sentbody.js" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/cim-server-sdk-mina.iml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/jar.bat" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/jar.sh" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/pom.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/coder/AppMessageCodecFactory.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/coder/AppMessageDecoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/coder/AppMessageEncoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/coder/WebMessageCodecFactory.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/coder/WebMessageDecoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/coder/WebMessageEncoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/constant/CIMConstant.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/handler/WebsocketHandler.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/CIMSession.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/HandshakerResponse.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/HeartbeatRequest.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/HeartbeatResponse.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/Message.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/ReplyBody.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/SentBody.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/Transportable.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/Message.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/MessageProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/ReplyBody.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/ReplyBodyProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/SentBody.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/SentBodyProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/Session.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-mina/src/main/java/com/farsunset/cim/sdk/server/model/proto/SessionProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/cim-server-sdk-netty.iml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/jar.bat" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/jar.sh" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/pom.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/coder/AppMessageDecoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/coder/AppMessageEncoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/coder/WebMessageDecoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/coder/WebMessageEncoder.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/constant/CIMConstant.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/handler/CIMNioSocketAcceptor.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/handler/CIMRequestHandler.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/handler/HeartbeatHandler.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/CIMSession.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/HeartbeatRequest.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/HeartbeatResponse.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/Message.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/ReplyBody.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/SentBody.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/Transportable.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/Message.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/MessageProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/ReplyBody.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/ReplyBodyProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/SentBody.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/SentBodyProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/Session.proto" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-server-sdk/cim-server-sdk-netty/src/main/java/com/farsunset/cim/sdk/server/model/proto/SessionProto.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.gitignore" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/caches/build_file_checksums.ser" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/caches/build_file_checksums.ser" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/caches/gradle_models.ser" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/encodings.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/gradle.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/misc.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/modules.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/modules.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/runConfigurations.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/.idea/vcs.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/.gitignore" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/build.gradle" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/libs/cim-android-sdk-3.8.2.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/proguard-rules.pro" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/proguard-rules.pro" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/AndroidManifest.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/AndroidManifest.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/adapter/MessageTimeDescComparator.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/adapter/SystemMsgListViewAdapter.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/app/CIMMonitorActivity.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/app/Constant.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/receiver/CIMPushManagerReceiver.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/ui/LoginActivity.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/ui/SplashActivity.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/java/com/farsunset/ichat/example/ui/SystemMessageActivity.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/color/login_text_button_selector.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/icon.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/login_bg.jpg" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/login_default_avatar.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/login_input.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_common_btn_blue_bg_pressed.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_common_btn_blue_unpressed.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_header_bar_bg.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_header_btn_back_normal.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_header_btn_back_press.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_msgbox_bg_nor.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_msgbox_bg_pressed.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/skin_msgbox_bg_top.9.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable-hdpi/splash_bg.jpg" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable/common_button_blue.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable/common_msgbox_bg.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/drawable/top_back_left_selector.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/layout/activity_login.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/layout/activity_login.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/layout/activity_splansh.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/layout/activity_system_chat.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/layout/item_chat_sysmsg.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/layout/layout_global_top_header.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/values/colors.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/values/colors.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/values/strings.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/values/strings.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/app/src/main/res/values/styles.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/build.gradle" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradle.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradle.properties" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradlew" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradlew" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradlew.bat" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/gradlew.bat" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-android/settings.gradle" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-java/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-java/cim-client-java.iml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-java/cim-java-client.iml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-java/libs/cim-java-sdk-3.8.0.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-java/pom.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-java/src/main/java/CIMJavaClient.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-web/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-web/index.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../cim-use-examples/cim-client-web/js/cim/cim.web.sdk.js" beforeDir="false" afterPath="$PROJECT_DIR$/../cim-use-examples/cim-client-web/js/cim/cim.web.sdk.js" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../doc/AndroidSDK使用文档.doc" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../doc/IOS或PC客户端等SDK开发文档.doc" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../doc/JavaSDK使用文档.doc" beforeDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
@ -20,7 +247,21 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="GitSEFilterConfiguration">
|
||||
<file-type-list>
|
||||
<filtered-out-file-type name="LOCAL_BRANCH" />
|
||||
<filtered-out-file-type name="REMOTE_BRANCH" />
|
||||
<filtered-out-file-type name="TAG" />
|
||||
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
|
||||
</file-type-list>
|
||||
</component>
|
||||
<component name="ProjectId" id="1PxWQToGq56jcmMz176UjXWLSaU" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
@ -30,6 +271,7 @@
|
||||
<property name="RequestMappingsPanelOrder1" value="1" />
|
||||
<property name="RequestMappingsPanelWidth0" value="75" />
|
||||
<property name="RequestMappingsPanelWidth1" value="75" />
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="aspect.path.notification.shown" value="true" />
|
||||
@ -42,19 +284,42 @@
|
||||
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||
<property name="nodejs_package_manager_path" value="npm" />
|
||||
<property name="settings.editor.selected.configurable" value="configurable.group.appearance" />
|
||||
<property name="show.migrate.to.gradle.popup" value="false" />
|
||||
</component>
|
||||
<component name="ReactorSettings">
|
||||
<option name="notificationShown" value="true" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\Administrator\Documents\gitee-cim\cim-boot-server\lib" />
|
||||
<recent name="$PROJECT_DIR$/lib" />
|
||||
<recent name="C:\Users\Administrator\Documents\cim\cim-boot-server\cim-boot-server\cim-boot-server" />
|
||||
<recent name="C:\Users\Administrator\Documents\cim\cim-boot-server\cim-boot-server\cim-boot-server\src" />
|
||||
<recent name="$PROJECT_DIR$" />
|
||||
<recent name="$PROJECT_DIR$/libs" />
|
||||
<recent name="$PROJECT_DIR$/src/main/resources" />
|
||||
<recent name="$PROJECT_DIR$/src/main/java/com/farsunset/cim/component" />
|
||||
<recent name="$PROJECT_DIR$/src/main/java/com/farsunset/cim/handler" />
|
||||
</key>
|
||||
<key name="CopyClassDialog.RECENTS_KEY">
|
||||
<recent name="com.farsunset.cim.config" />
|
||||
<recent name="com.farsunset.cim.mvc.controller.admin" />
|
||||
<recent name="com.farsunset.cim.constants" />
|
||||
<recent name="com.farsunset.cim.component.redis" />
|
||||
<recent name="com.farsunset.cim.service.impl" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="ServerLauncher" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
|
||||
<configuration default="true" type="ArquillianJUnit" factoryName="" nameIsGenerated="true">
|
||||
<option name="arquillianRunConfiguration">
|
||||
<value>
|
||||
<option name="containerStateName" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="TEST_OBJECT" value="class" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="BootApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
|
||||
<module name="cim-boot-server" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
@ -62,17 +327,18 @@
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="SPRING_BOOT_MAIN_CLASS" value="com.farsunset.cim.ServerLauncher" />
|
||||
<option name="SPRING_BOOT_MAIN_CLASS" value="com.farsunset.cim.BootApplication" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Spring Boot.ServerLauncher" />
|
||||
<item itemvalue="Spring Boot.BootApplication" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
@ -104,99 +370,16 @@
|
||||
<workItem from="1579226829168" duration="8852000" />
|
||||
<workItem from="1583472574255" duration="526000" />
|
||||
<workItem from="1583473153031" duration="15009000" />
|
||||
<workItem from="1618489559220" duration="4137000" />
|
||||
<workItem from="1619013470791" duration="41000" />
|
||||
<workItem from="1619014134954" duration="548000" />
|
||||
<workItem from="1619185841584" duration="14228000" />
|
||||
<workItem from="1619619256370" duration="6445000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="2" />
|
||||
</component>
|
||||
<component name="WindowStateProjectService">
|
||||
<state x="609" y="345" key="#com.intellij.fileTypes.FileTypeChooser" timestamp="1583567210548">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state x="609" y="345" key="#com.intellij.fileTypes.FileTypeChooser/0.23.1920.1057@0.23.1920.1057" timestamp="1583567210548" />
|
||||
<state x="645" y="287" key="#com.intellij.openapi.updateSettings.impl.PluginUpdateInfoDialog" timestamp="1583472646530">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state x="645" y="287" key="#com.intellij.openapi.updateSettings.impl.PluginUpdateInfoDialog/0.23.1920.1057@0.23.1920.1057" timestamp="1583472646530" />
|
||||
<state x="627" y="209" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog" timestamp="1579149988674">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="627" y="209" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog/0.0.1920.1040@0.0.1920.1040" timestamp="1579149988674" />
|
||||
<state x="690" y="218" key="FileChooserDialogImpl" timestamp="1579230010253">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="690" y="218" key="FileChooserDialogImpl/0.0.1920.1040@0.0.1920.1040" timestamp="1579230010253" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.bottom" timestamp="1583567568644">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.0.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696749" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.bottom/0.23.1920.1057@0.23.1920.1057" timestamp="1583567568644" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.center" timestamp="1583567568644">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.0.center/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696749" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.center/0.23.1920.1057@0.23.1920.1057" timestamp="1583567568644" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.left" timestamp="1583567568643">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.0.left/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696749" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.left/0.23.1920.1057@0.23.1920.1057" timestamp="1583567568643" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.right" timestamp="1583567568644">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.0.right/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696749" />
|
||||
<state width="1870" height="403" key="GridCell.Tab.0.right/0.23.1920.1057@0.23.1920.1057" timestamp="1583567568644" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.bottom" timestamp="1583567566487">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.1.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696751" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.bottom/0.23.1920.1057@0.23.1920.1057" timestamp="1583567566487" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.center" timestamp="1583567566486">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.1.center/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696750" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.center/0.23.1920.1057@0.23.1920.1057" timestamp="1583567566486" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.left" timestamp="1583567566486">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.1.left/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696749" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.left/0.23.1920.1057@0.23.1920.1057" timestamp="1583567566486" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.right" timestamp="1583567566486">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state width="1867" height="615" key="GridCell.Tab.1.right/0.0.1920.1040@0.0.1920.1040" timestamp="1579243696751" />
|
||||
<state width="1870" height="565" key="GridCell.Tab.1.right/0.23.1920.1057@0.23.1920.1057" timestamp="1583567566486" />
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.bottom" timestamp="1579156159339">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1579156159339" />
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.center" timestamp="1579156159339">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.center/0.0.1920.1040@0.0.1920.1040" timestamp="1579156159339" />
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.left" timestamp="1579156159339">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.left/0.0.1920.1040@0.0.1920.1040" timestamp="1579156159339" />
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.right" timestamp="1579156159339">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1867" height="386" key="GridCell.Tab.2.right/0.0.1920.1040@0.0.1920.1040" timestamp="1579156159339" />
|
||||
<state x="574" y="219" width="771" height="670" key="find.popup" timestamp="1583473246286">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state x="574" y="193" width="771" height="654" key="find.popup/0.0.1920.1040@0.0.1920.1040" timestamp="1579242964438" />
|
||||
<state x="574" y="219" width="771" height="670" key="find.popup/0.23.1920.1057@0.23.1920.1057" timestamp="1583473246286" />
|
||||
<state x="161" y="163" key="new project wizard" timestamp="1579242569030">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="161" y="163" key="new project wizard/0.0.1920.1040@0.0.1920.1040" timestamp="1579242569030" />
|
||||
<state x="539" y="28" width="840" height="1051" key="search.everywhere.popup" timestamp="1583567214095">
|
||||
<screen x="0" y="23" width="1920" height="1057" />
|
||||
</state>
|
||||
<state x="539" y="5" width="840" height="1034" key="search.everywhere.popup/0.0.1920.1040@0.0.1920.1040" timestamp="1579235575382" />
|
||||
<state x="539" y="28" width="840" height="1051" key="search.everywhere.popup/0.23.1920.1057@0.23.1920.1057" timestamp="1583567214095" />
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
@ -212,9 +395,9 @@
|
||||
<option name="timeStamp" value="10" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="java-line">
|
||||
<url>file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/handler/SessionClosedHandler.java</url>
|
||||
<line>48</line>
|
||||
<option name="timeStamp" value="12" />
|
||||
<url>file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/component/message/PushMessageListener.java</url>
|
||||
<line>24</line>
|
||||
<option name="timeStamp" value="16" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
|
0
cim-client-sdk/cim-java-sdk/jar.bat → cim-boot-server/jar.bat
Executable file → Normal file
0
cim-client-sdk/cim-java-sdk/jar.bat → cim-boot-server/jar.bat
Executable file → Normal file
Binary file not shown.
Binary file not shown.
BIN
cim-boot-server/libs/cim-server-sdk-netty-4.0.0.jar
Normal file
BIN
cim-boot-server/libs/cim-server-sdk-netty-4.0.0.jar
Normal file
Binary file not shown.
@ -11,15 +11,17 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.5.RELEASE</version>
|
||||
<version>2.4.4</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<netty.version>4.1.35.Final</netty.version>
|
||||
<mina.version>2.1.3</mina.version>
|
||||
<netty.version>4.1.62.Final</netty.version>
|
||||
<protobuf.version>3.11.1</protobuf.version>
|
||||
<mysql.jdbc.version>8.0.22</mysql.jdbc.version>
|
||||
<common.pool.version>2.8.0</common.pool.version>
|
||||
<swagger.version>3.0.0</swagger.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@ -36,26 +38,40 @@
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.farsunset</groupId>
|
||||
<artifactId>cim-server-sdk</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>4.0.0</version>
|
||||
<scope>system</scope>
|
||||
<!-- mina 、netty版本 sdk任选其一 -->
|
||||
<systemPath>${project.basedir}/libs/cim-server-sdk-netty-3.8.0.jar</systemPath>
|
||||
<systemPath>${project.basedir}/libs/cim-server-sdk-netty-4.0.0.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--- ##################使用mina版本SDK时的配置 start ##################-->
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>${mina.version}</version>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
<version>${common.pool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--- ##################使用mina版本SDK时的配置 end ##################-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.jdbc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--- ##################使用netty本SDK时的配置 start ##################-->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
@ -113,7 +129,6 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
1
cim-boot-server/run.bat
Normal file
1
cim-boot-server/run.bat
Normal file
@ -0,0 +1 @@
|
||||
java -Dcom.sun.akuma.Daemon=daemonized -Dspring.profiles.active=pro -jar ./cim-boot-server-4.0.0.jar
|
3
cim-boot-server/run.sh
Executable file
3
cim-boot-server/run.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#! /bin/bash
|
||||
|
||||
java -Dcom.sun.akuma.Daemon=daemonized -Dspring.profiles.active=pro -jar ./cim-boot-server-4.0.0.jar &
|
@ -19,21 +19,14 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.server.model;
|
||||
package com.farsunset.cim;
|
||||
|
||||
/**
|
||||
* 需要向另一端发送的结构体
|
||||
*/
|
||||
public interface Transportable {
|
||||
/**
|
||||
* 消息体字节数组
|
||||
* @return
|
||||
*/
|
||||
byte[] getBody();
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
* @return
|
||||
*/
|
||||
byte getType();
|
||||
}
|
||||
@SpringBootApplication
|
||||
public class BootApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BootApplication.class, args);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ServerLauncher {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ServerLauncher.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.component.handler;
|
||||
|
||||
import com.farsunset.cim.component.handler.annotation.CIMHandler;
|
||||
import com.farsunset.cim.component.redis.SignalRedisTemplate;
|
||||
import com.farsunset.cim.entity.Session;
|
||||
import com.farsunset.cim.sdk.server.constant.ChannelAttr;
|
||||
import com.farsunset.cim.sdk.server.group.SessionGroup;
|
||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||
import com.farsunset.cim.service.SessionService;
|
||||
import io.netty.channel.Channel;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 客户长连接 账户绑定实现
|
||||
*/
|
||||
@CIMHandler(key = "client_bind")
|
||||
public class BindHandler implements CIMRequestHandler {
|
||||
|
||||
@Resource
|
||||
private SessionService sessionService;
|
||||
|
||||
@Resource
|
||||
private SessionGroup sessionGroup;
|
||||
|
||||
@Resource
|
||||
private SignalRedisTemplate signalRedisTemplate;
|
||||
|
||||
@Override
|
||||
public void process(Channel channel, SentBody body) {
|
||||
|
||||
ReplyBody reply = new ReplyBody();
|
||||
reply.setKey(body.getKey());
|
||||
reply.setCode(HttpStatus.OK.value());
|
||||
reply.setTimestamp(System.currentTimeMillis());
|
||||
|
||||
String uid = body.get("uid");
|
||||
Session session = new Session();
|
||||
session.setUid(uid);
|
||||
session.setNid(channel.attr(ChannelAttr.ID).get());
|
||||
session.setDeviceId(body.get("deviceId"));
|
||||
session.setChannel(body.get("channel"));
|
||||
session.setDeviceName(body.get("deviceName"));
|
||||
session.setAppVersion(body.get("appVersion"));
|
||||
session.setOsVersion(body.get("osVersion"));
|
||||
|
||||
channel.attr(ChannelAttr.UID).set(uid);
|
||||
channel.attr(ChannelAttr.CHANNEL).set(session.getChannel());
|
||||
channel.attr(ChannelAttr.DEVICE_ID).set(session.getDeviceId());
|
||||
|
||||
/*
|
||||
*存储到数据库
|
||||
*/
|
||||
sessionService.add(session);
|
||||
|
||||
/*
|
||||
* 添加到内存管理
|
||||
*/
|
||||
sessionGroup.add(channel);
|
||||
|
||||
/*
|
||||
*向客户端发送bind响应
|
||||
*/
|
||||
channel.writeAndFlush(reply);
|
||||
|
||||
/*
|
||||
* 发送上线事件到集群中的其他实例,控制其他设备下线
|
||||
*/
|
||||
signalRedisTemplate.bind(session);
|
||||
}
|
||||
}
|
@ -19,44 +19,47 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.handler;
|
||||
package com.farsunset.cim.component.handler;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
||||
import com.farsunset.cim.component.handler.annotation.CIMHandler;
|
||||
import com.farsunset.cim.entity.Session;
|
||||
import com.farsunset.cim.sdk.server.constant.ChannelAttr;
|
||||
import com.farsunset.cim.sdk.server.group.SessionGroup;
|
||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||
import com.farsunset.cim.service.CIMSessionService;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.farsunset.cim.service.SessionService;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/*
|
||||
* 断开连接,清除session
|
||||
*
|
||||
/**
|
||||
* 连接断开时,更新用户相关状态
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class SessionClosedHandler implements CIMRequestHandler {
|
||||
@CIMHandler(key = "client_closed")
|
||||
public class ClosedHandler implements CIMRequestHandler {
|
||||
|
||||
@Resource
|
||||
private CIMSessionService cimSessionService;
|
||||
|
||||
private SessionService sessionService;
|
||||
|
||||
@Resource
|
||||
private SessionGroup sessionGroup;
|
||||
|
||||
@Override
|
||||
public void process(CIMSession ios, SentBody message) {
|
||||
Object quietly = ios.getAttribute(CIMConstant.KEY_QUIETLY_CLOSE);
|
||||
if (Objects.equals(quietly, true)) {
|
||||
public void process(Channel channel, SentBody message) {
|
||||
|
||||
String uid = channel.attr(ChannelAttr.UID).get();
|
||||
|
||||
String nid = channel.attr(ChannelAttr.ID).get();
|
||||
|
||||
sessionGroup.remove(channel);
|
||||
|
||||
if (!Objects.equals(channel.attr(ChannelAttr.CHANNEL).get(), Session.CHANNEL_IOS)){
|
||||
sessionService.delete(uid,nid);
|
||||
return;
|
||||
}
|
||||
|
||||
Object account = ios.getAttribute(CIMConstant.KEY_ACCOUNT);
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
cimSessionService.remove(account.toString());
|
||||
sessionService.updateState(uid,nid, Session.STATE_INACTIVE);
|
||||
}
|
||||
|
||||
}
|
@ -19,14 +19,17 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
package com.farsunset.cim.component.handler.annotation;
|
||||
|
||||
/**
|
||||
* 需要向另一端发送的结构体
|
||||
*/
|
||||
public interface Protobufable {
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
byte[] getByteArray();
|
||||
import java.lang.annotation.*;
|
||||
|
||||
byte getType();
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Component
|
||||
|
||||
public @interface CIMHandler {
|
||||
String key();
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package com.farsunset.cim.component.message;
|
||||
|
||||
import com.farsunset.cim.entity.Session;
|
||||
import com.farsunset.cim.sdk.server.constant.ChannelAttr;
|
||||
import com.farsunset.cim.sdk.server.group.SessionGroup;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import com.farsunset.cim.util.JSONUtils;
|
||||
import io.netty.channel.Channel;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 集群环境下,监控多设备登录情况,控制是否其余终端下线的逻辑
|
||||
*/
|
||||
@Component
|
||||
public class BindMessageListener implements MessageListener {
|
||||
|
||||
private static final String FORCE_OFFLINE_ACTION = "999";
|
||||
|
||||
private static final String SYSTEM_ID = "0";
|
||||
|
||||
/*
|
||||
一个账号只能在同一个类型的终端登录
|
||||
如: 多个android或ios不能同时在线
|
||||
一个android或ios可以和web,桌面同时在线
|
||||
*/
|
||||
private final Map<String,String[]> conflictMap = new HashMap<>();
|
||||
|
||||
@Resource
|
||||
private SessionGroup sessionGroup;
|
||||
|
||||
public BindMessageListener(){
|
||||
conflictMap.put(Session.CHANNEL_ANDROID,new String[]{Session.CHANNEL_ANDROID,Session.CHANNEL_IOS});
|
||||
conflictMap.put(Session.CHANNEL_IOS,new String[]{Session.CHANNEL_ANDROID,Session.CHANNEL_IOS});
|
||||
conflictMap.put(Session.CHANNEL_WINDOWS,new String[]{Session.CHANNEL_WINDOWS,Session.CHANNEL_WEB,Session.CHANNEL_MAC});
|
||||
conflictMap.put(Session.CHANNEL_WEB,new String[]{Session.CHANNEL_WINDOWS,Session.CHANNEL_WEB,Session.CHANNEL_MAC});
|
||||
conflictMap.put(Session.CHANNEL_MAC,new String[]{Session.CHANNEL_WINDOWS,Session.CHANNEL_WEB,Session.CHANNEL_MAC});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(org.springframework.data.redis.connection.Message redisMessage, byte[] bytes) {
|
||||
|
||||
Session session = JSONUtils.fromJson(redisMessage.getBody(), Session.class);
|
||||
String uid = session.getUid();
|
||||
String[] conflictChannels = conflictMap.get(session.getChannel());
|
||||
|
||||
Collection<Channel> channelList = sessionGroup.find(uid,conflictChannels);
|
||||
|
||||
channelList.removeIf(channel -> session.getNid().equals(channel.attr(ChannelAttr.ID).get()));
|
||||
|
||||
/*
|
||||
* 获取到其他在线的终端连接,提示账号再其他终端登录
|
||||
*/
|
||||
channelList.forEach(channel -> {
|
||||
|
||||
if (Objects.equals(session.getDeviceId(),channel.attr(ChannelAttr.DEVICE_ID).get())){
|
||||
channel.close();
|
||||
return;
|
||||
}
|
||||
|
||||
Message message = new Message();
|
||||
message.setAction(FORCE_OFFLINE_ACTION);
|
||||
message.setReceiver(uid);
|
||||
message.setSender(SYSTEM_ID);
|
||||
message.setContent(session.getDeviceName());
|
||||
channel.writeAndFlush(message);
|
||||
channel.close();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.farsunset.cim.component.message;
|
||||
|
||||
import com.farsunset.cim.sdk.server.group.SessionGroup;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import com.farsunset.cim.util.JSONUtils;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
/**
|
||||
* 集群环境下,监听redis队列,广播消息到每个实例进行推送
|
||||
* 如果使用MQ的情况也,最好替换为MQ消息队列
|
||||
*/
|
||||
@Component
|
||||
public class PushMessageListener implements MessageListener {
|
||||
|
||||
@Resource
|
||||
private SessionGroup sessionGroup;
|
||||
|
||||
@Override
|
||||
public void onMessage(org.springframework.data.redis.connection.Message redisMessage, byte[] bytes) {
|
||||
|
||||
Message message = JSONUtils.fromJson(redisMessage.getBody(), Message.class);
|
||||
|
||||
String uid = message.getReceiver();
|
||||
|
||||
sessionGroup.write(uid,message);
|
||||
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.push;
|
||||
package com.farsunset.cim.component.push;
|
||||
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
|
||||
@ -34,6 +34,6 @@ public interface CIMMessagePusher {
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
public void push(Message msg);
|
||||
void push(Message msg);
|
||||
|
||||
}
|
@ -19,34 +19,56 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.api.controller;
|
||||
package com.farsunset.cim.component.push;
|
||||
|
||||
import com.farsunset.cim.push.DefaultMessagePusher;
|
||||
import com.farsunset.cim.component.redis.KeyValueRedisTemplate;
|
||||
import com.farsunset.cim.component.redis.SignalRedisTemplate;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.farsunset.cim.service.APNsService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/message")
|
||||
public class MessageController {
|
||||
/*
|
||||
* 消息发送实现类
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class DefaultMessagePusher implements CIMMessagePusher {
|
||||
|
||||
@Resource
|
||||
private DefaultMessagePusher defaultMessagePusher;
|
||||
private APNsService apnsService;
|
||||
|
||||
@Resource
|
||||
private SignalRedisTemplate signalRedisTemplate;
|
||||
|
||||
@PostMapping(value = "/send")
|
||||
public ResponseEntity<Long> send(Message message) {
|
||||
@Resource
|
||||
private KeyValueRedisTemplate keyValueRedisTemplate;
|
||||
|
||||
message.setId(System.currentTimeMillis());
|
||||
/**
|
||||
* 向用户发送消息
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public final void push(Message message) {
|
||||
|
||||
defaultMessagePusher.push(message);
|
||||
String uid = message.getReceiver();
|
||||
|
||||
/*
|
||||
* 说明iOS客户端开启了apns
|
||||
*/
|
||||
String deviceToken = keyValueRedisTemplate.getDeviceToken(uid);
|
||||
if(deviceToken != null) {
|
||||
apnsService.push(message,deviceToken);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 通过发送redis广播,到集群中的每台实例,获得当前UID绑定了连接并推送
|
||||
* @see com.farsunset.hoxin.component.message.PushMessageListener
|
||||
*/
|
||||
signalRedisTemplate.push(message);
|
||||
|
||||
return ResponseEntity.ok(message.getId());
|
||||
}
|
||||
|
||||
}
|
@ -19,52 +19,40 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
package com.farsunset.cim.component.redis;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import com.farsunset.cim.constants.Constants;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* java |android 客户端请求结构
|
||||
*
|
||||
*/
|
||||
public class Intent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Component
|
||||
public class KeyValueRedisTemplate extends StringRedisTemplate {
|
||||
|
||||
private String action;
|
||||
|
||||
private final HashMap<String, Object> data = new HashMap<String, Object>();
|
||||
|
||||
public Intent() {
|
||||
public KeyValueRedisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
super(connectionFactory);
|
||||
}
|
||||
|
||||
public Intent(String action) {
|
||||
this.action = action;
|
||||
public void set(String key ,String value) {
|
||||
super.boundValueOps(key).set(value);
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
public String get(String key) {
|
||||
return super.boundValueOps(key).get();
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
public String getDeviceToken(String uid){
|
||||
return super.boundValueOps(String.format(Constants.APNS_DEVICE_TOKEN,uid)).get();
|
||||
}
|
||||
|
||||
public void putExtra(String key, Object value) {
|
||||
data.put(key, value);
|
||||
public void openApns(String uid,String deviceToken){
|
||||
super.boundValueOps(String.format(Constants.APNS_DEVICE_TOKEN,uid)).set(deviceToken);
|
||||
}
|
||||
|
||||
public Object getExtra(String key) {
|
||||
return data.get(key);
|
||||
public void closeApns(String uid){
|
||||
super.delete(String.format(Constants.APNS_DEVICE_TOKEN,uid));
|
||||
}
|
||||
|
||||
public long getLongExtra(String key, long defValue) {
|
||||
Object v = getExtra(key);
|
||||
try {
|
||||
return Long.parseLong(v.toString());
|
||||
} catch (Exception e) {
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.component.redis;
|
||||
|
||||
import com.farsunset.cim.constants.Constants;
|
||||
import com.farsunset.cim.entity.Session;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import com.farsunset.cim.util.JSONUtils;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SignalRedisTemplate extends StringRedisTemplate {
|
||||
|
||||
public SignalRedisTemplate(LettuceConnectionFactory connectionFactory) {
|
||||
super(connectionFactory);
|
||||
connectionFactory.setValidateConnection(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发送到 集群中的每个实例,获取对应长连接进行消息写入
|
||||
* @param message
|
||||
*/
|
||||
public void push(Message message) {
|
||||
super.convertAndSend(Constants.PUSH_MESSAGE_INNER_QUEUE, JSONUtils.toJSONString(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发送到 集群中的每个实例,解决多终端在线冲突问题
|
||||
* @param session
|
||||
*/
|
||||
public void bind(Session session) {
|
||||
super.convertAndSend(Constants.BIND_MESSAGE_INNER_QUEUE, JSONUtils.toJSONString(session));
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
package com.farsunset.cim.config;
|
||||
|
||||
import com.farsunset.cim.handler.BindHandler;
|
||||
import com.farsunset.cim.handler.SessionClosedHandler;
|
||||
import com.farsunset.cim.component.handler.annotation.CIMHandler;
|
||||
import com.farsunset.cim.sdk.server.group.SessionGroup;
|
||||
import com.farsunset.cim.sdk.server.group.TagSessionGroup;
|
||||
import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor;
|
||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||
import com.farsunset.cim.service.SessionService;
|
||||
import io.netty.channel.Channel;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@ -15,6 +17,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class CIMConfig implements CIMRequestHandler, ApplicationListener<ApplicationStartedEvent> {
|
||||
@ -22,7 +25,20 @@ public class CIMConfig implements CIMRequestHandler, ApplicationListener<Applica
|
||||
@Resource
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private final HashMap<String,CIMRequestHandler> appHandlerMap = new HashMap<>();
|
||||
@Resource
|
||||
private SessionService sessionService;
|
||||
|
||||
private final HashMap<String,CIMRequestHandler> handlerMap = new HashMap<>();
|
||||
|
||||
@Bean
|
||||
public SessionGroup sessionGroup() {
|
||||
return new SessionGroup();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TagSessionGroup tagSessionGroup() {
|
||||
return new TagSessionGroup();
|
||||
}
|
||||
|
||||
|
||||
@Bean(destroyMethod = "destroy")
|
||||
@ -38,13 +54,13 @@ public class CIMConfig implements CIMRequestHandler, ApplicationListener<Applica
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(CIMSession session, SentBody body) {
|
||||
public void process(Channel channel, SentBody body) {
|
||||
|
||||
CIMRequestHandler handler = appHandlerMap.get(body.getKey());
|
||||
CIMRequestHandler handler = handlerMap.get(body.getKey());
|
||||
|
||||
if(handler == null) {return ;}
|
||||
|
||||
handler.process(session, body);
|
||||
handler.process(channel, body);
|
||||
|
||||
}
|
||||
/*
|
||||
@ -53,9 +69,22 @@ public class CIMConfig implements CIMRequestHandler, ApplicationListener<Applica
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
|
||||
|
||||
appHandlerMap.put("client_bind",applicationContext.getBean(BindHandler.class));
|
||||
appHandlerMap.put("client_closed",applicationContext.getBean(SessionClosedHandler.class));
|
||||
Map<String, CIMRequestHandler> beans = applicationContext.getBeansOfType(CIMRequestHandler.class);
|
||||
|
||||
for (Map.Entry<String, CIMRequestHandler> entry : beans.entrySet()) {
|
||||
|
||||
CIMRequestHandler handler = entry.getValue();
|
||||
|
||||
CIMHandler annotation = handler.getClass().getAnnotation(CIMHandler.class);
|
||||
|
||||
if (annotation != null){
|
||||
handlerMap.put(annotation.key(),handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
applicationContext.getBean(CIMNioSocketAcceptor.class).bind();
|
||||
|
||||
sessionService.deleteLocalhost();
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.config;
|
||||
|
||||
import com.farsunset.cim.constants.Constants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@Configuration
|
||||
@AutoConfigureBefore(RedisAutoConfiguration.class)
|
||||
public class RedisConfig {
|
||||
|
||||
@Autowired
|
||||
public RedisConfig(LettuceConnectionFactory connectionFactory, @Value("${spring.profiles.active}") String profile){
|
||||
if (Objects.equals("dev",profile)){
|
||||
connectionFactory.setValidateConnection(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,
|
||||
MessageListener pushMessageListener,
|
||||
MessageListener bindMessageListener){
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.addMessageListener(pushMessageListener,new ChannelTopic(Constants.PUSH_MESSAGE_INNER_QUEUE));
|
||||
container.addMessageListener(bindMessageListener,new ChannelTopic(Constants.BIND_MESSAGE_INNER_QUEUE));
|
||||
return container;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.oas.annotations.EnableOpenApi;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
@EnableOpenApi
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public Docket userApiDocket(ApiInfo apiInfo) {
|
||||
return new Docket(DocumentationType.OAS_30)
|
||||
.apiInfo(apiInfo)
|
||||
.groupName("APP接口")
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.basePackage("com.farsunset.cim.mvc.controller.api"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title("CIM Push Service APIs.")
|
||||
.description("CIM客户端接口文档")
|
||||
.version("2.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -19,18 +19,15 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.server.handler;
|
||||
package com.farsunset.cim.constants;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||
String PUSH_MESSAGE_INNER_QUEUE = "signal/channel/PUSH_MESSAGE_INNER_QUEUE";
|
||||
|
||||
public interface CIMRequestHandler {
|
||||
String BIND_MESSAGE_INNER_QUEUE = "signal/channel/BIND_MESSAGE_INNER_QUEUE";
|
||||
|
||||
/**
|
||||
* 处理长连接发送的请求
|
||||
* @param session
|
||||
* @param message
|
||||
*/
|
||||
void process(CIMSession session, SentBody message);
|
||||
String PING_MESSAGE_INNER_QUEUE = "signal/channel/PING_MESSAGE_INNER_QUEUE";
|
||||
|
||||
String APNS_DEVICE_TOKEN = "APNS_OPEN_%s";
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.entity;
|
||||
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "t_hoxin_session")
|
||||
public class Session implements Serializable {
|
||||
|
||||
private static final transient long serialVersionUID = 1L;
|
||||
public static final transient int STATE_ACTIVE = 0;
|
||||
public static final transient int STATE_APNS = 1;
|
||||
public static final transient int STATE_INACTIVE = 2;
|
||||
|
||||
public static final transient String CHANNEL_IOS = "ios";
|
||||
public static final transient String CHANNEL_ANDROID = "android";
|
||||
public static final transient String CHANNEL_WINDOWS = "windows";
|
||||
public static final transient String CHANNEL_MAC = "mac";
|
||||
public static final transient String CHANNEL_WEB = "web";
|
||||
|
||||
/**
|
||||
* 数据库主键ID
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* session绑定的用户账号
|
||||
*/
|
||||
@Column(name = "uid")
|
||||
private String uid;
|
||||
|
||||
/**
|
||||
* session在本台服务器上的ID
|
||||
*/
|
||||
@Column(name = "nid",length = 32,nullable = false)
|
||||
private String nid;
|
||||
|
||||
/**
|
||||
* 客户端ID (设备号码+应用包名),ios为deviceToken
|
||||
*/
|
||||
|
||||
@Column(name = "device_id",length = 64,nullable = false)
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 终端设备型号
|
||||
*/
|
||||
@Column(name = "device_name")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* session绑定的服务器IP
|
||||
*/
|
||||
@Column(name = "host",length = 15,nullable = false)
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* 终端设备类型
|
||||
*/
|
||||
@Column(name = "channel",length = 10,nullable = false)
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 终端应用版本
|
||||
*/
|
||||
@Column(name = "app_version")
|
||||
private String appVersion;
|
||||
|
||||
/**
|
||||
* 终端系统版本
|
||||
*/
|
||||
@Column(name = "os_version")
|
||||
private String osVersion;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
@Column(name = "bind_time")
|
||||
private Long bindTime;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@Column(name = "longitude")
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 维度
|
||||
*/
|
||||
@Column(name = "latitude")
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 位置
|
||||
*/
|
||||
@Column(name = "location")
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private int state;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public void setUid(String uid) {
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getAppVersion() {
|
||||
return appVersion;
|
||||
}
|
||||
|
||||
public void setAppVersion(String appVersion) {
|
||||
this.appVersion = appVersion;
|
||||
}
|
||||
|
||||
public String getOsVersion() {
|
||||
return osVersion;
|
||||
}
|
||||
|
||||
public void setOsVersion(String osVersion) {
|
||||
this.osVersion = osVersion;
|
||||
}
|
||||
|
||||
public Long getBindTime() {
|
||||
return bindTime;
|
||||
}
|
||||
|
||||
public void setBindTime(Long bindTime) {
|
||||
this.bindTime = bindTime;
|
||||
}
|
||||
|
||||
public Double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(Double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public Double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(Double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.handler;
|
||||
|
||||
import com.farsunset.cim.push.CIMMessagePusher;
|
||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||
import com.farsunset.cim.service.CIMSessionService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/*
|
||||
* 账号绑定实现
|
||||
*
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class BindHandler implements CIMRequestHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BindHandler.class);
|
||||
|
||||
@Resource
|
||||
private CIMSessionService cimSessionService;
|
||||
|
||||
@Value("${server.host}")
|
||||
private String host;
|
||||
|
||||
@Resource
|
||||
private CIMMessagePusher defaultMessagePusher;
|
||||
|
||||
@Override
|
||||
public void process(CIMSession newSession, SentBody body) {
|
||||
|
||||
ReplyBody reply = new ReplyBody();
|
||||
reply.setKey(body.getKey());
|
||||
reply.setCode(HttpStatus.OK.value());
|
||||
reply.setTimestamp(System.currentTimeMillis());
|
||||
|
||||
try {
|
||||
|
||||
String account = body.get("account");
|
||||
newSession.setAccount(account);
|
||||
newSession.setDeviceId(body.get("deviceId"));
|
||||
newSession.setHost(host);
|
||||
newSession.setChannel(body.get("channel"));
|
||||
newSession.setDeviceModel(body.get("device"));
|
||||
newSession.setClientVersion(body.get("appVersion"));
|
||||
newSession.setSystemVersion(body.get("osVersion"));
|
||||
newSession.setBindTime(System.currentTimeMillis());
|
||||
/*
|
||||
* 由于客户端断线服务端可能会无法获知的情况,客户端重连时,需要关闭旧的连接
|
||||
*/
|
||||
CIMSession oldSession = cimSessionService.get(account);
|
||||
|
||||
/*
|
||||
* 如果是账号已经在另一台终端登录。则让另一个终端下线
|
||||
*/
|
||||
|
||||
if (oldSession != null && fromOtherDevice(newSession,oldSession) && oldSession.isConnected()) {
|
||||
sendForceOfflineMessage(oldSession, account, newSession.getDeviceModel());
|
||||
}
|
||||
|
||||
/*
|
||||
* 有可能是同一个设备重复连接,则关闭旧的链接,这种情况一般是客户端断网,联网又重新链接上来,之前的旧链接没有来得及通过心跳机制关闭,在这里手动关闭
|
||||
* 条件1,连接来自是同一个设备
|
||||
* 条件2.2个连接都是同一台服务器
|
||||
*/
|
||||
|
||||
if (oldSession != null && !fromOtherDevice(newSession,oldSession) && Objects.equals(oldSession.getHost(),host)) {
|
||||
closeQuietly(oldSession);
|
||||
}
|
||||
|
||||
cimSessionService.save(newSession);
|
||||
|
||||
|
||||
} catch (Exception exception) {
|
||||
reply.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
logger.error("Bind has error",exception);
|
||||
}
|
||||
|
||||
newSession.write(reply);
|
||||
}
|
||||
|
||||
private boolean fromOtherDevice(CIMSession oldSession ,CIMSession newSession) {
|
||||
|
||||
return !Objects.equals(oldSession.getDeviceId(), newSession.getDeviceId());
|
||||
}
|
||||
|
||||
private void sendForceOfflineMessage(CIMSession oldSession, String account, String deviceModel) {
|
||||
|
||||
Message msg = new Message();
|
||||
msg.setAction(CIMConstant.MessageAction.ACTION_OFFLINE);
|
||||
msg.setReceiver(account);
|
||||
msg.setSender("system");
|
||||
msg.setContent(deviceModel);
|
||||
msg.setId(System.currentTimeMillis());
|
||||
|
||||
defaultMessagePusher.push(msg);
|
||||
|
||||
closeQuietly(oldSession);
|
||||
|
||||
}
|
||||
|
||||
private void closeQuietly(CIMSession oldSession) {
|
||||
if (oldSession.isConnected() && Objects.equals(host, oldSession.getHost())) {
|
||||
oldSession.setAttribute(CIMConstant.KEY_QUIETLY_CLOSE,true);
|
||||
oldSession.closeOnFlush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.admin.controller;
|
||||
package com.farsunset.cim.mvc.controller.admin;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
@ -19,9 +19,9 @@
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.admin.controller;
|
||||
package com.farsunset.cim.mvc.controller.admin;
|
||||
|
||||
import com.farsunset.cim.service.CIMSessionService;
|
||||
import com.farsunset.cim.service.SessionService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -34,11 +34,13 @@ import javax.annotation.Resource;
|
||||
public class SessionController {
|
||||
|
||||
@Resource
|
||||
private CIMSessionService cimSessionService;
|
||||
|
||||
private SessionService sessionService;
|
||||
|
||||
@GetMapping(value = "/list")
|
||||
public String list(Model model) {
|
||||
model.addAttribute("sessionList", cimSessionService.list());
|
||||
model.addAttribute("sessionList", sessionService.findAll());
|
||||
return "console/session/manage";
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.mvc.controller.api;
|
||||
|
||||
import com.farsunset.cim.service.SessionService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/apns")
|
||||
@Api(produces = "application/json", tags = "APNs推送相关")
|
||||
public class APNsController {
|
||||
|
||||
@ApiOperation(httpMethod = "POST", value = "开启apns")
|
||||
|
||||
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "deviceToken", value = "APNs的deviceToken", paramType = "query", dataTypeClass = String.class, required = true, example = ""),
|
||||
@ApiImplicitParam(name = "uid", value = "用户ID", paramType = "query", dataTypeClass = String.class,example = "0")
|
||||
})
|
||||
@PostMapping(value = "/open")
|
||||
public ResponseEntity<Void> open(@RequestParam String uid , @RequestParam String deviceToken) {
|
||||
|
||||
sessionService.openApns(uid,deviceToken);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Resource
|
||||
private SessionService sessionService;
|
||||
|
||||
@ApiOperation(httpMethod = "POST", value = "关闭apns")
|
||||
@ApiImplicitParam(name = "uid", value = "用户ID", paramType = "query", dataTypeClass = String.class,example = "0")
|
||||
@PostMapping(value = "/close")
|
||||
public ResponseEntity<Void> close(@RequestParam String uid) {
|
||||
|
||||
sessionService.closeApns(uid);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.mvc.controller.api;
|
||||
|
||||
import com.farsunset.cim.component.push.DefaultMessagePusher;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/message")
|
||||
@Api(produces = "application/json", tags = "消息相关接口" )
|
||||
public class MessageController {
|
||||
|
||||
@Resource
|
||||
private DefaultMessagePusher defaultMessagePusher;
|
||||
|
||||
@ApiOperation(httpMethod = "POST", value = "发送消息")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "sender", value = "发送者UID", paramType = "query", dataTypeClass = String.class, required = true, example = ""),
|
||||
@ApiImplicitParam(name = "receiver", value = "接收者UID", paramType = "query", dataTypeClass = String.class, required = true, example = ""),
|
||||
@ApiImplicitParam(name = "action", value = "消息动作", paramType = "query", dataTypeClass = String.class, required = true, example = ""),
|
||||
@ApiImplicitParam(name = "title", value = "消息标题", paramType = "query", dataTypeClass = String.class, example = ""),
|
||||
@ApiImplicitParam(name = "content", value = "消息内容", paramType = "query", dataTypeClass = String.class, example = ""),
|
||||
@ApiImplicitParam(name = "format", value = "消息格式", paramType = "query", dataTypeClass = String.class, example = ""),
|
||||
@ApiImplicitParam(name = "extra", value = "扩展字段", paramType = "query", dataTypeClass = String.class, example = ""),
|
||||
})
|
||||
@PostMapping(value = "/send")
|
||||
public ResponseEntity<Long> send(@RequestParam String sender ,
|
||||
@RequestParam String receiver ,
|
||||
@RequestParam String action ,
|
||||
@RequestParam(required = false) String title ,
|
||||
@RequestParam(required = false) String content ,
|
||||
@RequestParam(required = false) String format ,
|
||||
@RequestParam(required = false) String extra) {
|
||||
|
||||
Message message = new Message();
|
||||
message.setSender(sender);
|
||||
message.setReceiver(receiver);
|
||||
message.setAction(action);
|
||||
message.setContent(content);
|
||||
message.setFormat(format);
|
||||
message.setTitle(title);
|
||||
message.setExtra(extra);
|
||||
|
||||
message.setId(System.currentTimeMillis());
|
||||
|
||||
defaultMessagePusher.push(message);
|
||||
|
||||
return ResponseEntity.ok(message.getId());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.push;
|
||||
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import com.farsunset.cim.service.ApnsService;
|
||||
import com.farsunset.cim.service.CIMSessionService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
|
||||
/*
|
||||
* 消息发送实现类
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class DefaultMessagePusher implements CIMMessagePusher {
|
||||
|
||||
@Value("${server.host}")
|
||||
private String host;
|
||||
|
||||
@Resource
|
||||
private CIMSessionService cimSessionService;
|
||||
|
||||
|
||||
|
||||
@Resource
|
||||
private ApnsService apnsService;
|
||||
|
||||
|
||||
/*
|
||||
* 向用户发送消息
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
@Override
|
||||
public void push(Message message) {
|
||||
CIMSession session = cimSessionService.get(message.getReceiver());
|
||||
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* IOS设备,如果开启了apns,则使用apns推送
|
||||
*/
|
||||
if (session.isIOSChannel() && session.isApnsEnable()) {
|
||||
apnsService.push(message, session.getDeviceId());
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 服务器集群时,判断当前session是否连接于本台服务器
|
||||
* 如果连接到了其他服务器则转发请求到目标服务器
|
||||
*/
|
||||
if (session.isConnected() && !Objects.equals(host, session.getHost())) {
|
||||
/*
|
||||
* @TODO
|
||||
* 在此调用目标服务器接口来发送,如session.host = 123.123.123.123
|
||||
* 调用目标服务器的消息发送接口http://123.123.123.123:8080/message/send
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 如果是Android,浏览器或者windows客户端则直接发送
|
||||
*/
|
||||
if (session.isConnected() && Objects.equals(host, session.getHost())) {
|
||||
session.write(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.repository;
|
||||
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.entity.Session;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/*
|
||||
* 正式场景下,使用redis或者数据库来存储session信息
|
||||
*/
|
||||
@Repository
|
||||
public class SessionRepository {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public interface SessionRepository extends JpaRepository<Session, Long> {
|
||||
|
||||
private ConcurrentHashMap<String, CIMSession> map = new ConcurrentHashMap<>();
|
||||
@Modifying
|
||||
@Query("delete from Session where uid = ?1 and nid = ?2")
|
||||
void delete(String uid,String nid);
|
||||
|
||||
@Modifying
|
||||
@Query("delete from Session where host = ?1 ")
|
||||
void deleteAll(String host);
|
||||
|
||||
public void save(CIMSession session){
|
||||
map.put(session.getAccount(),session);
|
||||
}
|
||||
@Modifying
|
||||
@Query("update Session set state = ?3 where uid = ?1 and nid = ?2")
|
||||
void updateState(String uid,String nid,int state);
|
||||
|
||||
public CIMSession get(String account){
|
||||
return map.get(account);
|
||||
}
|
||||
@Modifying
|
||||
@Query("update Session set state = " + Session.STATE_APNS + " where uid = ?1 and channel = ?2")
|
||||
void openApns(String uid,String channel);
|
||||
|
||||
public void remove(String account){
|
||||
map.remove(account);
|
||||
}
|
||||
|
||||
public List<CIMSession> findAll(){
|
||||
return new LinkedList<>(map.values());
|
||||
}
|
||||
@Modifying
|
||||
@Query("update Session set state = " + Session.STATE_ACTIVE + " where uid = ?1 and channel = ?2")
|
||||
void closeApns(String uid,String channel);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ package com.farsunset.cim.service;
|
||||
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
|
||||
public interface ApnsService {
|
||||
public interface APNsService {
|
||||
|
||||
void push(Message message, String deviceToken);
|
||||
}
|
@ -21,23 +21,30 @@
|
||||
*/
|
||||
package com.farsunset.cim.service;
|
||||
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
|
||||
import com.farsunset.cim.entity.Session;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/*
|
||||
* 集群 session管理实现示例, 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 服务器集群时
|
||||
* 须要将CIMSession 信息存入数据库或者redis中 等 第三方存储空间中,便于所有服务器都可以访问
|
||||
/**
|
||||
* 存储连接信息,便于查看用户的链接信息
|
||||
*/
|
||||
public interface CIMSessionService {
|
||||
public interface SessionService {
|
||||
|
||||
void save(CIMSession session);
|
||||
void add(Session session);
|
||||
|
||||
CIMSession get(String account);
|
||||
void delete(String uid,String nid);
|
||||
|
||||
List<CIMSession> list();
|
||||
|
||||
void remove(String account);
|
||||
/**
|
||||
* 删除本机的连接记录
|
||||
*/
|
||||
void deleteLocalhost();
|
||||
|
||||
void updateState(String uid,String nid,int state);
|
||||
|
||||
void openApns(String uid,String deviceToken);
|
||||
|
||||
void closeApns(String uid);
|
||||
|
||||
List<Session> findAll();
|
||||
}
|
@ -25,29 +25,38 @@ import cn.teaey.apns4j.Apns4j;
|
||||
import cn.teaey.apns4j.network.ApnsChannel;
|
||||
import cn.teaey.apns4j.network.ApnsChannelFactory;
|
||||
import cn.teaey.apns4j.network.ApnsGateway;
|
||||
import cn.teaey.apns4j.protocol.ApnsPayload;
|
||||
import com.farsunset.cim.sdk.server.model.Message;
|
||||
import com.farsunset.cim.service.ApnsService;
|
||||
import com.farsunset.cim.util.ApnsPayloadCompat;
|
||||
import com.farsunset.cim.service.APNsService;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@Service
|
||||
public class JavaApnsServiceImpl implements ApnsService {
|
||||
public class APNsServiceImpl implements APNsService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JavaApnsServiceImpl.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(APNsServiceImpl.class);
|
||||
|
||||
private final ApnsChannelFactory apnsChannelFactory;
|
||||
|
||||
@Autowired
|
||||
public APNsServiceImpl(@Value("${apple.apns.p12.file}") String p12File,
|
||||
@Value("${apple.apns.p12.password}") String password,
|
||||
@Value("${apple.apns.debug}") boolean isDebug){
|
||||
InputStream stream = getClass().getResourceAsStream(p12File);
|
||||
apnsChannelFactory = Apns4j.newChannelFactoryBuilder()
|
||||
.keyStoreMeta(stream)
|
||||
.keyStorePwd(password)
|
||||
.apnsGateway(isDebug ? ApnsGateway.DEVELOPMENT : ApnsGateway.PRODUCTION)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Value("${apple.apns.p12.password}")
|
||||
private String password;
|
||||
@Value("${apple.apns.p12.file}")
|
||||
private String p12Path;
|
||||
@Value("${apple.apns.debug}")
|
||||
private boolean isDebug;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
@ -56,31 +65,30 @@ public class JavaApnsServiceImpl implements ApnsService {
|
||||
if(StringUtils.isBlank(deviceToken)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
InputStream stream = getClass().getResourceAsStream(p12Path);
|
||||
ApnsChannelFactory apnsChannelFactory = Apns4j.newChannelFactoryBuilder()
|
||||
.keyStoreMeta(stream)
|
||||
.keyStorePwd(password)
|
||||
.apnsGateway(isDebug ? ApnsGateway.DEVELOPMENT : ApnsGateway.PRODUCTION)
|
||||
.build();
|
||||
|
||||
ApnsChannel apnsChannel = apnsChannelFactory.newChannel();
|
||||
ApnsPayload apnsPayload = new ApnsPayload();
|
||||
|
||||
apnsPayload.alert("您有一条新的消息");
|
||||
|
||||
apnsPayload.sound("default");
|
||||
apnsPayload.badge(1);
|
||||
apnsPayload.extend("id",message.getId());
|
||||
apnsPayload.extend("action",message.getAction());
|
||||
apnsPayload.extend("content",message.getContent());
|
||||
apnsPayload.extend("sender",message.getSender());
|
||||
apnsPayload.extend("receiver",message.getReceiver());
|
||||
apnsPayload.extend("format",message.getFormat());
|
||||
apnsPayload.extend("extra",message.getExtra());
|
||||
apnsPayload.extend("timestamp",message.getTimestamp());
|
||||
|
||||
try {
|
||||
ApnsPayloadCompat apnsPayload = new ApnsPayloadCompat();
|
||||
apnsPayload.setAction(message.getAction());
|
||||
apnsPayload.setContent(message.getContent());
|
||||
apnsPayload.setSender(message.getSender());
|
||||
apnsPayload.setFormat(message.getFormat());
|
||||
apnsPayload.setReceiver(message.getReceiver());
|
||||
apnsChannel.send(deviceToken, apnsPayload);
|
||||
|
||||
LOGGER.info(deviceToken +"\r\ndata: {}",apnsPayload.toJsonString());
|
||||
LOGGER.info("APNs push done.\ndeviceToken : {} \napnsPayload : {}",deviceToken,apnsPayload.toJsonString());
|
||||
}catch(Exception exception) {
|
||||
LOGGER.error("Apns has error",exception);
|
||||
LOGGER.error("APNs push failed",exception);
|
||||
}finally {
|
||||
apnsChannel.close();
|
||||
IOUtils.closeQuietly(stream);
|
||||
IOUtils.closeQuietly(apnsChannel);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.service.impl;
|
||||
|
||||
|
||||
import com.farsunset.cim.repository.SessionRepository;
|
||||
import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor;
|
||||
import com.farsunset.cim.sdk.server.model.CIMSession;
|
||||
import com.farsunset.cim.service.CIMSessionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Service
|
||||
public class CIMSessionServiceImpl implements CIMSessionService {
|
||||
|
||||
@Resource
|
||||
private CIMNioSocketAcceptor nioSocketAcceptor;
|
||||
|
||||
@Resource
|
||||
private SessionRepository sessionRepository;
|
||||
|
||||
@Override
|
||||
public void save(CIMSession session) {
|
||||
sessionRepository.save(session);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* @param account 用户id
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public CIMSession get(String account) {
|
||||
|
||||
CIMSession session = sessionRepository.get(account);
|
||||
|
||||
if (session != null){
|
||||
session.setSession(nioSocketAcceptor.getManagedSession(session.getNid()));
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String account) {
|
||||
sessionRepository.remove(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CIMSession> list() {
|
||||
return sessionRepository.findAll();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.service.impl;
|
||||
|
||||
import com.farsunset.cim.component.redis.KeyValueRedisTemplate;
|
||||
import com.farsunset.cim.entity.Session;
|
||||
import com.farsunset.cim.repository.SessionRepository;
|
||||
import com.farsunset.cim.service.SessionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SessionServiceImpl implements SessionService {
|
||||
|
||||
@Resource
|
||||
private SessionRepository sessionRepository;
|
||||
|
||||
@Resource
|
||||
private KeyValueRedisTemplate keyValueRedisTemplate;
|
||||
|
||||
|
||||
private final String host;
|
||||
|
||||
public SessionServiceImpl() throws UnknownHostException {
|
||||
host = InetAddress.getLocalHost().getHostAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Session session) {
|
||||
session.setBindTime(System.currentTimeMillis());
|
||||
session.setHost(host);
|
||||
sessionRepository.save(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String uid, String nid) {
|
||||
sessionRepository.delete(uid,nid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteLocalhost() {
|
||||
sessionRepository.deleteAll(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(String uid, String nid, int state) {
|
||||
sessionRepository.updateState(uid,nid,state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openApns(String uid,String deviceToken) {
|
||||
keyValueRedisTemplate.openApns(uid,deviceToken);
|
||||
sessionRepository.openApns(uid,Session.CHANNEL_IOS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeApns(String uid) {
|
||||
keyValueRedisTemplate.closeApns(uid);
|
||||
sessionRepository.closeApns(uid,Session.CHANNEL_IOS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Session> findAll() {
|
||||
return sessionRepository.findAll();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public final class JSONUtils {
|
||||
private static final JsonMapper OBJECT_MAPPER = JsonMapper.builder()
|
||||
.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS)
|
||||
.enable(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.serializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
.build();
|
||||
|
||||
|
||||
public static String toJSONString(Object data) {
|
||||
|
||||
try {
|
||||
return OBJECT_MAPPER.writeValueAsString(data);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String str, Class<T> clazz) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(str, clazz);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T fromJson(byte[] data, Class<T> clazz) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(data, clazz);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> List<T> parseList(String str, Class<T> clazz) {
|
||||
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionLikeType(List.class,clazz);
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(str, javaType);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
}
|
BIN
cim-boot-server/src/main/resources/apns/app.p12
Normal file
BIN
cim-boot-server/src/main/resources/apns/app.p12
Normal file
Binary file not shown.
@ -1,6 +1,46 @@
|
||||
server.port=8080
|
||||
server.host=127.0.0.1
|
||||
spring.profiles.active=dev
|
||||
|
||||
##################################################################
|
||||
# JDBC Config #
|
||||
##################################################################
|
||||
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/cim?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
|
||||
spring.datasource.username = cim
|
||||
spring.datasource.password = cimv587!
|
||||
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
|
||||
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
|
||||
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.maximum-pool-size=10
|
||||
spring.datasource.hikari.auto-commit=true
|
||||
spring.datasource.hikari.idle-timeout=30000
|
||||
spring.datasource.hikari.pool-name=MASTER_HIKARI_POOL
|
||||
spring.datasource.hikari.max-lifetime=120000
|
||||
spring.datasource.hikari.connection-timeout=30000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
spring.datasource.hikari.validation-timeout=600000
|
||||
|
||||
##################################################################
|
||||
# JPA Config #
|
||||
##################################################################
|
||||
spring.jpa.database = MYSQL
|
||||
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
spring.jpa.hibernate.ddl-auto = update
|
||||
spring.jpa.open-in-view = false
|
||||
spring.jpa.hibernate.naming.implicit-strategy= org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
|
||||
spring.jpa.hibernate.naming.physical-strategy= org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
|
||||
|
||||
##################################################################
|
||||
# Redis Config #
|
||||
##################################################################
|
||||
spring.redis.host=127.0.0.1
|
||||
spring.redis.password=RDSV587
|
||||
spring.redis.database=12
|
||||
spring.redis.lettuce.pool.max-active=10
|
||||
spring.redis.lettuce.pool.max-wait= 10s
|
||||
spring.redis.lettuce.pool.max-idle=5
|
||||
spring.redis.lettuce.pool.min-idle=1
|
||||
spring.redis.timeout=10s
|
||||
|
||||
##################################################################
|
||||
# Freemarker Config #
|
||||
@ -22,5 +62,5 @@ cim.app.port=23456
|
||||
cim.websocket.port=34567
|
||||
|
||||
apple.apns.debug=false
|
||||
apple.apns.p12.password= your p12 password
|
||||
apple.apns.p12.file= /apns/lvxin.p12
|
||||
apple.apns.p12.password=123
|
||||
apple.apns.p12.file= /apns/app.p12
|
@ -57,7 +57,7 @@ module.console.cimsession.channel = 终端
|
||||
module.console.cimsession.app.version =应用版本
|
||||
module.console.cimsession.os.version =系统版本
|
||||
module.console.cimsession.deviceid =设备编号
|
||||
module.console.cimsession.device.model =终端型号
|
||||
module.console.cimsession.device.name =终端型号
|
||||
module.console.cimsession.online.time =在线时长(秒)
|
||||
module.console.cimsession.time.format ={0}秒
|
||||
|
||||
|
12
cim-boot-server/src/main/resources/logback-spring.xml
Normal file
12
cim-boot-server/src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<withJansi>true</withJansi>
|
||||
<encoder>
|
||||
<pattern>[%thread] %d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{32}) - %msg %n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="info">
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
</configuration>
|
@ -3,9 +3,14 @@
|
||||
<ul class="ui-nav-inner">
|
||||
<li style="height: 50px;text-align: center;margin-top: 10px;">
|
||||
<a type="button" target="_blank" href="/webclient" class="btn btn-danger" >
|
||||
<span class="glyphicon glyphicon-globe"></span> WEB版本
|
||||
<span class="glyphicon glyphicon-globe"></span> 网页终端
|
||||
</a>
|
||||
</li>
|
||||
<li style="height: 50px;text-align: center;margin-top: 10px;">
|
||||
<a type="button" target="_blank" href="/swagger-ui/index.html" class="btn btn-success" >
|
||||
<span class="glyphicon glyphicon-leaf"></span> 接口文档
|
||||
</a>
|
||||
</li>
|
||||
<li style="border-bottom: 1px solid #D1D6DA;"></li>
|
||||
<li class="ui-item" id="sessionMenu">
|
||||
<a href="/console/session/list">
|
||||
|
@ -20,8 +20,7 @@ function showMessageDialog(account){
|
||||
function doSendMessage(){
|
||||
var message = $('#message').val();
|
||||
var account = $('#Saccount').val();
|
||||
if($.trim(message)=='')
|
||||
{
|
||||
if($.trim(message)===''){
|
||||
return;
|
||||
}
|
||||
showProcess("<@spring.message 'module.console.cimsession.sending'/>");
|
||||
@ -49,35 +48,33 @@ function doSendMessage(){
|
||||
<table style="width: 100%" class="utable">
|
||||
<thead>
|
||||
<tr class="tableHeader">
|
||||
<th width="8%"><@spring.message 'module.console.cimsession.account'/></th>
|
||||
<th width="6%"> <@spring.message 'module.console.cimsession.nid'/></th>
|
||||
<th width="6%"><@spring.message 'module.console.cimsession.channel'/></th>
|
||||
<th width="14%"><@spring.message 'module.console.cimsession.deviceid'/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.device.model'/></th>
|
||||
<th width="6%"><@spring.message 'module.console.cimsession.app.version'/></th>
|
||||
<th width="6%"><@spring.message 'module.console.cimsession.os.version'/></th>
|
||||
<th width="6%"><@spring.message 'module.console.cimsession.online.time'/></th>
|
||||
<th width="25%"><@spring.message 'module.common.location'/></th>
|
||||
<th width="8%"><@spring.message "module.common.operation"/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.account'/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.nid'/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.channel'/></th>
|
||||
<th width="20%"><@spring.message 'module.console.cimsession.deviceid'/></th>
|
||||
<th width="20%"><@spring.message 'module.console.cimsession.device.name'/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.app.version'/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.os.version'/></th>
|
||||
<th width="10%"><@spring.message 'module.console.cimsession.online.time'/></th>
|
||||
<th width="10%"><@spring.message "module.common.operation"/></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list sessionList as cimsession>
|
||||
<tr style="height: 50px;">
|
||||
<td>${cimsession.account! }</td>
|
||||
<td>${cimsession.uid! }</td>
|
||||
<td><#if cimsession.nid??>${cimsession.nid}</#if></td>
|
||||
<td>${cimsession.channel! }</td>
|
||||
<td>${cimsession.deviceId! }</td>
|
||||
<td>${cimsession.deviceModel! }</td>
|
||||
<td>${cimsession.clientVersion! }</td>
|
||||
<td>${cimsession.systemVersion! }</td>
|
||||
<td>${cimsession.deviceName! }</td>
|
||||
<td>${cimsession.appVersion! }</td>
|
||||
<td>${cimsession.osVersion! }</td>
|
||||
<td>
|
||||
<@spring.messageArgs "module.console.cimsession.time.format",[((.now?long - cimsession.bindTime)/1000)?round?c] />
|
||||
</td>
|
||||
<td>${cimsession.location!}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-xs">
|
||||
<button type="button" class="btn btn-primary" style="padding: 5px;" onclick="showMessageDialog('${cimsession.account!}')">
|
||||
<button type="button" class="btn btn-primary" style="padding: 5px;" onclick="showMessageDialog('${cimsession.uid!}')">
|
||||
<span class="glyphicon glyphicon-send" style="top:2px;"></span>
|
||||
<@spring.message 'module.console.cimsession.send.message'/>
|
||||
</button>
|
||||
|
@ -22,14 +22,14 @@
|
||||
|
||||
/** 当socket连接成功回调 **/
|
||||
function onConnectFinished(){
|
||||
CIMPushManager.bindAccount($('#account').val());
|
||||
CIMPushManager.bind($('#account').val());
|
||||
}
|
||||
|
||||
/** 当收到请求回复时候回调 **/
|
||||
function onReplyReceived(reply)
|
||||
{
|
||||
console.log(reply);
|
||||
if(reply.key=='client_bind' && reply.code==200)
|
||||
if(reply.key==='client_bind' && reply.code === "200" )
|
||||
{
|
||||
hideProcess();
|
||||
|
||||
@ -48,7 +48,10 @@
|
||||
function onMessageReceived(message)
|
||||
{
|
||||
console.log(message);
|
||||
if(message.action == ACTION_999){
|
||||
/*
|
||||
账户在其他地方登录了
|
||||
*/
|
||||
if(message.action === ACTION_999){
|
||||
$('#MessageDialog').fadeOut();
|
||||
$('#LoginDialog').fadeIn();
|
||||
$('#LoginDialog').addClass("in");
|
||||
@ -56,9 +59,8 @@
|
||||
}
|
||||
|
||||
showNotification(message.content);
|
||||
|
||||
$("#messageList").append("<h6 style='text-align: center;'>时间:"+new Date(message.timestamp).toLocaleString()+"</h6>");
|
||||
$("#messageList").append("<div class='alert alert-info' >"+message.content+"</div>");
|
||||
var time = new Date(message.timestamp).toLocaleString();
|
||||
$("#messageList").prepend("<div class='alert alert-info' >"+time+"</p></p>"+message.content+"</div>");
|
||||
}
|
||||
|
||||
|
||||
@ -83,8 +85,9 @@
|
||||
$(document).ready(function(){
|
||||
$('#LoginDialog').fadeIn();
|
||||
$('#LoginDialog').addClass("in");
|
||||
|
||||
initNotification();
|
||||
$('#host').val(CIM_HOST);
|
||||
$('#port').val(CIM_PORT);
|
||||
initNotification();
|
||||
});
|
||||
|
||||
|
||||
@ -130,12 +133,28 @@
|
||||
</div>
|
||||
|
||||
<div class="input-group" style="margin-top: 30px;margin-left:10px;margin-right:10px;margin-bottom:30px;">
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-user" aria-hidden="true"></span></span>
|
||||
<span class="input-group-addon">账号</span>
|
||||
<input type="text" class="form-control" id="account" maxlength="32" placeholder="帐号(数字或者英文字母)"
|
||||
style="display: inline; width: 100%; height: 50px;" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="alert alert-success" role="alert" style="margin: 0 10px;">
|
||||
cim.web.sdk.js中设置cim服务的IP(域名)和端口
|
||||
</div>
|
||||
|
||||
<div class="input-group" style="margin-top: 30px;margin-left:10px;margin-right:10px;margin-bottom:30px;">
|
||||
<span class="input-group-addon">host</span>
|
||||
<input type="text" class="form-control" id="host" maxlength="32" readonly = "readonly"
|
||||
style="display: inline; width: 100%; height: 50px;" />
|
||||
</div>
|
||||
|
||||
<div class="input-group" style="margin-top: 30px;margin-left:10px;margin-right:10px;margin-bottom:30px;">
|
||||
<span class="input-group-addon">port</span>
|
||||
<input type="text" class="form-control" id="port" maxlength="32" readonly = "readonly"
|
||||
style="display: inline; width: 100%; height: 50px;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" style="text-align: center;">
|
||||
<a type="button" class="btn btn-success btn-lg" onclick="doLogin()"
|
||||
style="width: 300px;">登录</a>
|
||||
@ -146,10 +165,13 @@
|
||||
|
||||
<!-- 消息提示页面 -->
|
||||
<div class="modal fade" data-backdrop="static" id="MessageDialog" tabindex="-1" role="dialog" >
|
||||
<div class="modal-dialog" style="width: 600px;margin: 30px auto;">
|
||||
<div class="alert alert-success" role="alert">
|
||||
通过<a href="/console/session/list" class="alert-link" target="_blank" >控制台</a>或者<a href="/swagger-ui/index.html" target="_blank" class="alert-link">调用接口</a>发送消息
|
||||
</div>
|
||||
<div class="modal-dialog" style="width: 720px;margin: 30px auto;">
|
||||
<div class="modal-content" >
|
||||
<div class="modal-header" style="text-align: center;">
|
||||
<span style="float: left;">请在管理页面推送一条消息</span>
|
||||
<span style="float: left;">消息显示面板</span>
|
||||
<span style="float: right;color: #4caf50;">当前帐号:<span id="current_account"></span></span>
|
||||
</div>
|
||||
<div class="modal-body" id="messageList" style="min-height: 600px;" >
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*CIM服务器IP*/
|
||||
const CIM_HOST = "127.0.0.1";
|
||||
const CIM_HOST = window.location.hostname;
|
||||
/*
|
||||
*服务端 websocket端口
|
||||
*/
|
||||
@ -7,7 +7,7 @@ const CIM_PORT = 34567;
|
||||
const CIM_URI = "ws://" + CIM_HOST + ":" + CIM_PORT;
|
||||
|
||||
const APP_VERSION = "1.0.0";
|
||||
const APP_CHANNEL = "browser";
|
||||
const APP_CHANNEL = "web";
|
||||
const APP_PACKAGE = "com.farsunset.cim";
|
||||
|
||||
/*
|
||||
@ -18,6 +18,15 @@ const DATA_HEADER_LENGTH = 1;
|
||||
|
||||
const MESSAGE = 2;
|
||||
const REPLY_BODY = 4;
|
||||
const SENT_BODY = 3;
|
||||
const PING = 1;
|
||||
const PONG = 0;
|
||||
/**
|
||||
* PONG字符串转换后
|
||||
* @type {Uint8Array}
|
||||
*/
|
||||
const PONG_BODY = new Uint8Array([80,79,78,71]);
|
||||
|
||||
|
||||
let socket;
|
||||
let manualStop = false;
|
||||
@ -33,12 +42,12 @@ CIMPushManager.connect = function () {
|
||||
socket.onclose = CIMPushManager.innerOnConnectionClosed;
|
||||
};
|
||||
|
||||
CIMPushManager.bindAccount = function (account) {
|
||||
CIMPushManager.bind = function (account) {
|
||||
|
||||
window.localStorage.account = account;
|
||||
|
||||
let deviceId = window.localStorage.deviceIddeviceId;
|
||||
if (deviceId == '' || deviceId == undefined) {
|
||||
let deviceId = window.localStorage.deviceId;
|
||||
if (deviceId === '' || deviceId === undefined) {
|
||||
deviceId = generateUUID();
|
||||
window.localStorage.deviceId = deviceId;
|
||||
}
|
||||
@ -47,13 +56,13 @@ CIMPushManager.bindAccount = function (account) {
|
||||
let body = new proto.com.farsunset.cim.sdk.web.model.SentBody();
|
||||
body.setKey("client_bind");
|
||||
body.setTimestamp(new Date().getTime());
|
||||
body.getDataMap().set("account", account);
|
||||
body.getDataMap().set("uid", account);
|
||||
body.getDataMap().set("channel", APP_CHANNEL);
|
||||
body.getDataMap().set("appVersion", APP_VERSION);
|
||||
body.getDataMap().set("osVersion", browser.version);
|
||||
body.getDataMap().set("packageName", APP_PACKAGE);
|
||||
body.getDataMap().set("deviceId", deviceId);
|
||||
body.getDataMap().set("device", browser.name);
|
||||
body.getDataMap().set("deviceName", browser.name);
|
||||
CIMPushManager.sendRequest(body);
|
||||
};
|
||||
|
||||
@ -83,13 +92,18 @@ CIMPushManager.innerOnMessageReceived = function (e) {
|
||||
let type = data[0];
|
||||
let body = data.subarray(DATA_HEADER_LENGTH, data.length);
|
||||
|
||||
if (type == MESSAGE) {
|
||||
if (type === PING) {
|
||||
CIMPushManager.pong();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === MESSAGE) {
|
||||
let message = proto.com.farsunset.cim.sdk.web.model.Message.deserializeBinary(body);
|
||||
onInterceptMessageReceived(message.toObject(false));
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == REPLY_BODY) {
|
||||
if (type === REPLY_BODY) {
|
||||
let message = proto.com.farsunset.cim.sdk.web.model.ReplyBody.deserializeBinary(body);
|
||||
/**
|
||||
* 将proto对象转换成json对象,去除无用信息
|
||||
@ -123,16 +137,24 @@ CIMPushManager.innerOnConnectionClosed = function (e) {
|
||||
|
||||
CIMPushManager.sendRequest = function (body) {
|
||||
let data = body.serializeBinary();
|
||||
let protobuf = new Uint8Array(data.length);
|
||||
protobuf.set(data, 0);
|
||||
let protobuf = new Uint8Array(data.length + 1);
|
||||
protobuf[0] = SENT_BODY;
|
||||
protobuf.set(data, 1);
|
||||
socket.send(protobuf);
|
||||
};
|
||||
|
||||
CIMPushManager.pong = function () {
|
||||
let pong = new Uint8Array(PONG_BODY.byteLength + 1);
|
||||
pong[0] = PONG;
|
||||
pong.set(PONG_BODY,1);
|
||||
socket.send(pong);
|
||||
};
|
||||
|
||||
function onInterceptMessageReceived(message) {
|
||||
/*
|
||||
*被强制下线之后,不再继续连接服务端
|
||||
*/
|
||||
if (message.action == ACTION_999) {
|
||||
if (message.action === ACTION_999) {
|
||||
manualStop = true;
|
||||
}
|
||||
/*
|
||||
@ -174,7 +196,7 @@ function generateUUID() {
|
||||
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
let r = (d + Math.random() * 16) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
});
|
||||
return uuid.replace(/-/g, '');
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
/*CIM服务器IP*/
|
||||
const CIM_HOST = "127.0.0.1";
|
||||
const CIM_HOST = window.location.hostname;
|
||||
/*
|
||||
*服务端 websocket端口
|
||||
*/
|
||||
@ -7,7 +7,7 @@ const CIM_PORT = 34567;
|
||||
const CIM_URI = "ws://" + CIM_HOST + ":" + CIM_PORT;
|
||||
|
||||
const APP_VERSION = "1.0.0";
|
||||
const APP_CHANNEL = "browser";
|
||||
const APP_CHANNEL = "web";
|
||||
const APP_PACKAGE = "com.farsunset.cim";
|
||||
|
||||
/*
|
||||
@ -18,6 +18,15 @@ const DATA_HEADER_LENGTH = 1;
|
||||
|
||||
const MESSAGE = 2;
|
||||
const REPLY_BODY = 4;
|
||||
const SENT_BODY = 3;
|
||||
const PING = 1;
|
||||
const PONG = 0;
|
||||
/**
|
||||
* PONG字符串转换后
|
||||
* @type {Uint8Array}
|
||||
*/
|
||||
const PONG_BODY = new Uint8Array([80,79,78,71]);
|
||||
|
||||
|
||||
let socket;
|
||||
let manualStop = false;
|
||||
@ -33,12 +42,12 @@ CIMPushManager.connect = function () {
|
||||
socket.onclose = CIMPushManager.innerOnConnectionClosed;
|
||||
};
|
||||
|
||||
CIMPushManager.bindAccount = function (account) {
|
||||
CIMPushManager.bind = function (account) {
|
||||
|
||||
window.localStorage.account = account;
|
||||
|
||||
let deviceId = window.localStorage.deviceIddeviceId;
|
||||
if (deviceId == '' || deviceId == undefined) {
|
||||
let deviceId = window.localStorage.deviceId;
|
||||
if (deviceId === '' || deviceId === undefined) {
|
||||
deviceId = generateUUID();
|
||||
window.localStorage.deviceId = deviceId;
|
||||
}
|
||||
@ -47,13 +56,13 @@ CIMPushManager.bindAccount = function (account) {
|
||||
let body = new proto.com.farsunset.cim.sdk.web.model.SentBody();
|
||||
body.setKey("client_bind");
|
||||
body.setTimestamp(new Date().getTime());
|
||||
body.getDataMap().set("account", account);
|
||||
body.getDataMap().set("uid", account);
|
||||
body.getDataMap().set("channel", APP_CHANNEL);
|
||||
body.getDataMap().set("appVersion", APP_VERSION);
|
||||
body.getDataMap().set("osVersion", browser.version);
|
||||
body.getDataMap().set("packageName", APP_PACKAGE);
|
||||
body.getDataMap().set("deviceId", deviceId);
|
||||
body.getDataMap().set("device", browser.name);
|
||||
body.getDataMap().set("deviceName", browser.name);
|
||||
CIMPushManager.sendRequest(body);
|
||||
};
|
||||
|
||||
@ -83,13 +92,18 @@ CIMPushManager.innerOnMessageReceived = function (e) {
|
||||
let type = data[0];
|
||||
let body = data.subarray(DATA_HEADER_LENGTH, data.length);
|
||||
|
||||
if (type == MESSAGE) {
|
||||
if (type === PING) {
|
||||
CIMPushManager.pong();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === MESSAGE) {
|
||||
let message = proto.com.farsunset.cim.sdk.web.model.Message.deserializeBinary(body);
|
||||
onInterceptMessageReceived(message.toObject(false));
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == REPLY_BODY) {
|
||||
if (type === REPLY_BODY) {
|
||||
let message = proto.com.farsunset.cim.sdk.web.model.ReplyBody.deserializeBinary(body);
|
||||
/**
|
||||
* 将proto对象转换成json对象,去除无用信息
|
||||
@ -123,16 +137,24 @@ CIMPushManager.innerOnConnectionClosed = function (e) {
|
||||
|
||||
CIMPushManager.sendRequest = function (body) {
|
||||
let data = body.serializeBinary();
|
||||
let protobuf = new Uint8Array(data.length);
|
||||
protobuf.set(data, 0);
|
||||
let protobuf = new Uint8Array(data.length + 1);
|
||||
protobuf[0] = SENT_BODY;
|
||||
protobuf.set(data, 1);
|
||||
socket.send(protobuf);
|
||||
};
|
||||
|
||||
CIMPushManager.pong = function () {
|
||||
let pong = new Uint8Array(PONG_BODY.byteLength + 1);
|
||||
pong[0] = PONG;
|
||||
pong.set(PONG_BODY,1);
|
||||
socket.send(pong);
|
||||
};
|
||||
|
||||
function onInterceptMessageReceived(message) {
|
||||
/*
|
||||
*被强制下线之后,不再继续连接服务端
|
||||
*/
|
||||
if (message.action == ACTION_999) {
|
||||
if (message.action === ACTION_999) {
|
||||
manualStop = true;
|
||||
}
|
||||
/*
|
||||
@ -174,7 +196,7 @@ function generateUUID() {
|
||||
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
let r = (d + Math.random() * 16) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
});
|
||||
return uuid.replace(/-/g, '');
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.farsunset</groupId>
|
||||
<artifactId>cim-android-sdk</artifactId>
|
||||
<version>3.8.2</version>
|
||||
<version>4.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
|
@ -29,7 +29,7 @@ import android.net.Uri;
|
||||
|
||||
class CIMCacheManager {
|
||||
|
||||
public static final String KEY_ACCOUNT = "KEY_ACCOUNT";
|
||||
public static final String KEY_UID = "KEY_UID";
|
||||
|
||||
public static final String KEY_DEVICE_ID = "KEY_DEVICE_ID";
|
||||
|
||||
@ -100,5 +100,4 @@ class CIMCacheManager {
|
||||
String value = getString(context, key);
|
||||
return value == null ? 0 : Integer.parseInt(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,13 +58,11 @@ class CIMConnectorManager {
|
||||
/*
|
||||
服务端在连接写空闲120秒的时候发送心跳请求给客户端,所以客户端在空闲150秒后都没有收到任何数据,则关闭链接,并重新创建
|
||||
*/
|
||||
private static final int CONNECT_ALIVE_TIME_OUT = 150 * 1000;
|
||||
private static final int CONNECT_ALIVE_TIME_OUT = 120 * 1000;
|
||||
|
||||
private static final CIMLogger LOGGER = CIMLogger.getLogger();
|
||||
|
||||
private static final HandlerThread IDLE_HANDLER_THREAD = new HandlerThread("READ-IDLE", Process.THREAD_PRIORITY_BACKGROUND);
|
||||
|
||||
private volatile SocketChannel socketChannel;
|
||||
private SocketChannel socketChannel;
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -77,15 +75,11 @@ class CIMConnectorManager {
|
||||
private final ClientMessageEncoder messageEncoder = new ClientMessageEncoder();
|
||||
private final ClientMessageDecoder messageDecoder = new ClientMessageDecoder();
|
||||
|
||||
static {
|
||||
IDLE_HANDLER_THREAD.start();
|
||||
}
|
||||
|
||||
private CIMConnectorManager(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public synchronized static CIMConnectorManager getManager(Context context) {
|
||||
public static synchronized CIMConnectorManager getManager(Context context) {
|
||||
|
||||
if (manager == null) {
|
||||
manager = new CIMConnectorManager(context);
|
||||
@ -272,10 +266,10 @@ class CIMConnectorManager {
|
||||
}
|
||||
}
|
||||
|
||||
private final Handler idleHandler = new Handler(IDLE_HANDLER_THREAD.getLooper()) {
|
||||
private final Handler idleHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(android.os.Message m) {
|
||||
onSessionIdle();
|
||||
workerExecutor.execute(() -> onSessionIdle());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -184,7 +184,6 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
|
||||
return CIMConstant.MessageAction.ACTION_999.equals(action);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 接收消息实现方法
|
||||
*
|
||||
|
@ -82,4 +82,5 @@ public interface CIMEventListener {
|
||||
* @return 排序 值越大优先级越高
|
||||
*/
|
||||
int getEventDispatchOrder();
|
||||
|
||||
}
|
||||
|
@ -30,14 +30,13 @@ import com.farsunset.cim.sdk.android.model.SentBody;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* CIM 消息监听器管理
|
||||
*/
|
||||
public class CIMListenerManager {
|
||||
|
||||
private static final ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>();
|
||||
private static final ArrayList<CIMEventListener> cimListeners = new ArrayList<>();
|
||||
private static final ReceiveComparator comparator = new ReceiveComparator();
|
||||
|
||||
private CIMListenerManager() {
|
||||
@ -48,70 +47,57 @@ public class CIMListenerManager {
|
||||
|
||||
if (!cimListeners.contains(listener)) {
|
||||
cimListeners.add(listener);
|
||||
Collections.sort(cimListeners, comparator);
|
||||
Collections.sort(cimListeners,comparator);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeMessageListener(CIMEventListener listener) {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
CIMEventListener target = iterable.next();
|
||||
if (listener.getClass() == target.getClass()) {
|
||||
iterable.remove();
|
||||
}
|
||||
}
|
||||
cimListeners.remove(listener);
|
||||
}
|
||||
|
||||
public static void notifyOnNetworkChanged(NetworkInfo info) {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onNetworkChanged(info);
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onNetworkChanged(info);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectFinished(boolean hasAutoBind) {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onConnectFinished(hasAutoBind);
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onConnectFinished(hasAutoBind);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnMessageReceived(Message message) {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onMessageReceived(message);
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onMessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionClosed() {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onConnectionClosed();
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onConnectionClosed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectFailed() {
|
||||
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onConnectFailed();
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onConnectFailed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void notifyOnReplyReceived(ReplyBody body) {
|
||||
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onReplyReceived(body);
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onReplyReceived(body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void notifyOnSendFinished(SentBody body) {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
iterable.next().onSendFinished(body);
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
cimListener.onSendFinished(body);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,9 +106,8 @@ public class CIMListenerManager {
|
||||
}
|
||||
|
||||
public static void logListenersName() {
|
||||
Iterator<CIMEventListener> iterable = cimListeners.iterator();
|
||||
while (iterable.hasNext()) {
|
||||
Log.i(CIMEventListener.class.getSimpleName(), "#######" + iterable.next().getClass().getName() + "#######");
|
||||
for (CIMEventListener cimListener : cimListeners) {
|
||||
Log.i(CIMEventListener.class.getSimpleName(), "#######" + cimListener.getClass().getName() + "#######");
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +118,6 @@ public class CIMListenerManager {
|
||||
|
||||
@Override
|
||||
public int compare(CIMEventListener arg1, CIMEventListener arg2) {
|
||||
|
||||
int order1 = arg1.getEventDispatchOrder();
|
||||
int order2 = arg2.getEventDispatchOrder();
|
||||
return Integer.compare(order2, order1);
|
||||
|
@ -69,14 +69,11 @@ public class CIMPushManager {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CIMCacheManager.putString(context, CIMCacheManager.KEY_CIM_SERVER_HOST, host);
|
||||
CIMCacheManager.putInt(context, CIMCacheManager.KEY_CIM_SERVER_PORT, port);
|
||||
|
||||
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_DESTROYED, false);
|
||||
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_MANUAL_STOP, false);
|
||||
|
||||
CIMCacheManager.remove(context, CIMCacheManager.KEY_ACCOUNT);
|
||||
CIMCacheManager.remove(context, CIMCacheManager.KEY_UID);
|
||||
|
||||
|
||||
Intent serviceIntent = new Intent(context, CIMPushService.class);
|
||||
@ -110,13 +107,33 @@ public class CIMPushManager {
|
||||
/**
|
||||
* 设置一个账号登录到服务端
|
||||
*/
|
||||
public static void bindAccount(Context context, String account) {
|
||||
|
||||
if (isDestroyed(context) || account == null || account.trim().length() == 0) {
|
||||
public static void bind(Context context, long uid) {
|
||||
bind(context,String.valueOf(uid));
|
||||
}
|
||||
public static void bind(Context context, String uid) {
|
||||
|
||||
if (isDestroyed(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendBindRequest(context, account);
|
||||
sendBindRequest(context, uid);
|
||||
}
|
||||
|
||||
public static void setTag(Context context, String tag) {
|
||||
|
||||
SentBody sent = new SentBody();
|
||||
sent.setKey(CIMConstant.RequestKey.CLIENT_SET_TAG);
|
||||
sent.put("tag", tag);
|
||||
sendRequest(context, sent);
|
||||
|
||||
}
|
||||
|
||||
public static void removeTag(Context context) {
|
||||
|
||||
SentBody sent = new SentBody();
|
||||
sent.setKey(CIMConstant.RequestKey.CLIENT_REMOVE_TAG);
|
||||
sendRequest(context, sent);
|
||||
|
||||
}
|
||||
|
||||
@ -130,18 +147,17 @@ public class CIMPushManager {
|
||||
startService(context, serviceIntent);
|
||||
}
|
||||
|
||||
private static void sendBindRequest(Context context, String account) {
|
||||
private static void sendBindRequest(Context context, String uid) {
|
||||
|
||||
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_MANUAL_STOP, false);
|
||||
CIMCacheManager.putString(context, CIMCacheManager.KEY_ACCOUNT, account);
|
||||
|
||||
CIMCacheManager.putString(context, CIMCacheManager.KEY_UID, uid);
|
||||
|
||||
SentBody sent = new SentBody();
|
||||
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
|
||||
sent.put("account", account);
|
||||
sent.put("deviceId", getDeviceId(context));
|
||||
sent.put("uid", String.valueOf(uid));
|
||||
sent.put("channel", "android");
|
||||
sent.put("device", Build.MODEL);
|
||||
sent.put("deviceId", getDeviceId(context));
|
||||
sent.put("deviceName", Build.MODEL);
|
||||
sent.put("appVersion", getVersionName(context));
|
||||
sent.put("osVersion", Build.VERSION.RELEASE);
|
||||
sent.put("packageName", context.getPackageName());
|
||||
@ -151,12 +167,13 @@ public class CIMPushManager {
|
||||
|
||||
protected static boolean autoBindAccount(Context context) {
|
||||
|
||||
String account = CIMCacheManager.getString(context, CIMCacheManager.KEY_ACCOUNT);
|
||||
if (account == null || account.trim().length() == 0 || isDestroyed(context)) {
|
||||
String uid = CIMCacheManager.getString(context, CIMCacheManager.KEY_UID);
|
||||
|
||||
if (uid == null || isDestroyed(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sendBindRequest(context, account);
|
||||
sendBindRequest(context, uid);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -200,7 +217,7 @@ public class CIMPushManager {
|
||||
public static void destroy(Context context) {
|
||||
|
||||
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_DESTROYED, true);
|
||||
CIMCacheManager.putString(context, CIMCacheManager.KEY_ACCOUNT, null);
|
||||
CIMCacheManager.remove(context, CIMCacheManager.KEY_UID);
|
||||
|
||||
Intent serviceIntent = new Intent(context, CIMPushService.class);
|
||||
serviceIntent.setAction(ACTION_DESTROY_CIM_SERVICE);
|
||||
|
@ -72,7 +72,7 @@ public class ClientMessageDecoder {
|
||||
/*
|
||||
消息读取完成后,通过type来解析成对应的消息体
|
||||
*/
|
||||
if (CIMConstant.ProtobufType.S_H_RQ == type) {
|
||||
if (CIMConstant.ProtobufType.PING == type) {
|
||||
return Ping.getInstance();
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,12 @@ public interface CIMConstant {
|
||||
/*
|
||||
客户端->服务端 发送的心跳响应
|
||||
*/
|
||||
byte C_H_RS = 0;
|
||||
byte PONG = 0;
|
||||
|
||||
/*
|
||||
服务端->客户端 发送的心跳请求
|
||||
*/
|
||||
byte S_H_RQ = 1;
|
||||
byte PING = 1;
|
||||
|
||||
byte MESSAGE = 2;
|
||||
|
||||
@ -53,6 +53,10 @@ public interface CIMConstant {
|
||||
|
||||
String CLIENT_BIND = "client_bind";
|
||||
|
||||
String CLIENT_SET_TAG = "client_set_tag";
|
||||
|
||||
String CLIENT_REMOVE_TAG = "client_remove_tag";
|
||||
|
||||
}
|
||||
|
||||
interface MessageAction {
|
||||
|
@ -30,7 +30,7 @@ import java.nio.channels.SocketChannel;
|
||||
* 日志打印,添加session 的id和ip address
|
||||
*/
|
||||
public class CIMLogger {
|
||||
private final static String TAG = "CIM";
|
||||
private static final String TAG = "CIM";
|
||||
private boolean debug = true;
|
||||
|
||||
public static CIMLogger getLogger() {
|
||||
@ -51,13 +51,13 @@ public class CIMLogger {
|
||||
|
||||
public void messageReceived(SocketChannel session, Object message) {
|
||||
if (debug) {
|
||||
Log.i(TAG, String.format("[RECEIVED]" + getSessionInfo(session) + "\n%s", message));
|
||||
Log.i(TAG, "[RECEIVED]" + getSessionInfo(session) + "\n" + message);
|
||||
}
|
||||
}
|
||||
|
||||
public void messageSent(SocketChannel session, Object message) {
|
||||
if (debug) {
|
||||
Log.i(TAG, String.format("[ SENT ]" + getSessionInfo(session) + "\n%s", message));
|
||||
Log.i(TAG,"[ SENT ]" + getSessionInfo(session) + "\n" + message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,16 +115,13 @@ public class CIMLogger {
|
||||
if (session.socket().getLocalAddress() != null) {
|
||||
builder.append(" L:").append(session.socket().getLocalAddress()).append(":").append(session.socket().getLocalPort());
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
try {
|
||||
if (session.socket().getRemoteSocketAddress() != null) {
|
||||
builder.append(" R:").append(session.socket().getRemoteSocketAddress().toString());
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
@ -73,6 +73,15 @@ public class Message implements Serializable {
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
@ -154,17 +163,4 @@ public class Message implements Serializable {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isNotEmpty(String txt) {
|
||||
return txt != null && txt.trim().length() != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,42 +21,29 @@
|
||||
*/
|
||||
package com.farsunset.cim.sdk.android.model;
|
||||
|
||||
import com.farsunset.cim.sdk.android.constant.CIMConstant;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 服务端心跳请求
|
||||
*/
|
||||
public class Ping implements Serializable, BinaryBody {
|
||||
public class Ping implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = "SERVER_HEARTBEAT_REQUEST";
|
||||
private static final String CMD_HEARTBEAT_REQUEST = "SR";
|
||||
private static final String TAG = "PING";
|
||||
|
||||
private static final Ping object = new Ping();
|
||||
|
||||
private Ping() {
|
||||
|
||||
}
|
||||
|
||||
public static Ping getInstance() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return CMD_HEARTBEAT_REQUEST.getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getType() {
|
||||
return CIMConstant.ProtobufType.S_H_RQ;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ import java.io.Serializable;
|
||||
public class Pong implements Serializable, BinaryBody {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = "CLIENT_HEARTBEAT_RESPONSE";
|
||||
private static final String CMD_HEARTBEAT_RESPONSE = "CR";
|
||||
private static final String TAG = "PONG";
|
||||
private static final String CMD_PONG = "PONG";
|
||||
|
||||
private static final Pong object = new Pong();
|
||||
|
||||
@ -46,7 +46,7 @@ public class Pong implements Serializable, BinaryBody {
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return CMD_HEARTBEAT_RESPONSE.getBytes();
|
||||
return CMD_PONG.getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,7 +56,7 @@ public class Pong implements Serializable, BinaryBody {
|
||||
|
||||
@Override
|
||||
public byte getType() {
|
||||
return CIMConstant.ProtobufType.C_H_RS;
|
||||
return CIMConstant.ProtobufType.PONG;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,8 +21,10 @@
|
||||
*/
|
||||
package com.farsunset.cim.sdk.android.model;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Hashtable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ -53,7 +55,7 @@ public class ReplyBody implements Serializable {
|
||||
/**
|
||||
* 返回数据集合
|
||||
*/
|
||||
private final Hashtable<String, String> data = new Hashtable<String, String>();
|
||||
private final Map<String, String> data = new HashMap<>();
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
|
@ -21,11 +21,13 @@
|
||||
*/
|
||||
package com.farsunset.cim.sdk.android.model;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import com.farsunset.cim.sdk.android.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.android.model.proto.SentBodyProto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Hashtable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -37,7 +39,7 @@ public class SentBody implements Serializable, BinaryBody {
|
||||
|
||||
private String key;
|
||||
|
||||
private final Hashtable<String, String> data = new Hashtable<String, String>();
|
||||
private final Map<String, String> data = new HashMap<>();
|
||||
|
||||
private long timestamp;
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>BundleSDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>CIMKit.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>CimKit.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
@ -15,7 +15,7 @@
|
||||
|
||||
/// 心跳包数据
|
||||
+(NSData *)initHeartbeatData{
|
||||
NSData * model = [@"CR" convertBytesStringToData];
|
||||
NSData * model = [@"PONG" convertBytesStringToData];
|
||||
NSInteger lenght = model.length;
|
||||
Byte type = 0;
|
||||
Byte head[3] ;
|
||||
@ -35,27 +35,7 @@
|
||||
SentBodyModel * body = [SentBodyModel new];
|
||||
body.key = @"client_bind";
|
||||
body.timestamp = (int64_t)[NSDate timeIntervalSinceReferenceDate] *1000;
|
||||
body.data_p[@"account"] = userId;
|
||||
body.data_p[@"deviceId"] = [[self class] deviceId];
|
||||
body.data_p[@"channel"] = @"ios";
|
||||
NSData *modeData = body.data;
|
||||
NSInteger lenght = modeData.length;
|
||||
Byte type = 3;
|
||||
Byte head[3] ;
|
||||
head[0] = type;
|
||||
head[1] = lenght & 0xff;
|
||||
head[2] = (lenght >> 8) & 0xff;
|
||||
NSMutableData * sendData = [[NSMutableData alloc] initWithBytes:head length:3];
|
||||
[sendData appendData:modeData];
|
||||
return sendData;
|
||||
|
||||
}
|
||||
|
||||
+(NSData *)initMessageData:(NSString *)userId{
|
||||
SentBodyModel * body = [SentBodyModel new];
|
||||
body.key = @"client_bind";
|
||||
body.timestamp = (int64_t)[NSDate timeIntervalSinceReferenceDate] *1000;
|
||||
body.data_p[@"account"] = userId;
|
||||
body.data_p[@"uid"] = userId;
|
||||
body.data_p[@"deviceId"] = [[self class] deviceId];
|
||||
body.data_p[@"channel"] = @"ios";
|
||||
NSData *modeData = body.data;
|
||||
|
@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: com.google.protobuf:protobuf-java:3.11.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.farsunset</groupId>
|
||||
<artifactId>cim-java-sdk</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<protobuf.version>3.11.1</protobuf.version>
|
||||
<slf4j.version>1.7.30</slf4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>${protobuf.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
class CIMCacheManager {
|
||||
|
||||
private static final HashMap<String, String> CIM_CONFIG_INFO = new HashMap<String, String>();
|
||||
|
||||
public static final String KEY_MANUAL_STOP = "KEY_MANUAL_STOP";
|
||||
|
||||
public static final String KEY_CIM_DESTROYED = "KEY_CIM_DESTROYED";
|
||||
|
||||
public static final String KEY_CIM_SERVER_HOST = "KEY_CIM_SERVER_HOST";
|
||||
|
||||
public static final String KEY_CIM_SERVER_PORT = "KEY_CIM_SERVER_PORT";
|
||||
|
||||
public static final String KEY_CIM_CONNECTION_STATE = "KEY_CIM_CONNECTION_STATE";
|
||||
|
||||
static CIMCacheManager toolkit;
|
||||
|
||||
public static CIMCacheManager getInstance() {
|
||||
if (toolkit == null) {
|
||||
toolkit = new CIMCacheManager();
|
||||
}
|
||||
return toolkit;
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
CIM_CONFIG_INFO.remove(key);
|
||||
}
|
||||
|
||||
public void putString(String key, String value) {
|
||||
CIM_CONFIG_INFO.put(key, value);
|
||||
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return CIM_CONFIG_INFO.get(key);
|
||||
}
|
||||
|
||||
public void putBoolean(String key, boolean value) {
|
||||
putString(key, Boolean.toString(value));
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key) {
|
||||
String value = getString(key);
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
public void putInt(String key, int value) {
|
||||
putString(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
String value = getString(key);
|
||||
return value == null ? 0 : Integer.parseInt(value);
|
||||
}
|
||||
|
||||
}
|
@ -1,294 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.farsunset.cim.sdk.client.coder.CIMLogger;
|
||||
import com.farsunset.cim.sdk.client.coder.ClientMessageDecoder;
|
||||
import com.farsunset.cim.sdk.client.coder.ClientMessageEncoder;
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.HeartbeatRequest;
|
||||
import com.farsunset.cim.sdk.client.model.HeartbeatResponse;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.Protobufable;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
|
||||
/**
|
||||
* 连接服务端管理,cim核心处理类,管理连接,以及消息处理
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
class CIMConnectorManager {
|
||||
|
||||
private static CIMConnectorManager manager;
|
||||
|
||||
private final int READ_BUFFER_SIZE = 2048;
|
||||
private final int WRITE_BUFFER_SIZE = 1024;
|
||||
private final int CONNECT_TIME_OUT = 10 * 1000;
|
||||
|
||||
private final CIMLogger LOGGER = CIMLogger.getLogger();
|
||||
|
||||
private SocketChannel socketChannel ;
|
||||
|
||||
private ByteBuffer readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
|
||||
|
||||
private final ExecutorService workerExecutor = Executors.newFixedThreadPool(1, r -> new Thread(r,"worker-"));
|
||||
private final ExecutorService bossExecutor = Executors.newFixedThreadPool(1, r -> new Thread(r,"boss-"));
|
||||
private final ExecutorService eventExecutor = Executors.newFixedThreadPool(1, r -> new Thread(r,"event-"));
|
||||
|
||||
|
||||
private final ClientMessageEncoder messageEncoder = new ClientMessageEncoder();
|
||||
private final ClientMessageDecoder messageDecoder = new ClientMessageDecoder();
|
||||
|
||||
private final ByteBuffer headerBuffer = ByteBuffer.allocate(CIMConstant.DATA_HEADER_LENGTH);
|
||||
|
||||
|
||||
public synchronized static CIMConnectorManager getManager() {
|
||||
|
||||
if (manager == null) {
|
||||
manager = new CIMConnectorManager();
|
||||
}
|
||||
|
||||
return manager;
|
||||
|
||||
}
|
||||
|
||||
public void connect(final String host, final int port) {
|
||||
|
||||
|
||||
if (isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bossExecutor.execute(() -> {
|
||||
|
||||
if (isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.startConnect(host, port);
|
||||
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
|
||||
|
||||
try {
|
||||
|
||||
socketChannel = SocketChannel.open();
|
||||
socketChannel.configureBlocking(true);
|
||||
socketChannel.socket().setTcpNoDelay(true);
|
||||
socketChannel.socket().setKeepAlive(true);
|
||||
socketChannel.socket().setReceiveBufferSize(READ_BUFFER_SIZE);
|
||||
socketChannel.socket().setSendBufferSize(WRITE_BUFFER_SIZE);
|
||||
|
||||
socketChannel.socket().connect(new InetSocketAddress(host, port),CONNECT_TIME_OUT);
|
||||
|
||||
handleConnectedEvent();
|
||||
|
||||
|
||||
/*
|
||||
*开始读取来自服务端的消息,先读取3个字节的消息头
|
||||
*/
|
||||
while (socketChannel.read(headerBuffer) > 0) {
|
||||
handleSocketReadEvent();
|
||||
}
|
||||
|
||||
/*
|
||||
*read 返回 <= 0的情况,发生了意外需要断开重链
|
||||
*/
|
||||
closeSession();
|
||||
|
||||
}catch(ConnectException | SocketTimeoutException ignore){
|
||||
handleConnectAbortedEvent();
|
||||
} catch(IOException ignore) {
|
||||
handleDisconnectedEvent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleDisconnectedEvent() {
|
||||
closeSession();
|
||||
}
|
||||
|
||||
private void handleConnectAbortedEvent() {
|
||||
|
||||
long interval = CIMConstant.RECONNECT_INTERVAL_TIME - (5 * 1000 - new Random().nextInt(15 * 1000));
|
||||
|
||||
LOGGER.connectFailure(interval);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECT_FAILED);
|
||||
intent.putExtra("interval", interval);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
|
||||
private void handleConnectedEvent() {
|
||||
|
||||
sessionCreated();
|
||||
}
|
||||
|
||||
private void handleSocketReadEvent() throws IOException {
|
||||
|
||||
Object message = messageDecoder.doDecode(headerBuffer,socketChannel);
|
||||
|
||||
LOGGER.messageReceived(socketChannel, message);
|
||||
|
||||
if (isHeartbeatRequest(message)) {
|
||||
send(HeartbeatResponse.getInstance());
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageReceived(message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void send(final Protobufable body) {
|
||||
|
||||
if(!isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
workerExecutor.execute(() -> {
|
||||
int result = 0;
|
||||
try {
|
||||
|
||||
ByteBuffer buffer = messageEncoder.encode(body);
|
||||
while(buffer.hasRemaining()){
|
||||
result += socketChannel.write(buffer);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
result = -1;
|
||||
}finally {
|
||||
|
||||
if(result <= 0) {
|
||||
closeSession();
|
||||
}else {
|
||||
messageSent(body);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void sessionCreated() {
|
||||
|
||||
LOGGER.sessionCreated(socketChannel);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECT_FINISHED);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
|
||||
public void sessionClosed() {
|
||||
|
||||
LOGGER.sessionClosed(socketChannel);
|
||||
|
||||
readBuffer.clear();
|
||||
|
||||
if(readBuffer.capacity() > READ_BUFFER_SIZE) {
|
||||
readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
|
||||
public void messageReceived(Object data) {
|
||||
|
||||
if (data instanceof Message) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED);
|
||||
intent.putExtra(Message.class.getName(), data);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
if (data instanceof ReplyBody) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED);
|
||||
intent.putExtra(ReplyBody.class.getName(), data);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void messageSent(Object data) {
|
||||
|
||||
LOGGER.messageSent(socketChannel, data);
|
||||
|
||||
if (data instanceof SentBody) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(CIMConstant.IntentAction.ACTION_SEND_FINISHED);
|
||||
intent.putExtra(SentBody.class.getName(), data);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHeartbeatRequest(Object data) {
|
||||
return data instanceof HeartbeatRequest;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
closeSession();
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return socketChannel != null && socketChannel.isConnected();
|
||||
}
|
||||
|
||||
public void closeSession() {
|
||||
|
||||
if(!isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
socketChannel.close();
|
||||
} catch (IOException ignore) {
|
||||
}finally {
|
||||
this.sessionClosed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sendBroadcast(final Intent intent) {
|
||||
eventExecutor.execute(() -> CIMEventBroadcastReceiver.getInstance().onReceive(intent));
|
||||
}
|
||||
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* 消息入口,所有消息都会经过这里
|
||||
*/
|
||||
public class CIMEventBroadcastReceiver {
|
||||
private static CIMEventBroadcastReceiver receiver;
|
||||
private CIMEventListener listener;
|
||||
|
||||
private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, r -> {
|
||||
Thread thread = new Thread(r);
|
||||
thread.setName("cim-reconnect-");
|
||||
return thread;
|
||||
});
|
||||
|
||||
private CIMEventBroadcastReceiver(){
|
||||
|
||||
}
|
||||
public static CIMEventBroadcastReceiver getInstance() {
|
||||
if (receiver == null) {
|
||||
receiver = new CIMEventBroadcastReceiver();
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public void setGlobalCIMEventListener(CIMEventListener ls) {
|
||||
listener = ls;
|
||||
}
|
||||
|
||||
public void onReceive(Intent intent) {
|
||||
|
||||
/*
|
||||
* cim断开服务器事件
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED)) {
|
||||
onInnerConnectionClosed();
|
||||
}
|
||||
|
||||
/*
|
||||
* cim连接服务器失败事件
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECT_FAILED)) {
|
||||
long interval = intent.getLongExtra("interval", CIMConstant.RECONNECT_INTERVAL_TIME);
|
||||
onInnerConnectFailed(interval);
|
||||
}
|
||||
|
||||
/*
|
||||
* cim连接服务器成功事件
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECT_FINISHED)) {
|
||||
onInnerConnectFinished();
|
||||
}
|
||||
|
||||
/*
|
||||
* 收到推送消息事件
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED)) {
|
||||
onInnerMessageReceived((Message) intent.getExtra(Message.class.getName()));
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取收到replyBody成功事件
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED)) {
|
||||
listener.onReplyReceived((ReplyBody) intent.getExtra(ReplyBody.class.getName()));
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取sendBody发送成功事件
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_SEND_FINISHED)) {
|
||||
onInnerSendFinished((SentBody) intent.getExtra(SentBody.class.getName()));
|
||||
}
|
||||
|
||||
/*
|
||||
* 重新连接,如果断开的话
|
||||
*/
|
||||
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECTION_RECOVERY)) {
|
||||
CIMPushManager.connect();
|
||||
}
|
||||
}
|
||||
|
||||
private void onInnerConnectionClosed() {
|
||||
|
||||
listener.onConnectionClosed();
|
||||
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
|
||||
CIMPushManager.connect();
|
||||
|
||||
}
|
||||
|
||||
private void onInnerConnectFailed(long interval) {
|
||||
|
||||
executorService.schedule((Runnable) CIMPushManager::connect,interval, TimeUnit.MICROSECONDS);
|
||||
|
||||
listener.onConnectFailed();
|
||||
}
|
||||
|
||||
private void onInnerConnectFinished() {
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_CIM_CONNECTION_STATE, true);
|
||||
|
||||
boolean autoBind = CIMPushManager.autoBindDeviceId();
|
||||
|
||||
listener.onConnectFinished(autoBind);
|
||||
}
|
||||
|
||||
|
||||
private void onInnerMessageReceived(Message message) {
|
||||
if (isForceOfflineMessage(message.getAction())) {
|
||||
CIMPushManager.stop();
|
||||
}
|
||||
|
||||
listener.onMessageReceived(message);
|
||||
}
|
||||
|
||||
private boolean isForceOfflineMessage(String action) {
|
||||
return CIMConstant.MessageAction.ACTION_999.equals(action);
|
||||
}
|
||||
|
||||
private void onInnerSendFinished(SentBody body) {
|
||||
listener.onSendFinished(body);
|
||||
}
|
||||
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* CIM 主要事件接口
|
||||
*/
|
||||
public interface CIMEventListener {
|
||||
|
||||
/**
|
||||
* 当收到服务端推送过来的消息时调用
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
void onMessageReceived(Message message);
|
||||
|
||||
/**
|
||||
* 当调用CIMPushManager.sendRequest()向服务端发送请求,获得相应时调用
|
||||
*
|
||||
* @param body
|
||||
*/
|
||||
void onReplyReceived(ReplyBody body);
|
||||
|
||||
/**
|
||||
* 当调用CIMPushManager.sendRequest()向服务端发送请求成功
|
||||
* @param body
|
||||
*/
|
||||
void onSendFinished(SentBody body);
|
||||
|
||||
/**
|
||||
* 当连接服务器成功时回调
|
||||
*
|
||||
* @param hasAutoBind
|
||||
* : true 已经自动绑定账号到服务器了,不需要再手动调用bindAccount
|
||||
*/
|
||||
void onConnectFinished(boolean hasAutoBind);
|
||||
|
||||
/**
|
||||
* 当断开服务器连接的时候回调
|
||||
*/
|
||||
void onConnectionClosed();
|
||||
|
||||
/**
|
||||
* 当服务器连接失败的时候回调
|
||||
*
|
||||
*/
|
||||
void onConnectFailed();
|
||||
|
||||
/**
|
||||
* 监听器在容器里面的排序。值越大则越先接收
|
||||
* @return 值越大优先级越高
|
||||
*/
|
||||
int getEventDispatchOrder();
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
|
||||
/**
|
||||
* CIM 消息监听器管理
|
||||
*/
|
||||
public class CIMListenerManager {
|
||||
|
||||
private static final ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>();
|
||||
private static final CIMMessageReceiveComparator comparator = new CIMMessageReceiveComparator();
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CIMListenerManager.class);
|
||||
|
||||
public static void registerMessageListener(CIMEventListener listener) {
|
||||
|
||||
if (!cimListeners.contains(listener)) {
|
||||
cimListeners.add(listener);
|
||||
Collections.sort(cimListeners, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeMessageListener(CIMEventListener listener) {
|
||||
for (int i = 0; i < cimListeners.size(); i++) {
|
||||
if (listener.getClass() == cimListeners.get(i).getClass()) {
|
||||
cimListeners.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectFinished(boolean autoBind) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectFinished(autoBind);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnMessageReceived(Message message) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onMessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionClosed() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionClosed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnReplyReceived(ReplyBody body) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onReplyReceived(body);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectFailed() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectFailed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
cimListeners.clear();
|
||||
}
|
||||
|
||||
public static void logListenersName() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
LOGGER.debug("#######" + listener.getClass().getName() + "#######");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息接收activity的接收顺序排序,CIM_RECEIVE_ORDER倒序
|
||||
*/
|
||||
private static class CIMMessageReceiveComparator implements Comparator<CIMEventListener> {
|
||||
|
||||
@Override
|
||||
public int compare(CIMEventListener arg1, CIMEventListener arg2) {
|
||||
|
||||
int order1 = arg1.getEventDispatchOrder();
|
||||
int order2 = arg2.getEventDispatchOrder();
|
||||
return order2 - order1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* CIM 功能接口
|
||||
*/
|
||||
public class CIMPushManager {
|
||||
|
||||
static String ACTION_ACTIVATE_PUSH_SERVICE = "ACTION_ACTIVATE_PUSH_SERVICE";
|
||||
|
||||
static String ACTION_CREATE_CIM_CONNECTION = "ACTION_CREATE_CIM_CONNECTION";
|
||||
|
||||
static String ACTION_SEND_REQUEST_BODY = "ACTION_SEND_REQUEST_BODY";
|
||||
|
||||
static String ACTION_CLOSE_CIM_CONNECTION = "ACTION_CLOSE_CIM_CONNECTION";
|
||||
|
||||
static String ACTION_DESTROY = "ACTION_DESTROY";
|
||||
|
||||
|
||||
/**
|
||||
* 销毁的
|
||||
*/
|
||||
public static final int STATE_DESTROYED = 0x0000DE;
|
||||
/**
|
||||
* 停止推送
|
||||
*/
|
||||
public static final int STATE_STOPPED = 0x0000EE;
|
||||
|
||||
/**
|
||||
* 正常
|
||||
*/
|
||||
public static final int STATE_NORMAL = 0x000000;
|
||||
|
||||
/**
|
||||
* 初始化,连接服务端,在程序启动页或者 在Application里调用
|
||||
*
|
||||
* @param ip
|
||||
* @param port
|
||||
*/
|
||||
|
||||
public static void connect(String ip, int port) {
|
||||
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_CIM_DESTROYED, false);
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_MANUAL_STOP, false);
|
||||
|
||||
CIMCacheManager.getInstance().putString(CIMCacheManager.KEY_CIM_SERVER_HOST, ip);
|
||||
CIMCacheManager.getInstance().putInt(CIMCacheManager.KEY_CIM_SERVER_PORT, port);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra(CIMCacheManager.KEY_CIM_SERVER_HOST, ip);
|
||||
serviceIntent.putExtra(CIMCacheManager.KEY_CIM_SERVER_PORT, port);
|
||||
serviceIntent.setAction(ACTION_CREATE_CIM_CONNECTION);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
private static void startService(Intent intent) {
|
||||
CIMPushService.getInstance().onStartCommand(intent);
|
||||
}
|
||||
|
||||
protected static void connect() {
|
||||
|
||||
boolean isManualStopped = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_MANUAL_STOP);
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
|
||||
if (isManualStopped || isManualDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
String host = CIMCacheManager.getInstance().getString(CIMCacheManager.KEY_CIM_SERVER_HOST);
|
||||
int port = CIMCacheManager.getInstance().getInt(CIMCacheManager.KEY_CIM_SERVER_PORT);
|
||||
|
||||
connect(host, port);
|
||||
|
||||
}
|
||||
|
||||
private static void sendBindRequest(String account) {
|
||||
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_MANUAL_STOP, false);
|
||||
SentBody sent = new SentBody();
|
||||
Properties sysPro = System.getProperties();
|
||||
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
|
||||
sent.put("account", account);
|
||||
sent.put("deviceId", getDeviceId());
|
||||
sent.put("channel", "java");
|
||||
sent.put("device", sysPro.getProperty("os.name"));
|
||||
sent.put("appVersion", getClientVersion());
|
||||
sent.put("osVersion", sysPro.getProperty("os.version"));
|
||||
sendRequest(sent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个账号登录到服务端
|
||||
*
|
||||
* @param account
|
||||
* 用户唯一ID
|
||||
*/
|
||||
public static void bindAccount(String account) {
|
||||
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
if (isManualDestroyed || account == null || account.trim().length() == 0) {
|
||||
return;
|
||||
}
|
||||
sendBindRequest(account);
|
||||
|
||||
}
|
||||
|
||||
protected static boolean autoBindDeviceId() {
|
||||
|
||||
String account = getAccount();
|
||||
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
boolean isManualStopped = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_MANUAL_STOP);
|
||||
if (isManualStopped || account == null || account.trim().length() == 0 || isManualDestroyed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sendBindRequest(account);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送一个CIM请求
|
||||
*
|
||||
* @body
|
||||
*/
|
||||
public static void sendRequest(SentBody body) {
|
||||
|
||||
boolean isManualStopped = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_MANUAL_STOP);
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
|
||||
if (isManualStopped || isManualDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra(SentBody.class.getName(), body);
|
||||
serviceIntent.setAction(ACTION_SEND_REQUEST_BODY);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止接受推送,将会退出当前账号登录,端口与服务端的连接
|
||||
*
|
||||
*/
|
||||
public static void stop() {
|
||||
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
if (isManualDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_MANUAL_STOP, true);
|
||||
|
||||
startService(new Intent(ACTION_CLOSE_CIM_CONNECTION));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 完全销毁CIM,一般用于完全退出程序,调用resume将不能恢复
|
||||
*/
|
||||
public static void destroy() {
|
||||
|
||||
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_CIM_DESTROYED, true);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.setAction(ACTION_DESTROY);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新恢复接收推送,重新连接服务端,并登录当前账号如果autoBind == true
|
||||
*/
|
||||
public static void resume() {
|
||||
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
if (isManualDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoBindDeviceId();
|
||||
}
|
||||
|
||||
public static boolean isConnected() {
|
||||
return CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_CONNECTION_STATE);
|
||||
}
|
||||
|
||||
public static int getState() {
|
||||
boolean isManualDestroyed = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_CIM_DESTROYED);
|
||||
if (isManualDestroyed) {
|
||||
return STATE_DESTROYED;
|
||||
}
|
||||
|
||||
boolean isManualStopped = CIMCacheManager.getInstance().getBoolean(CIMCacheManager.KEY_MANUAL_STOP);
|
||||
if (isManualStopped) {
|
||||
return STATE_STOPPED;
|
||||
}
|
||||
|
||||
return STATE_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
public static String getClientVersion() {
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_VERSION);
|
||||
}
|
||||
|
||||
public static String getAccount() {
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_ACCOUNT);
|
||||
}
|
||||
|
||||
public static void setAccount(String account) {
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_ACCOUNT, account);
|
||||
}
|
||||
|
||||
public static void setClientVersion(String version) {
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_VERSION, version);
|
||||
}
|
||||
|
||||
private static String getDeviceId() {
|
||||
|
||||
String currDeviceId = System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_DEVICE_ID);
|
||||
if(currDeviceId != null) {
|
||||
return currDeviceId;
|
||||
}
|
||||
String deviceId = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_DEVICE_ID, deviceId);
|
||||
return deviceId;
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* 与服务端连接服务
|
||||
*/
|
||||
public class CIMPushService {
|
||||
|
||||
private final CIMConnectorManager manager;
|
||||
|
||||
private static CIMPushService service;
|
||||
|
||||
public static CIMPushService getInstance() {
|
||||
if (service == null) {
|
||||
service = new CIMPushService();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
public CIMPushService() {
|
||||
manager = CIMConnectorManager.getManager();
|
||||
}
|
||||
|
||||
public void onStartCommand(Intent intent) {
|
||||
|
||||
String action = intent == null ? CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE : intent.getAction();
|
||||
|
||||
if (CIMPushManager.ACTION_CREATE_CIM_CONNECTION.equals(action)) {
|
||||
String host = CIMCacheManager.getInstance().getString(CIMCacheManager.KEY_CIM_SERVER_HOST);
|
||||
int port = CIMCacheManager.getInstance().getInt(CIMCacheManager.KEY_CIM_SERVER_PORT);
|
||||
manager.connect(host, port);
|
||||
}
|
||||
|
||||
if (CIMPushManager.ACTION_SEND_REQUEST_BODY.equals(action)) {
|
||||
manager.send((SentBody) intent.getExtra(SentBody.class.getName()));
|
||||
}
|
||||
|
||||
if (CIMPushManager.ACTION_CLOSE_CIM_CONNECTION.equals(action)) {
|
||||
manager.closeSession();
|
||||
}
|
||||
|
||||
if (CIMPushManager.ACTION_DESTROY.equals(action)) {
|
||||
manager.destroy();
|
||||
}
|
||||
|
||||
if (CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action) && !manager.isConnected()) {
|
||||
|
||||
String host = CIMCacheManager.getInstance().getString(CIMCacheManager.KEY_CIM_SERVER_HOST);
|
||||
int port = CIMCacheManager.getInstance().getInt(CIMCacheManager.KEY_CIM_SERVER_PORT);
|
||||
manager.connect(host, port);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.coder;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* 日志打印,添加session 的id和ip address
|
||||
*/
|
||||
public class CIMLogger {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CIMLogger.class);
|
||||
|
||||
public static CIMLogger getLogger() {
|
||||
return LoggerHolder.logger;
|
||||
}
|
||||
|
||||
private CIMLogger() {
|
||||
|
||||
}
|
||||
|
||||
private static class LoggerHolder{
|
||||
private static final CIMLogger logger = new CIMLogger();
|
||||
}
|
||||
|
||||
|
||||
public void messageReceived(SocketChannel session, Object message) {
|
||||
LOGGER.info(String.format("RECEIVED" + getSessionInfo(session) + "\n%s", message));
|
||||
}
|
||||
|
||||
public void messageSent(SocketChannel session, Object message) {
|
||||
LOGGER.info(String.format("SENT" + getSessionInfo(session) + "\n%s", message));
|
||||
}
|
||||
|
||||
public void sessionCreated( SocketChannel session) {
|
||||
LOGGER.info("OPENED" + getSessionInfo(session));
|
||||
}
|
||||
|
||||
public void sessionIdle( SocketChannel session) {
|
||||
LOGGER.debug("IDLE READ" + getSessionInfo(session));
|
||||
}
|
||||
|
||||
public void sessionClosed( SocketChannel session) {
|
||||
LOGGER.warn("CLOSED ID = " + session.hashCode());
|
||||
|
||||
}
|
||||
|
||||
public void connectFailure(long interval) {
|
||||
LOGGER.debug("CONNECT FAILURE TRY RECONNECT AFTER " + interval +"ms");
|
||||
}
|
||||
|
||||
public void startConnect(String host , int port) {
|
||||
LOGGER.info("START CONNECT REMOTE HOST:" + host + " PORT:" + port);
|
||||
}
|
||||
|
||||
public void connectState(boolean isConnected) {
|
||||
LOGGER.debug("CONNECTED:" + isConnected);
|
||||
}
|
||||
|
||||
public void connectState(boolean isConnected,boolean isManualStop,boolean isDestroyed) {
|
||||
LOGGER.debug("CONNECTED:" + isConnected + " STOPPED:"+isManualStop+ " DESTROYED:"+isDestroyed);
|
||||
}
|
||||
|
||||
private String getSessionInfo(SocketChannel session) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (session == null) {
|
||||
return "";
|
||||
}
|
||||
builder.append(" [");
|
||||
builder.append("id:").append(session.hashCode());
|
||||
|
||||
try {
|
||||
if (session.socket().getLocalAddress() != null) {
|
||||
builder.append(" L:").append(session.socket().getLocalAddress()+":"+session.socket().getLocalPort());
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (session.socket().getRemoteSocketAddress() != null) {
|
||||
builder.append(" R:").append(session.socket().getRemoteSocketAddress().toString());
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.coder;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.HeartbeatRequest;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.model.proto.MessageProto;
|
||||
import com.farsunset.cim.sdk.model.proto.ReplyBodyProto;
|
||||
|
||||
/**
|
||||
* 客户端消息解码
|
||||
*/
|
||||
public class ClientMessageDecoder {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param headerBuffer 读取到的消息头
|
||||
* @param socketChannel
|
||||
* @return
|
||||
*/
|
||||
|
||||
public Object doDecode(ByteBuffer headerBuffer , SocketChannel socketChannel) throws IOException {
|
||||
|
||||
headerBuffer.position(0);
|
||||
|
||||
byte type = headerBuffer.get();
|
||||
byte lv = headerBuffer.get();
|
||||
byte hv = headerBuffer.get();
|
||||
|
||||
headerBuffer.clear();
|
||||
|
||||
/*
|
||||
* 先通过消息头拿到消息的长度,然后进行定长读取
|
||||
* 解决消息的断包和粘包情况
|
||||
*/
|
||||
|
||||
int dataLength = getContentLength(lv, hv);
|
||||
|
||||
ByteBuffer bodyBuffer = ByteBuffer.allocate(dataLength);
|
||||
|
||||
/*
|
||||
* 如果读取的消息长度不够,则进行等待后续消息到来
|
||||
* 当读取的消息长度(bodyBuffer.position() == dataLength)时意味着一个完整的消息已经接收完成
|
||||
*/
|
||||
do {
|
||||
socketChannel.read(bodyBuffer);
|
||||
} while (bodyBuffer.position() != dataLength);
|
||||
|
||||
|
||||
/*
|
||||
消息读取完成后,通过type来解析成对应的消息体
|
||||
*/
|
||||
if (CIMConstant.ProtobufType.S_H_RQ == type) {
|
||||
return HeartbeatRequest.getInstance();
|
||||
}
|
||||
|
||||
if (CIMConstant.ProtobufType.REPLY_BODY == type) {
|
||||
ReplyBodyProto.Model bodyProto = ReplyBodyProto.Model.parseFrom(bodyBuffer.array());
|
||||
ReplyBody body = new ReplyBody();
|
||||
body.setKey(bodyProto.getKey());
|
||||
body.setTimestamp(bodyProto.getTimestamp());
|
||||
body.putAll(bodyProto.getDataMap());
|
||||
body.setCode(bodyProto.getCode());
|
||||
body.setMessage(bodyProto.getMessage());
|
||||
return body;
|
||||
}
|
||||
|
||||
MessageProto.Model bodyProto = MessageProto.Model.parseFrom(bodyBuffer.array());
|
||||
Message message = new Message();
|
||||
message.setId(bodyProto.getId());
|
||||
message.setAction(bodyProto.getAction());
|
||||
message.setContent(bodyProto.getContent());
|
||||
message.setSender(bodyProto.getSender());
|
||||
message.setReceiver(bodyProto.getReceiver());
|
||||
message.setTitle(bodyProto.getTitle());
|
||||
message.setExtra(bodyProto.getExtra());
|
||||
message.setTimestamp(bodyProto.getTimestamp());
|
||||
message.setFormat(bodyProto.getFormat());
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析消息体长度
|
||||
*/
|
||||
private int getContentLength(byte lv, byte hv) {
|
||||
int l = (lv & 0xff);
|
||||
int h = (hv & 0xff);
|
||||
return (l | h << 8);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.coder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Protobufable;
|
||||
|
||||
|
||||
/**
|
||||
* 客户端消息发送前进行编码
|
||||
*/
|
||||
public class ClientMessageEncoder {
|
||||
|
||||
public ByteBuffer encode(Protobufable body) {
|
||||
|
||||
byte[] data = body.getByteArray();
|
||||
|
||||
ByteBuffer ioBuffer = ByteBuffer.allocate(data.length + CIMConstant.DATA_HEADER_LENGTH);
|
||||
|
||||
ioBuffer.put(createHeader(body.getType(), data.length));
|
||||
ioBuffer.put(data);
|
||||
ioBuffer.flip();
|
||||
|
||||
return ioBuffer;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息体最大为65535
|
||||
*
|
||||
* @param type
|
||||
* @param length
|
||||
* @return
|
||||
*/
|
||||
private byte[] createHeader(byte type, int length) {
|
||||
byte[] header = new byte[CIMConstant.DATA_HEADER_LENGTH];
|
||||
header[0] = type;
|
||||
header[1] = (byte) (length & 0xff);
|
||||
header[2] = (byte) ((length >> 8) & 0xff);
|
||||
return header;
|
||||
}
|
||||
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.constant;
|
||||
|
||||
/**
|
||||
* 常量
|
||||
*/
|
||||
public interface CIMConstant {
|
||||
|
||||
long RECONNECT_INTERVAL_TIME = 30 * 1000;
|
||||
/*
|
||||
* 消息头长度为3个字节,第一个字节为消息类型,第二,第三字节 转换int后为消息长度
|
||||
*/
|
||||
int DATA_HEADER_LENGTH = 3;
|
||||
|
||||
|
||||
interface ConfigKey {
|
||||
|
||||
String DEVICE_MODEL = "client.model";
|
||||
String CLIENT_VERSION = "client.version";
|
||||
String CLIENT_ACCOUNT = "client.account";
|
||||
String CLIENT_DEVICE_ID = "client.deviceId";
|
||||
|
||||
}
|
||||
|
||||
interface ProtobufType {
|
||||
byte C_H_RS = 0;
|
||||
byte S_H_RQ = 1;
|
||||
byte MESSAGE = 2;
|
||||
byte SENT_BODY = 3;
|
||||
byte REPLY_BODY = 4;
|
||||
}
|
||||
|
||||
interface RequestKey {
|
||||
|
||||
String CLIENT_BIND = "client_bind";
|
||||
|
||||
}
|
||||
|
||||
interface MessageAction {
|
||||
/*
|
||||
被其他设备登录挤下线消息
|
||||
*/
|
||||
String ACTION_999 = "999";
|
||||
}
|
||||
|
||||
interface IntentAction {
|
||||
|
||||
/*
|
||||
消息广播action
|
||||
*/
|
||||
String ACTION_MESSAGE_RECEIVED = "com.farsunset.cim.ACTION_MESSAGE_RECEIVED";
|
||||
|
||||
/*
|
||||
发送sendBody成功广播
|
||||
*/
|
||||
String ACTION_SEND_FINISHED = "com.farsunset.cim.ACTION_SEND_FINISHED";
|
||||
|
||||
/*
|
||||
链接意外关闭广播
|
||||
*/
|
||||
String ACTION_CONNECTION_CLOSED = "com.farsunset.cim.ACTION_CONNECTION_CLOSED";
|
||||
|
||||
/*
|
||||
链接失败广播
|
||||
*/
|
||||
String ACTION_CONNECT_FAILED = "com.farsunset.cim.ACTION_CONNECT_FAILED";
|
||||
|
||||
/*
|
||||
链接成功广播
|
||||
*/
|
||||
String ACTION_CONNECT_FINISHED = "com.farsunset.cim.ACTION_CONNECT_FINISHED";
|
||||
|
||||
/*
|
||||
发送sendBody成功后获得replyBody回应广播
|
||||
*/
|
||||
String ACTION_REPLY_RECEIVED = "com.farsunset.cim.ACTION_REPLY_RECEIVED";
|
||||
|
||||
/*
|
||||
重试连接
|
||||
*/
|
||||
String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
|
||||
/**
|
||||
* 服务端心跳请求
|
||||
*
|
||||
*/
|
||||
public class HeartbeatRequest implements Serializable, Protobufable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = "SERVER_HEARTBEAT_REQUEST";
|
||||
private static final String CMD_HEARTBEAT_RESPONSE = "SR";
|
||||
|
||||
private static final HeartbeatRequest object = new HeartbeatRequest();
|
||||
|
||||
private HeartbeatRequest() {
|
||||
|
||||
}
|
||||
|
||||
public static HeartbeatRequest getInstance() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return CMD_HEARTBEAT_RESPONSE.getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getType() {
|
||||
return CIMConstant.ProtobufType.S_H_RQ;
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
|
||||
/**
|
||||
* 客户端心跳响应
|
||||
*/
|
||||
public class HeartbeatResponse implements Serializable, Protobufable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = "CLIENT_HEARTBEAT_RESPONSE";
|
||||
private static final String CMD_HEARTBEAT_RESPONSE = "CR";
|
||||
|
||||
private static final HeartbeatResponse object = new HeartbeatResponse();
|
||||
|
||||
private HeartbeatResponse() {
|
||||
|
||||
}
|
||||
|
||||
public static HeartbeatResponse getInstance() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
return CMD_HEARTBEAT_RESPONSE.getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getType() {
|
||||
return CIMConstant.ProtobufType.C_H_RS;
|
||||
}
|
||||
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 消息对象
|
||||
*/
|
||||
public class Message implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 消息类型,用户自定义消息类别
|
||||
*/
|
||||
private long id;
|
||||
|
||||
/**
|
||||
* 消息类型,用户自定义消息类别
|
||||
*/
|
||||
private String action;
|
||||
/**
|
||||
* 消息标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 消息类容,于action 组合为任何类型消息,content 根据 format 可表示为 text,json ,xml数据格式
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息发送者账号
|
||||
*/
|
||||
private String sender;
|
||||
/**
|
||||
* 消息发送者接收者
|
||||
*/
|
||||
private String receiver;
|
||||
|
||||
/**
|
||||
* content 内容格式
|
||||
*/
|
||||
private String format;
|
||||
|
||||
/**
|
||||
* 附加内容 内容
|
||||
*/
|
||||
private String extra;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public Message() {
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public String getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public void setReceiver(String receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("#Message#").append("\n");
|
||||
buffer.append("id:").append(id).append("\n");
|
||||
buffer.append("action:").append(action).append("\n");
|
||||
buffer.append("title:").append(title).append("\n");
|
||||
buffer.append("content:").append(content).append("\n");
|
||||
buffer.append("extra:").append(extra).append("\n");
|
||||
buffer.append("sender:").append(sender).append("\n");
|
||||
buffer.append("receiver:").append(receiver).append("\n");
|
||||
buffer.append("format:").append(format).append("\n");
|
||||
buffer.append("timestamp:").append(timestamp);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
public boolean isNotEmpty(String txt) {
|
||||
return txt != null && txt.trim().length() != 0;
|
||||
}
|
||||
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 请求应答对象
|
||||
*
|
||||
*/
|
||||
public class ReplyBody implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 请求key
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 返回码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 返回说明
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 返回数据集合
|
||||
*/
|
||||
private HashMap<String, String> data;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public ReplyBody() {
|
||||
data = new HashMap<>();
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
if (v != null && k != null) {
|
||||
data.put(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public void remove(String k) {
|
||||
data.remove(k);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void putAll(Map<String, String> map) {
|
||||
data.putAll(map);
|
||||
}
|
||||
|
||||
public Set<String> getKeySet() {
|
||||
return data.keySet();
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("#ReplyBody#").append("\n");
|
||||
buffer.append("key:").append(this.getKey()).append("\n");
|
||||
buffer.append("timestamp:").append(timestamp).append("\n");
|
||||
buffer.append("code:").append(code).append("\n");
|
||||
buffer.append("data{").append("\n");
|
||||
for (String key : getKeySet()) {
|
||||
buffer.append(key).append(":").append(this.get(key)).append("\n");
|
||||
}
|
||||
buffer.append("}");
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.model.proto.SentBodyProto;
|
||||
|
||||
/**
|
||||
* java |android 客户端请求结构
|
||||
*
|
||||
*/
|
||||
public class SentBody implements Serializable, Protobufable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String key;
|
||||
|
||||
private HashMap<String, String> data = new HashMap<>();;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public SentBody() {
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
if (v != null && k != null) {
|
||||
data.put(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
public void putAll(Map<String, String> map) {
|
||||
data.putAll(map);
|
||||
}
|
||||
|
||||
public Set<String> getKeySet() {
|
||||
return data.keySet();
|
||||
}
|
||||
|
||||
public void remove(String k) {
|
||||
data.remove(k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("#SentBody#").append("\n");
|
||||
buffer.append("key:").append(key).append("\n");
|
||||
buffer.append("timestamp:").append(timestamp).append("\n");
|
||||
buffer.append("data{").append("\n");
|
||||
for (String key : getKeySet()) {
|
||||
buffer.append(key).append(":").append(this.get(key)).append("\n");
|
||||
}
|
||||
buffer.append("}");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray() {
|
||||
SentBodyProto.Model.Builder builder = SentBodyProto.Model.newBuilder();
|
||||
builder.setKey(key);
|
||||
builder.setTimestamp(timestamp);
|
||||
if (!data.isEmpty()) {
|
||||
builder.putAllData(data);
|
||||
}
|
||||
return builder.build().toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getType() {
|
||||
return CIMConstant.ProtobufType.SENT_BODY;
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package com.farsunset.cim.sdk.model.proto;
|
||||
option java_outer_classname="MessageProto";
|
||||
message Model {
|
||||
int64 id = 1;
|
||||
string action = 2;
|
||||
string content = 3;
|
||||
string sender = 4;
|
||||
string receiver = 5;
|
||||
string extra = 6;
|
||||
string title = 7;
|
||||
string format = 8;
|
||||
int64 timestamp = 9;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package com.farsunset.cim.sdk.model.proto;
|
||||
option java_outer_classname="ReplyBodyProto";
|
||||
|
||||
message Model {
|
||||
string key = 1;
|
||||
string code = 2;
|
||||
string message = 3;
|
||||
int64 timestamp =4;
|
||||
map<string,string> data =5;
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package com.farsunset.cim.sdk.model.proto;
|
||||
option java_outer_classname="SentBodyProto";
|
||||
|
||||
message Model {
|
||||
string key = 1;
|
||||
int64 timestamp =2;
|
||||
map<string,string> data =3;
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
target/
|
||||
.idea/
|
@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4" />
|
@ -1,55 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.farsunset</groupId>
|
||||
<artifactId>cim-server-sdk-mina</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<protobuf.java.version>3.11.1</protobuf.java.version>
|
||||
<mina.version>2.1.3</mina.version>
|
||||
<slf4j.version>1.7.30</slf4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>${mina.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>${protobuf.java.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************************
|
||||
* *
|
||||
* Website : http://www.farsunset.com *
|
||||
* *
|
||||
***************************************************************************************
|
||||
*/
|
||||
package com.farsunset.cim.sdk.server.coder;
|
||||
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFactory;
|
||||
import org.apache.mina.filter.codec.ProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoder;
|
||||
|
||||
/**
|
||||
* 服务端消息 编码解码器
|
||||
*/
|
||||
public class AppMessageCodecFactory implements ProtocolCodecFactory {
|
||||
|
||||
private final AppMessageEncoder encoder;
|
||||
|
||||
private final AppMessageDecoder decoder;
|
||||
|
||||
public AppMessageCodecFactory() {
|
||||
encoder = new AppMessageEncoder();
|
||||
decoder = new AppMessageDecoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolEncoder getEncoder(IoSession session) {
|
||||
return encoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolDecoder getDecoder(IoSession session) {
|
||||
return decoder;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user