Compare commits

...

129 Commits

Author SHA1 Message Date
xia jun
e6d50f36cb android sdk 支持15 2025-06-09 12:26:19 +08:00
flash
3634392e7f android sdk适配android 15 2025-06-09 12:19:24 +08:00
xia jun
4a68b47fdb 1、服务端SDK支持IP黑名单拦截
2、优化代码注释和升级依赖组件版本
2025-03-29 13:19:39 +08:00
xia jun
965abd1467 1、服务端SDK支持IP黑名单拦截
2、优化代码注释和升级依赖组件版本
2025-03-29 13:14:55 +08:00
远方夕阳
e8c87358ac
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2025-02-09 08:32:24 +00:00
xia jun
fe788c50c0 修改SDK文档描述,删除无用的参数 2025-01-06 11:45:35 +08:00
xia jun
b02d43af32 修复uni微信小程序模式下,Uint8Array转换的问题
参见https://blog.csdn.net/cnzzs/article/details/143497925
2025-01-01 10:24:11 +08:00
xia jun
c4a90251db 提供微信小程序客户端代码示例 2024-11-25 17:11:04 +08:00
xia jun
0d6ff67f08 新增长连接 接收发送消息实现 2024-11-03 13:48:21 +08:00
xia jun
626ee06c21 服务端SDK可以设置自定义日志处理器,可自行过滤不需要打印的日志 2024-10-18 14:04:27 +08:00
xia jun
eed7ffb747 服务端SDK可以设置自定义日志处理器,可自行过滤不需要打印的日志 2024-10-18 14:03:37 +08:00
远方夕阳
bdd66ce133
update README.md.
修改README

Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-07-17 04:53:50 +00:00
xia jun
7175585d37 优化解码socket数据 2024-06-11 12:53:52 +08:00
xia jun
baa536f442 Server SDK 优化Websocket鉴权机制,在握手之前鉴权。 2024-06-05 14:13:56 +08:00
远方夕阳
62fc15b33b
!20 ws鉴权问题
Merge pull request !20 from changhao.ni/master
2024-06-05 04:25:06 +00:00
远方夕阳
53fd3aa005
update cim-use-examples/cim-client-android/app/src/main/AndroidManifest.xml.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-06-05 03:59:12 +00:00
changhao.ni
b126dfc198 webscoket 鉴权方式修改 2024-05-29 10:29:21 +08:00
远方夕阳
ec130c97b4 update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-05-29 10:19:34 +08:00
远方夕阳
a4b401e16b update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-05-29 10:19:34 +08:00
LAPTOP-8KGKDQIB\39794
5d22b80a37 no message 2024-03-22 18:33:28 +08:00
LAPTOP-8KGKDQIB\39794
7e7b4c03da 修改https://gitee.com/farsunset/cim/issues/I9ACDM
session表channel字段加长到16位
2024-03-22 18:33:04 +08:00
远方夕阳
4098e564f4
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-03-20 07:06:47 +00:00
远方夕阳
570b977910
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-03-20 07:06:13 +00:00
远方夕阳
66c4ed8398
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-03-18 13:13:18 +00:00
远方夕阳
e5ba2ca32e
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-03-18 13:12:35 +00:00
远方夕阳
36270254b0
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-03-15 01:02:28 +00:00
远方夕阳
789c89185a Merge branch 'master' of https://gitee.com/farsunset/cim 2024-01-26 16:34:28 +08:00
远方夕阳
d189d4cca4 更新android demo工程 2024-01-26 16:34:17 +08:00
远方夕阳
a572ccc9a3
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2024-01-26 08:31:47 +00:00
远方夕阳
c1df188360 修改redis消息队列配置问题 2024-01-03 18:12:06 +08:00
远方夕阳
e60f64ec55 修改Android sdk 替换protobuf-lite为protobuf-javalite 2023-12-04 19:02:08 +08:00
zhuhailiang
43308baa5f sdk接口更新 2023-11-01 10:51:12 +08:00
zhuhailiang
a9909a4039 sdk封装接口调整、接口文档调整 2023-11-01 10:23:40 +08:00
zhuhailiang
ce2377c72b README.md文档更新 2023-10-25 11:34:55 +08:00
zhuhailiang
c9177612ea README.md说明文档提交 2023-10-25 11:32:02 +08:00
zhuhailiang
5cdb08306f cim客户端uniapp-sdk更新 2023-10-24 15:36:02 +08:00
远方夕阳
cfac26b7ad android sdk 适配 android14 2023-10-05 16:40:35 +08:00
远方夕阳
6a02c58d4e Merge branch 'master' of https://gitee.com/farsunset/cim 2023-10-05 11:46:01 +08:00
远方夕阳
9856788ed1 android sdk 适配 android14 2023-10-05 11:45:51 +08:00
远方夕阳
1c9efbbaf0
!19 flutter sdk 长连接登录信息 改为缺省参数 可自行填写
Merge pull request !19 from 杨杰/master
2023-07-30 02:18:22 +00:00
yangjiejie12308
37bb7a06bc flutter sdk 长连接登录信息 改为缺省参数 可自行填写 2023-07-17 09:32:34 +08:00
远方夕阳
fdf435a873
!18 flutter sdk 新增全平台 websocket 连接通道 支持 web ios android windows mac linux
Merge pull request !18 from 杨杰/master
2023-07-14 03:30:23 +00:00
yangjiejie12308
df3385151a 新增 flutter_websocket_sdk 支持所有平台 2023-07-14 11:22:34 +08:00
yangjiejie12308
2a3d315d75 更新sdk websocket sdk 增加 2023-07-14 10:33:26 +08:00
远方夕阳
c8f45c9a97
!17 Flutter SDK 连接uid 改为字符串类型
Merge pull request !17 from 杨杰/master
2023-07-13 09:53:53 +00:00
yangjiejie12308
03a309d8ee fix 允许UID 为字符串 2023-07-13 17:25:37 +08:00
远方夕阳
5252c00a8f
!16 修复 重复收到消息的bug
Merge pull request !16 from 杨杰/master
2023-07-10 10:35:08 +00:00
yangjiejie12308
d7e8649c17 fix 重复收到消息的bug 2023-07-10 10:46:43 +08:00
远方夕阳
8a494b9c02
!15 修复 flutter sdk 中 osversion 过长的错误
Merge pull request !15 from 杨杰/master
2023-07-06 09:32:05 +00:00
yangjiejie12308
2a8ec5865e fix osversion is too long 2023-07-06 11:43:52 +08:00
远方夕阳
2ba80c85cf
!14 upload sdk to pub.dev
Merge pull request !14 from 杨杰/master
2023-07-06 02:59:05 +00:00
yangjiejie12308
457eb21769 删除自动生成的文件 2023-07-04 16:01:30 +08:00
yangjiejie12308
f3a7ab7cdf 合并 2023-07-04 15:59:33 +08:00
yangjiejie12308
c4b30acef3 flutter public to pub.dev 2023-07-04 15:58:32 +08:00
杨杰
c55c3d5012
update cim-client-sdk/cim-flutter-sdk/README.md.
Signed-off-by: 杨杰 <5301327+smebclub@user.noreply.gitee.com>
2023-07-04 06:25:46 +00:00
杨杰
721839d981
update cim-client-sdk/cim-flutter-sdk/README.md.
Signed-off-by: 杨杰 <5301327+smebclub@user.noreply.gitee.com>
2023-07-04 06:25:18 +00:00
杨杰
c5947f718f
update cim-client-sdk/cim-flutter-sdk/README.md.
Signed-off-by: 杨杰 <5301327+smebclub@user.noreply.gitee.com>
2023-07-04 06:15:21 +00:00
远方夕阳
f798e8a6fb
!13 update flutter sdk
Merge pull request !13 from 杨杰/master
2023-06-14 03:34:55 +00:00
yangjiejie12308
1d8bf474f9 update flutter sdk 2023-06-14 09:36:31 +08:00
远方夕阳
68b3ebd5c4 android sdk更新
适配targetSdkVersion 33
2023-02-15 12:18:41 +08:00
远方夕阳
046bfd8ade android sdk更新
适配targetSdkVersion 33
2023-02-15 11:15:43 +08:00
远方夕阳
97fe0a2721 服务端sdk升级
1、服务端新增 配置长连接心跳间隔和允许超时次数相关参数
2、com.farsunset.cim.acceptor.config.AppSocketConfig修改为com.farsunset.cim.acceptor.config.SocketConfig
2023-02-06 18:22:21 +08:00
远方夕阳
adf4f827e6 android sdk 监听器容器修改为CopyOnWriteArrayList 2022-11-04 16:21:26 +08:00
远方夕阳
11f40a0f51 android sdk 监听器容器修改为CopyOnWriteArrayList 2022-11-04 16:19:52 +08:00
远方夕阳
40a4353d21 修复android sdk 一处bug
频发切换wifi和移动网络,概率出现无法重连的问题
2022-09-29 18:40:27 +08:00
远方夕阳
e89a3918c5 修复android sdk 一处bug
频发切换wifi和移动网络,概率出现无法重连的问题
2022-09-29 18:23:12 +08:00
远方夕阳
35ab7cc72c 迁移基于oc的ios sdk 2022-09-17 15:25:39 +08:00
Chentao
2a2613b5cc [cim-ios-oc-sdk]增加重构代码 2022-09-16 13:35:24 +08:00
远方夕阳
560da9bebe 修改android版sdk Not allowed to delete channel with a foreground service 的问题 2022-09-07 17:10:50 +08:00
远方夕阳
538f80cee1 1、优化服务端session管理实现
2、android优化sdk通知管理
2022-09-04 22:47:38 +08:00
远方夕阳
ea9efc8594 新增服务端sdk功能接口,和代码注释 2022-09-01 13:51:38 +08:00
远方夕阳
c93ac73e80 服务端demo新增webrtc信令接口示例 2022-08-30 11:50:26 +08:00
远方夕阳
a0ddbe47c5 升级组件版本 2022-08-29 20:24:42 +08:00
远方夕阳
7a9a369960 修改android12中可能出现ForegroundServiceStartNotAllowedException的问题 2022-08-27 23:01:15 +08:00
远方夕阳
69cbb31d9e sdk切换为maven依赖 2022-08-27 17:35:05 +08:00
远方夕阳
c62d646cfc sdk切换为maven依赖 2022-08-27 17:34:32 +08:00
远方夕阳
bb7266e170
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2022-08-18 07:49:43 +00:00
远方夕阳
40a32b8887
update README.md.
Signed-off-by: 远方夕阳 <xj753277@126.com>
2022-08-18 07:49:11 +00:00
远方夕阳
d2e9727df7 添加构建maven配置 2022-08-18 15:40:17 +08:00
远方夕阳
822bc6f104
!12 修复iOS消息监听的BUG
Merge pull request !12 from ZBNever/master
2022-06-24 01:39:33 +00:00
周博
e54f90cb04 ios修复消息监听的BUG 2022-06-24 09:03:15 +08:00
远方夕阳
0d45aac81b
update README.md. 2022-05-17 07:25:30 +00:00
远方夕阳
994b78272d
update README.md. 2022-05-17 07:24:52 +00:00
远方夕阳
2996271f83
update README.md. 2022-05-17 07:24:34 +00:00
远方夕阳
c5bed5b689
update README.md. 2022-05-17 07:17:21 +00:00
远方夕阳
8cd43fdf9c 修改json序列化ReplyBody 丢失data字段的问题 2022-05-11 11:10:54 +08:00
远方夕阳
cba314151d 修改json序列化ReplyBody 丢失data字段的问题 2022-05-11 11:02:33 +08:00
远方夕阳
461be0fab1 1、websocket鉴权失败时响应ReplyBody,告知客户端鉴权失败 2022-05-10 17:07:39 +08:00
远方夕阳
7579845369 需改Sentbody.toString() 可能出现空指针的问题 2022-05-06 15:19:27 +08:00
远方夕阳
ec94bfcdf9
update README.md. 2022-04-27 07:49:56 +00:00
远方夕阳
b9afa1ca08
update README.md. 2022-04-27 07:45:41 +00:00
远方夕阳
585f3c4c80
update README.md. 2022-04-27 07:45:03 +00:00
远方夕阳
bffe162516
update README.md. 2022-04-27 07:44:09 +00:00
远方夕阳
a339e2640c
update README.md. 2022-04-23 05:18:03 +00:00
远方夕阳
c9552347a4
update README.md. 2022-04-23 05:17:40 +00:00
远方
ac32108750 优化服务端异常打印日志 2022-04-16 12:29:14 +08:00
远方
4051660957 服务端sdk 优化日志打印,线程名加入UID信息 2022-04-16 12:07:03 +08:00
远方夕阳
0e8a6aba18
update cim-boot-server/src/main/resources/application.properties. 2022-04-16 03:47:12 +00:00
远方夕阳
8f9d420ba2 服务端sdk日志优化 2022-04-14 17:13:45 +08:00
远方夕阳
16d5738451
update cim-server-sdk/src/main/java/com/farsunset/cim/acceptor/NioSocketAcceptor.java. 2022-04-07 09:21:11 +00:00
远方夕阳
42ba6e0cd4
update cim-server-sdk/src/main/java/com/farsunset/cim/acceptor/NioSocketAcceptor.java. 2022-04-07 09:20:34 +00:00
远方夕阳
62107d5b44
update README.md. 2022-04-07 03:43:57 +00:00
远方
be301d95c9 服务端sdk 优化日志打印,线程名加入UID信息 2022-04-04 14:01:10 +08:00
远方
6c61a09682 修改dome说明文件 2022-04-04 13:13:56 +08:00
远方
ad60928b54 修改Android sdk 网络断开 没有回调的问题 2022-03-28 21:26:57 +08:00
远方
2563c3fc12 1、调整Android sdk 连接超时为5秒(原10秒)
1、修复Android sdk 延时重连机制 时间不准确的问题
2022-03-27 21:46:44 +08:00
远方
bf7b6e79ae SentBody新增参数默认值 2022-03-20 14:25:08 +08:00
远方
eadac1b887 Android sdk 兼容targetSdkVersion 31 2022-03-20 14:14:51 +08:00
远方夕阳
4cc4d1d3b4
add cim-boot-server/init.sql. 2022-03-17 10:31:33 +00:00
远方夕阳
0263f804bb
update cim-boot-server/src/main/resources/application.properties. 2022-03-15 01:02:52 +00:00
远方夕阳
1cadbd167c 1.websocket新增支持json序列化方式,助力于小程序开发
2.服务端sdk优化包路径结构
3.修改部分问题
2022-03-14 18:57:29 +08:00
远方夕阳
91a890396d 兼容ws链接uri后面拼接参数 2022-02-16 14:31:08 +08:00
远方
fbe5e24e41 websocket支持握手时鉴权 2022-02-15 20:52:27 +08:00
远方夕阳
ec8b4a8392 websocket支持在握手时鉴权
文档地址:https://www.yuque.com/yuanfangxiyang/ma4ytb/vvy3iz#mmdUX
2022-02-15 19:52:32 +08:00
远方夕阳
9247b3daa5
update README.md. 2022-02-09 07:38:11 +00:00
远方夕阳
5ad68b833b
update README.md. 2022-01-17 13:10:24 +00:00
远方夕阳
8739fb87eb
update README.md. 2022-01-17 13:09:33 +00:00
远方夕阳
39a4ae2485
update README.md. 2022-01-17 13:08:52 +00:00
远方夕阳
4e98a6e571
update README.md. 2022-01-17 13:04:54 +00:00
远方夕阳
bf134137ee
update README.md. 2022-01-17 13:04:26 +00:00
远方夕阳
a505d3f06c !11 dotNet sdk 以及示例
Merge pull request !11 from 杨杰/dotnet
2021-12-27 10:09:21 +00:00
smeb_yangjie
e19c6424f2 dotnet_sdk说明 2021-12-24 19:40:51 +08:00
smeb_yangjie
a901e2b1f6 cim-dotnet-examples 2021-12-24 19:32:45 +08:00
35762f5ec9 fix 2021-12-24 18:12:37 +08:00
远方夕阳
7275b4b5ea !10 在flutter中测试通过的dart示例
Merge pull request !10 from 杨杰/cim-flutter-sdk
2021-12-24 03:24:52 +00:00
bf9b2860df cim for flutter sdk 2021-12-24 11:10:15 +08:00
远方夕阳
84786e6fdb update README.md. 2021-10-30 10:24:22 +00:00
远方夕阳
f6699c039e !8 弃用Cocoapods,支持SPM
Merge pull request !8 from 飞鱼log/master
2021-10-21 01:59:40 +00:00
飞鱼
4e0520b2b5 弃用Cocoapods, 支持SPM。SwiftUI Hello world! 2021-10-20 20:43:08 +08:00
610 changed files with 14185 additions and 38515 deletions

30
.gitignore vendored
View File

@ -1,2 +1,28 @@
target/
app/build/
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target/
/.idea/
.idea
*.class
*/local.properties

120
README.md
View File

@ -1,17 +1,28 @@
## 收费产品介绍
## 1、[在线文档](https://www.yuque.com/yuanfangxiyang/ma4ytb)
#### 布咕(https://farsunset.com/)
布咕是基于CIM组件开发的一整套完整的产品,面向所有人开放注册的试用场景。具有丰富的功能,音视频会议,聊天、群组、好友,组织架构、公众号、朋友圈等功能。不依赖任何第三方云服务,可以私有化部署。
## 2、[产品官网](http://farsunset.com)
---
<div align="center">
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/group_video_calling.jpg" width="24%" />
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/single_chatting_light.jpg" width="24%" />
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/single_chatting_dark.jpg" width="24%" />
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/moment_timeline_light.jpg" width="24%" />
</div>
## 项目介绍
[在线文档](https://www.yuque.com/yuanfangxiyang/ma4ytb)(https://www.yuque.com/yuanfangxiyang/ma4ytb)
CIM是一套完善的消息推送框架可应用于信令推送即时聊天移动设备指令推送等领域。开发者可沉浸于业务开发不用关心消息通道长连接、消息编解码协议等繁杂处理。
CIM采用业内主流开源技术构建易于扩展和使用并完美支持集群部署支持海量链接目前支持websocketandroidios桌面应用系统应用等多端接入持,可应用于移动应用物联网智能家居嵌入式开发桌面应用WEB应用即时消服务。
用时7年 基于CIM的项目已经运行在全国各个地方包括上市公司各地政务系统警务系统等服务于上百家客户希望CIM也能为您带来价值如果您也希望加入项目成为贡献者请联系我。如果觉得有用欢迎打赏。
历时10年基于CIM的项目已经运行在全国各个地方包括上市公司各地政务系统警务系统等服务于上百家客户希望CIM也能为您带来价值如果您也希望加入项目成为贡献者请联系我。如果觉得有用欢迎打赏。
如果对您有价值请送一个star和Fork喔~
<div align="center">
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/qcode/ali_pay.jpg" width="30%" />
@ -19,109 +30,40 @@ CIM采用业内主流开源技术构建易于扩展和使用并完美支
</div>
---
## [收费产品介绍](http://farsunset.com)
#### 和信
和信是基于CIM组件开发的一整套完整的产品,面向所有人开放注册的试用场景。具有丰富的功能,聊天、群组、好友列表、黑名单、公众号、朋友圈等功能。不依赖任何第三方服务,可以私有化部署。
#### 侣信
侣信是基于CIM组件开发的一整套完整的产品,面向中小企业和者各类团队组织内部交流使用工具。具有丰富的功能,聊天、群组、部门组织、公众号、内部朋友圈等功能。不依赖任何第三方服务,可以私有化部署。
<div align="center">
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/call_video_incoming.jpg" width="24%" />
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/single_chatting_light.jpg" width="24%" />
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/single_chatting_dark.jpg" width="24%" />
<img src="http://staticres.oss-cn-hangzhou.aliyuncs.com/hoxin/moment_timeline_light.jpg" width="24%" />
</div>
---
## 功能预览
1.控制台页面[http://127.0.0.1:8080](http://127.0.0.1:8080)
### 控制台页面[http://127.0.0.1:8080](http://127.0.0.1:8080)
![image](https://images.gitee.com/uploads/images/2019/0315/165050_9e269c1c_58912.png)
2.Android客户端
### Android客户端
![image](https://images.gitee.com/uploads/images/2019/0315/165050_6f20f69e_58912.png)
3.Web客户端
### Web客户端
![image](https://images.gitee.com/uploads/images/2019/0315/165050_dfc33c18_58912.png)
## 相关用户
-------------------------------------------------------------------------------------------
[JFlow](https://gitee.com/opencc/JFlow)
## 更新日志
-------------------------------------------------------------------------------------------
版本:3.5.0/时间:2018-08-22
1.服务端由原来的 spring+struts2修改为springboot工程
2.全面重写websocket的实现全面拥抱protobuf替换json序列化方式更加高效
-------------------------------------------------------------------------------------------
版本:3.6.0/时间:2019-04-17
1.服务端springboot升级2.1.4,protobuf升级3.7.0
2.android sdk升级适配android8.0+,修复一些之前的兼容性问题
3.消息的id字段名由mid修改为id类型由String修改为long;
-------------------------------------------------------------------------------------------
版本:3.7.0/时间:2019-05-13
1.服务端cim-boot-server修改为idea maven工程
2.android sdk优化升级去除mina或netty相关包的依赖
3.java sdk优化升级去除mina或netty相关包的依赖
4.新增web sdk可以由index.html快速启动demo
5.修正文档中一些疏漏
-------------------------------------------------------------------------------------------
版本:3.7.5/时间:2019-11-13
1.android sdk 优化使用protobuf-lite版本替代较为臃肿的protobut-java版本
-------------------------------------------------------------------------------------------
版本:3.8.0/时间:2020-01-17
## Maven Gradle
1.服务端sdk将websocket的服务端口和原生socket的端口分离可以禁用其中一个或者同时启
服务端sdk引用
2.web端的sdk简化流程不再需要心跳响应,修改了连接成功回调方法名称和创建连接方法名
```
3.andoid sdk修改几个广播action的名称以及回调方法名称详见cim-client-android工程
<dependency>
<groupId>com.farsunset</groupId>
<artifactId>cim-server-sdk-netty</artifactId>
<version>4.2.10</version>
</dependency>
4.所有sdk均使用maven构建idea工具开发发现多处代码单词拼写错误使用阿里语法检测组件优化了部分代码
```
5.同步修改了文档
android端sdk引用
-------------------------------------------------------------------------------------------
版本: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多处多处代码优化
```
implementation "com.farsunset:cim-android-sdk:4.2.15"
```

View File

@ -0,0 +1,2 @@
如果你不想搭建服务端也可以使用,公共的服务器做测试喔
具体信息参见https://www.yuque.com/yuanfangxiyang/ma4ytb/vvy3iz#yC5Vq

4
cim-boot-server/init.sql Normal file
View File

@ -0,0 +1,4 @@
create database cim;
#只需要创建库即可,服务器启动会自动创建表,基于application.properties中
#spring.jpa.hibernate.ddl-auto = update

View File

@ -6,21 +6,21 @@
<groupId>com.farsunset</groupId>
<artifactId>cim-boot-server</artifactId>
<version>1.0.0</version>
<version>4.2.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<version>2.5.14</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<netty.version>4.1.65.Final</netty.version>
<protobuf.version>3.17.0</protobuf.version>
<mysql.jdbc.version>8.0.22</mysql.jdbc.version>
<common.pool.version>2.8.0</common.pool.version>
<cim.server.sdk.version>4.2.10</cim.server.sdk.version>
<protobuf.version>3.25.0</protobuf.version>
<mysql.jdbc.version>9.2.0</mysql.jdbc.version>
<common.pool.version>2.12.1</common.pool.version>
<swagger.version>3.0.0</swagger.version>
</properties>
<dependencies>
@ -48,6 +48,11 @@
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
@ -61,12 +66,10 @@
</dependency>
<dependency>
<groupId>com.farsunset</groupId>
<artifactId>cim-server-sdk</artifactId>
<version>4.0.0</version>
<scope>system</scope>
<!-- mina 、netty版本 sdk任选其一 -->
<systemPath>${project.basedir}/libs/cim-server-sdk-netty-4.0.0.jar</systemPath>
<artifactId>cim-server-sdk-netty</artifactId>
<version>${cim.server.sdk.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
@ -74,52 +77,11 @@
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql.jdbc.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${netty.version}</version>
</dependency>
<!-- linux下有效. 其他linux平台自行修改对应的classifier -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<classifier>linux-x86_64</classifier>
<version>${netty.version}</version>
</dependency>
<!--- ##################使用netty本SDK时的配置 end ##################-->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
@ -135,7 +97,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
<version>2.11.0</version>
</dependency>
<dependency>

View File

@ -1 +1 @@
java -Dcom.sun.akuma.Daemon=daemonized -Dspring.profiles.active=pro -jar ./cim-boot-server-4.0.0.jar
java -Dcom.sun.akuma.Daemon=daemonized -Dspring.profiles.active=pro -jar ./cim-boot-server-4.2.0.jar

View File

@ -1,3 +1,3 @@
#! /bin/bash
java -Dcom.sun.akuma.Daemon=daemonized -Dspring.profiles.active=pro -jar ./cim-boot-server-4.0.0.jar &
java -Dcom.sun.akuma.Daemon=daemonized -Dspring.profiles.active=dev -Dserver.port=9090 -jar ./cim-boot-server-4.2.0.jar &

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -21,16 +21,10 @@
*/
package com.farsunset.cim;
import com.farsunset.cim.config.properties.APNsProperties;
import com.farsunset.cim.config.properties.CIMProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties({
APNsProperties.class,
CIMProperties.class})
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);

View File

@ -0,0 +1,35 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用户标注通过 token查到的用户账号注入到Controller参数里面
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessToken {
}

View File

@ -0,0 +1,4 @@
package com.farsunset.cim.annotation;
public @interface CreateAction {
}

View File

@ -0,0 +1,35 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用户标注通过 token查到的用户账号注入到Controller参数里面
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UID {
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2013-2022 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.event;
import com.farsunset.cim.model.Message;
import org.springframework.context.ApplicationEvent;
public class MessageEvent extends ApplicationEvent {
public MessageEvent(Message message) {
super(message);
}
@Override
public Message getSource() {
return (Message) source;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2013-2022 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.event;
import com.farsunset.cim.entity.Session;
import org.springframework.context.ApplicationEvent;
public class SessionEvent extends ApplicationEvent {
public SessionEvent(Session session) {
super(session);
}
@Override
public Session getSource() {
return (Session) source;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -23,12 +23,13 @@ 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.constant.ChannelAttr;
import com.farsunset.cim.constants.Constants;
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.group.SessionGroup;
import com.farsunset.cim.handler.CIMRequestHandler;
import com.farsunset.cim.model.ReplyBody;
import com.farsunset.cim.model.SentBody;
import com.farsunset.cim.service.SessionService;
import io.netty.channel.Channel;
import org.springframework.http.HttpStatus;
@ -53,6 +54,10 @@ public class BindHandler implements CIMRequestHandler {
@Override
public void process(Channel channel, SentBody body) {
if (sessionGroup.isManaged(channel)){
return;
}
ReplyBody reply = new ReplyBody();
reply.setKey(body.getKey());
reply.setCode(HttpStatus.OK.value());
@ -79,6 +84,8 @@ public class BindHandler implements CIMRequestHandler {
*/
sessionService.add(session);
channel.attr(Constants.SESSION_ID).set(session.getId());
/*
* 添加到内存管理
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -22,11 +22,12 @@
package com.farsunset.cim.component.handler;
import com.farsunset.cim.component.handler.annotation.CIMHandler;
import com.farsunset.cim.constant.ChannelAttr;
import com.farsunset.cim.constants.Constants;
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.SentBody;
import com.farsunset.cim.group.SessionGroup;
import com.farsunset.cim.handler.CIMRequestHandler;
import com.farsunset.cim.model.SentBody;
import com.farsunset.cim.service.SessionService;
import io.netty.channel.Channel;
@ -42,31 +43,25 @@ public class ClosedHandler implements CIMRequestHandler {
@Resource
private SessionService sessionService;
@Resource
private SessionGroup sessionGroup;
@Override
public void process(Channel channel, SentBody message) {
String uid = channel.attr(ChannelAttr.UID).get();
Long sessionId = channel.attr(Constants.SESSION_ID).get();
if (uid == null){
if (sessionId == null){
return;
}
String nid = channel.attr(ChannelAttr.ID).get();
sessionGroup.remove(channel);
/*
* ios开启了apns也需要显示在线因此不删记录
*/
if (!Objects.equals(channel.attr(ChannelAttr.CHANNEL).get(), Session.CHANNEL_IOS)){
sessionService.delete(uid,nid);
if (Objects.equals(channel.attr(ChannelAttr.CHANNEL).get(), Session.CHANNEL_IOS)){
sessionService.updateState(sessionId, Session.STATE_INACTIVE);
return;
}
sessionService.updateState(uid,nid, Session.STATE_INACTIVE);
sessionService.delete(sessionId);
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2013-2022 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.push.DefaultMessagePusher;
import com.farsunset.cim.component.redis.SignalRedisTemplate;
import com.farsunset.cim.constant.ChannelAttr;
import com.farsunset.cim.constants.Constants;
import com.farsunset.cim.entity.Session;
import com.farsunset.cim.group.SessionGroup;
import com.farsunset.cim.handler.CIMRequestHandler;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.model.ReplyBody;
import com.farsunset.cim.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_message")
public class MessageHandler implements CIMRequestHandler {
@Resource
private DefaultMessagePusher defaultMessagePusher;
@Override
public void process(Channel channel, SentBody body) {
Message message = new Message();
/*
获取到当前链接的UID
*/
message.setSender(channel.attr(ChannelAttr.UID).get());
message.setReceiver(body.get("receiver"));
message.setAction(body.get("action"));
message.setContent(body.get("content"));
message.setFormat(body.get("format"));
message.setTitle(body.get("title"));
message.setExtra(body.get("extra"));
message.setId(System.currentTimeMillis());
defaultMessagePusher.push(message);
/*
* 将发送的消息ID 通过Replay异步发送给客户端
* 可通过reqId来对应上多个消息的各自ID
*/
ReplyBody reply = new ReplyBody();
reply.setKey(body.getKey());
reply.setCode(HttpStatus.OK.value());
reply.put("messageId",String.valueOf(message.getId()));
reply.put("requestId",body.get("requestId"));
reply.setTimestamp(System.currentTimeMillis());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.

View File

@ -0,0 +1,65 @@
package com.farsunset.cim.component.logger;
import com.farsunset.cim.handler.LoggingHandler;
import com.farsunset.cim.model.Ping;
import com.farsunset.cim.model.Pong;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import org.springframework.stereotype.Component;
/**
* 自定义 CIM事件日志打印重写方法时注意需要有以下2种之一
* 1调用对应的ctx.fireXX(msg)方法;
* 2调用supper
*/
@ChannelHandler.Sharable
@Component
public class CIMEventLogger extends LoggingHandler {
/**
* 不打印客户端发送的Pong日志
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Pong){
ctx.fireChannelRead(msg);
return;
}
super.channelRead(ctx,msg);
}
/**
* 不打印服务端发送的Ping日志
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof Ping){
ctx.write(msg, promise);
return;
}
super.write(ctx,msg,promise);
}
/**
* 不打长连接空闲事件日志
* @param ctx
* @param evt
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
ctx.fireUserEventTriggered(evt);
}
}

View File

@ -1,19 +1,44 @@
/*
* Copyright 2013-2022 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.message;
import com.farsunset.cim.component.event.SessionEvent;
import com.farsunset.cim.constant.ChannelAttr;
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.group.SessionGroup;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.util.JSONUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOutboundInvoker;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.context.event.EventListener;
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;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* 集群环境下监控多设备登录情况控制是否其余终端下线的逻辑
@ -32,6 +57,11 @@ public class BindMessageListener implements MessageListener {
*/
private final Map<String,String[]> conflictMap = new HashMap<>();
/*
* web可能同一个终端 打开多 tab页面可以同时保持连接
*/
private final Set<String> keepLiveChannels = new HashSet<>();
@Resource
private SessionGroup sessionGroup;
@ -41,38 +71,115 @@ public class BindMessageListener implements MessageListener {
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});
keepLiveChannels.add(Session.CHANNEL_WEB);
}
@EventListener
public void onMessage(SessionEvent event) {
this.handle(event.getSource());
}
@Override
public void onMessage(org.springframework.data.redis.connection.Message redisMessage, byte[] bytes) {
Session session = JSONUtils.fromJson(redisMessage.getBody(), Session.class);
this.handle(session);
}
private void handle(Session session){
String uid = session.getUid();
String[] conflictChannels = conflictMap.get(session.getChannel());
if (ArrayUtils.isEmpty(conflictChannels)){
return;
}
Collection<Channel> channelList = sessionGroup.find(uid,conflictChannels);
channelList.removeIf(channel -> session.getNid().equals(channel.attr(ChannelAttr.ID).get()));
channelList.removeIf(new KeepLivePredicate(session));
/*
* 获取到其他在线的终端连接提示账号再其他终端登录
* 同设备仅关闭连接无需通知客户端
*/
channelList.forEach(channel -> {
channelList.stream().filter(new SameDevicePredicate(session)).forEach(ChannelOutboundInvoker::close);
if (Objects.equals(session.getDeviceId(),channel.attr(ChannelAttr.DEVICE_ID).get())){
channel.close();
return;
}
/*
* 不同设备关闭连接 通知客户端账号在其他设备登录
*/
channelList.stream().filter(new DifferentDevicePredicate(session)).forEach(new BreakOffMessageConsumer(uid,session.getDeviceName()));
Message message = new Message();
}
private static class BreakOffMessageConsumer implements Consumer<Channel> {
private final Message message;
private BreakOffMessageConsumer(String uid,String deviceName) {
message = new Message();
message.setAction(FORCE_OFFLINE_ACTION);
message.setReceiver(uid);
message.setSender(SYSTEM_ID);
message.setContent(session.getDeviceName());
channel.writeAndFlush(message);
channel.close();
});
message.setContent(deviceName);
}
@Override
public void accept(Channel channel) {
channel.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE);
}
}
private static class SameDevicePredicate implements Predicate<Channel> {
private final String deviceId;
private SameDevicePredicate(Session session) {
this.deviceId = session.getDeviceId();
}
@Override
public boolean test(Channel channel) {
return Objects.equals(this.deviceId,channel.attr(ChannelAttr.DEVICE_ID).get());
}
}
private static class DifferentDevicePredicate implements Predicate<Channel>{
private final SameDevicePredicate predicate;
private DifferentDevicePredicate(Session session) {
this.predicate = new SameDevicePredicate(session);
}
@Override
public boolean test(Channel channel) {
return !predicate.test(channel);
}
}
private class KeepLivePredicate implements Predicate<Channel>{
private final Session session;
private KeepLivePredicate(Session session) {
this.session = session;
}
@Override
public boolean test(Channel ioChannel) {
if (Objects.equals(session.getNid(),ioChannel.attr(ChannelAttr.ID).get())){
return true;
}
String deviceId = ioChannel.attr(ChannelAttr.DEVICE_ID).toString();
String channel = ioChannel.attr(ChannelAttr.CHANNEL).toString();
return keepLiveChannels.contains(channel) && Objects.equals(session.getDeviceId(),deviceId);
}
}
}

View File

@ -1,8 +1,31 @@
/*
* Copyright 2013-2022 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.message;
import com.farsunset.cim.sdk.server.group.SessionGroup;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.component.event.MessageEvent;
import com.farsunset.cim.group.SessionGroup;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.util.JSONUtils;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
@ -24,9 +47,23 @@ public class PushMessageListener implements MessageListener {
Message message = JSONUtils.fromJson(redisMessage.getBody(), Message.class);
String uid = message.getReceiver();
sessionGroup.write(uid,message);
this.onMessage(message);
}
@EventListener
public void onMessage(MessageEvent event) {
this.onMessage(event.getSource());
}
public void onMessage(Message message) {
String uid = message.getReceiver();
if (uid == null){
return;
}
sessionGroup.write(uid,message);
}
}

View File

@ -0,0 +1,28 @@
package com.farsunset.cim.component.predicate;
import com.farsunset.cim.auth.AuthPredicateInfo;
import org.springframework.stereotype.Component;
import java.util.function.Predicate;
/**
* WS 鉴权验证
*/
@Component
public class AuthPredicate implements Predicate<AuthPredicateInfo> {
@Override
public boolean test(AuthPredicateInfo auth) {
/*
可通过header或者uri传递参数
String token = auth.getHeader("token");
String token = auth.getParameter("token");
User user = doAuth(token);
auth.getCtx().attr(AttributeKey.valueOf("user_id")).set(user.getId());
*/
return true;
}
}

View File

@ -0,0 +1,25 @@
package com.farsunset.cim.component.predicate;
import org.springframework.stereotype.Component;
import java.util.function.Predicate;
@Component
public class BlacklistPredicate implements Predicate<String> {
/**
* IP黑名单拦截处理
* @param remoteAddress IP地址
* @return true:不拦截 false:拦截
*/
@Override
public boolean test(String remoteAddress) {
/*
* 自行根据IP判断是否需要拦截
*/
return true;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -21,7 +21,8 @@
*/
package com.farsunset.cim.component.push;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.model.Message;
/*
* 消息发送实接口

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -23,7 +23,7 @@ package com.farsunset.cim.component.push;
import com.farsunset.cim.component.redis.KeyValueRedisTemplate;
import com.farsunset.cim.component.redis.SignalRedisTemplate;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.service.APNsService;
import org.springframework.stereotype.Component;
@ -65,7 +65,7 @@ public class DefaultMessagePusher implements CIMMessagePusher {
/*
* 通过发送redis广播到集群中的每台实例获得当前UID绑定了连接并推送
* @see com.farsunset.hoxin.component.message.PushMessageListener
* @see com.farsunset.cim.component.message.PushMessageListener
*/
signalRedisTemplate.push(message);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -21,17 +21,31 @@
*/
package com.farsunset.cim.component.redis;
import com.farsunset.cim.component.event.MessageEvent;
import com.farsunset.cim.component.event.SessionEvent;
import com.farsunset.cim.constants.Constants;
import com.farsunset.cim.entity.Session;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.util.JSONUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Objects;
@Component
public class SignalRedisTemplate extends StringRedisTemplate {
@Value("${spring.profiles.active}")
private String env;
@Resource
private ApplicationContext applicationContext;
public SignalRedisTemplate(LettuceConnectionFactory connectionFactory) {
super(connectionFactory);
connectionFactory.setValidateConnection(true);
@ -42,6 +56,10 @@ public class SignalRedisTemplate extends StringRedisTemplate {
* @param message
*/
public void push(Message message) {
if (isDev()){
applicationContext.publishEvent(new MessageEvent(message));
return;
}
super.convertAndSend(Constants.PUSH_MESSAGE_INNER_QUEUE, JSONUtils.toJSONString(message));
}
@ -50,6 +68,19 @@ public class SignalRedisTemplate extends StringRedisTemplate {
* @param session
*/
public void bind(Session session) {
if (isDev()){
applicationContext.publishEvent(new SessionEvent(session));
return;
}
super.convertAndSend(Constants.BIND_MESSAGE_INNER_QUEUE, JSONUtils.toJSONString(session));
}
/**
* 本地调试环境下不走redis避免lettuce 经常command timeout
* @return
*/
private boolean isDev(){
return Objects.equals(env,"dev");
}
}

View File

@ -19,56 +19,42 @@
* *
***************************************************************************************
*/
package com.farsunset.cim.config.properties;
package com.farsunset.cim.component.redis;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class TokenRedisTemplate extends StringRedisTemplate {
private static final String TOKEN_CACHE_PREFIX = "TOKEN_%s";
@ConfigurationProperties(prefix = "cim")
public class CIMProperties {
public TokenRedisTemplate(RedisConnectionFactory connectionFactory) {
super(connectionFactory);
}
private final App app = new App();
public void save(String token, String uid) {
private final Websocket websocket = new Websocket();
String key = String.format(TOKEN_CACHE_PREFIX,token);
public App getApp() {
return app;
}
super.boundValueOps(key).set(uid);
}
public Websocket getWebsocket() {
return websocket;
}
public String get(String token) {
public static class App {
String key = String.format(TOKEN_CACHE_PREFIX,token);
private Integer port;
return super.boundValueOps(key).get();
public void setPort(Integer port) {
this.port = port;
}
}
public Integer getPort() {
return port;
}
}
public void remove(String token) {
public static class Websocket {
private Integer port;
String key = String.format(TOKEN_CACHE_PREFIX,token);
public Integer getPort() {
return port;
}
super.delete(key);
}
public void setPort(Integer port) {
this.port = port;
}
}
public Integer getAppPort() {
return app.port;
}
public Integer getWebsocketPort() {
return websocket.port;
}
}

View File

@ -1,16 +1,46 @@
/*
* Copyright 2013-2022 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.acceptor.AppSocketAcceptor;
import com.farsunset.cim.acceptor.WebsocketAcceptor;
import com.farsunset.cim.acceptor.config.SocketConfig;
import com.farsunset.cim.acceptor.config.WebsocketConfig;
import com.farsunset.cim.component.handler.annotation.CIMHandler;
import com.farsunset.cim.config.properties.CIMProperties;
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.SentBody;
import com.farsunset.cim.component.logger.CIMEventLogger;
import com.farsunset.cim.component.predicate.AuthPredicate;
import com.farsunset.cim.component.predicate.BlacklistPredicate;
import com.farsunset.cim.config.properties.APNsProperties;
import com.farsunset.cim.config.properties.CIMAppSocketProperties;
import com.farsunset.cim.config.properties.CIMWebsocketProperties;
import com.farsunset.cim.group.SessionGroup;
import com.farsunset.cim.group.TagSessionGroup;
import com.farsunset.cim.handler.CIMRequestHandler;
import com.farsunset.cim.model.SentBody;
import com.farsunset.cim.service.SessionService;
import io.netty.channel.Channel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
@ -20,6 +50,10 @@ import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@EnableConfigurationProperties({
APNsProperties.class,
CIMWebsocketProperties.class,
CIMAppSocketProperties.class})
@Configuration
public class CIMConfig implements CIMRequestHandler, ApplicationListener<ApplicationStartedEvent> {
@ -42,15 +76,41 @@ public class CIMConfig implements CIMRequestHandler, ApplicationListener<Applica
}
@Bean(destroyMethod = "destroy")
public CIMNioSocketAcceptor getNioSocketAcceptor(CIMProperties properties) {
@Bean(destroyMethod = "destroy",initMethod = "bind")
@ConditionalOnProperty(name = {"cim.websocket.enable"},matchIfMissing = true)
public WebsocketAcceptor websocketAcceptor(CIMWebsocketProperties properties, AuthPredicate authPredicate, BlacklistPredicate blacklistPredicate, CIMEventLogger cimEventLogger) {
WebsocketConfig config = new WebsocketConfig();
config.setBlacklistPredicate(blacklistPredicate);
config.setAuthPredicate(authPredicate);
config.setPath(properties.getPath());
config.setPort(properties.getPort());
config.setProtocol(properties.getProtocol());
config.setOuterRequestHandler(this);
config.setEnable(properties.isEnable());
return new CIMNioSocketAcceptor.Builder()
.setAppPort(properties.getAppPort())
.setWebsocketPort(properties.getWebsocketPort())
.setOuterRequestHandler(this)
.build();
config.setWriteIdle(properties.getWriteIdle());
config.setReadIdle(properties.getReadIdle());
config.setMaxPongTimeout(properties.getMaxPongTimeout());
config.setLoggingHandler(cimEventLogger);
return new WebsocketAcceptor(config);
}
@Bean(destroyMethod = "destroy",initMethod = "bind")
@ConditionalOnProperty(name = {"cim.app.enable"},matchIfMissing = true)
public AppSocketAcceptor appSocketAcceptor(CIMAppSocketProperties properties,BlacklistPredicate blacklistPredicate, CIMEventLogger cimEventLogger) {
SocketConfig config = new SocketConfig();
config.setPort(properties.getPort());
config.setOuterRequestHandler(this);
config.setEnable(properties.isEnable());
config.setWriteIdle(properties.getWriteIdle());
config.setReadIdle(properties.getReadIdle());
config.setMaxPongTimeout(properties.getMaxPongTimeout());
config.setLoggingHandler(cimEventLogger);
config.setBlacklistPredicate(blacklistPredicate);
return new AppSocketAcceptor(config);
}
@Override
@ -82,9 +142,6 @@ public class CIMConfig implements CIMRequestHandler, ApplicationListener<Applica
}
}
applicationContext.getBean(CIMNioSocketAcceptor.class).bind();
sessionService.deleteLocalhost();
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.mvc.resolver.TokenArgumentResolver;
import com.farsunset.cim.mvc.resolver.UidArgumentResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.util.List;
@Configuration
public class MvcConfig implements WebMvcConfigurer{
@Resource
private HandlerInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/webrtc/**");
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new UidArgumentResolver());
argumentResolvers.add(new TokenArgumentResolver());
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOriginPattern("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
configuration.setAllowCredentials(true);
source.registerCorsConfiguration("/**", configuration);
return new CorsFilter(source);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -24,6 +24,7 @@ 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.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
@ -38,7 +39,7 @@ import java.util.Objects;
@Configuration
@AutoConfigureBefore(RedisAutoConfiguration.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
@Autowired

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -26,31 +26,69 @@ 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.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
@EnableOpenApi
@Configuration
public class SwaggerConfig {
@Bean
public Docket userApiDocket(ApiInfo apiInfo) {
public Docket messageApiDocket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo)
.groupName("APP接口")
.apiInfo(new ApiInfoBuilder()
.title("CIM Push Service APIs.")
.description("消息发送相关接口")
.version("3.0")
.build())
.groupName("1、消息相关接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.farsunset.cim.mvc.controller.api"))
.build();
.apis(RequestHandlerSelectors.basePackage("com.farsunset.cim.mvc.controller.message"))
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
@Bean
public ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("CIM Push Service APIs.")
.description("CIM客户端接口文档")
.version("2.0")
.build();
public Docket webrtcApiDocket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(new ApiInfoBuilder()
.title("CIM Push Service APIs.")
.description("可用于webrtc通话信令接口")
.version("3.0")
.build())
.groupName("2、Webrtc相关接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.farsunset.cim.mvc.controller.webrtc"))
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> schemeList = new ArrayList<>();
schemeList.add(new ApiKey("access-token", "access-token", "header"));
return schemeList;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContextList = new ArrayList<>();
List<SecurityReference> securityReferenceList = new ArrayList<>();
securityReferenceList.add(new SecurityReference("access-token", new AuthorizationScope[]{new AuthorizationScope("global", "accessAnything")}));
securityContextList.add(SecurityContext
.builder()
.securityReferences(securityReferenceList)
.operationSelector(operationContext -> true)
.build()
);
return securityContextList;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.

View File

@ -0,0 +1,104 @@
/*
* Copyright 2013-2022 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.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.time.Duration;
@ConfigurationProperties(prefix = "cim.app")
public class CIMAppSocketProperties {
private boolean enable;
private Integer port;
/**
长链接写空闲时间触发时间(s)
心跳发送定时每当x秒无数据下发写入触发 服务端-->客户端 心跳事件
*/
private Duration writeIdle = Duration.ofSeconds(45);
/**
长链接读空闲时间触发时间(s)
心跳响应定时每当readIdle - writeIdle秒无数据接收触发心跳超时计数
*/
private Duration readIdle = Duration.ofSeconds(60);
/**
长链接最大允许心跳响应超时次数
达到该次数则 服务端断开链接
*/
private int maxPongTimeout = 1;
public void setPort(Integer port) {
this.port = port;
}
public Integer getPort() {
return port;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public Duration getWriteIdle() {
return writeIdle;
}
public void setWriteIdle(Duration writeIdle) {
if (writeIdle == null || writeIdle.getSeconds() <= 0){
return;
}
this.writeIdle = writeIdle;
}
public Duration getReadIdle() {
return readIdle;
}
public void setReadIdle(Duration readIdle) {
if (readIdle == null || readIdle.getSeconds() <= 0){
return;
}
this.readIdle = readIdle;
}
public int getMaxPongTimeout() {
return maxPongTimeout;
}
public void setMaxPongTimeout(int maxPongTimeout) {
if (maxPongTimeout <= 0){
return;
}
this.maxPongTimeout = maxPongTimeout;
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright 2013-2022 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.properties;
import com.farsunset.cim.constant.WebsocketProtocol;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.time.Duration;
@ConfigurationProperties(prefix = "cim.websocket")
public class CIMWebsocketProperties {
private boolean enable;
private Integer port;
private String path;
private WebsocketProtocol protocol;
/**
长链接写空闲时间触发时间(s)
心跳发送定时每当x秒无数据下发写入触发 服务端-->客户端 心跳事件
*/
private Duration writeIdle = Duration.ofSeconds(45);
/**
长链接读空闲时间触发时间(s)
心跳响应定时每当readIdle - writeIdle秒无数据接收触发心跳超时计数
*/
private Duration readIdle = Duration.ofSeconds(60);
/**
长链接最大允许心跳响应超时次数
达到该次数则 服务端断开链接
*/
private int maxPongTimeout = 1;
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public WebsocketProtocol getProtocol() {
return protocol;
}
public void setProtocol(WebsocketProtocol protocol) {
this.protocol = protocol;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public Duration getWriteIdle() {
return writeIdle;
}
public void setWriteIdle(Duration writeIdle) {
if (writeIdle == null || writeIdle.getSeconds() <= 0){
return;
}
this.writeIdle = writeIdle;
}
public Duration getReadIdle() {
return readIdle;
}
public void setReadIdle(Duration readIdle) {
if (readIdle == null || readIdle.getSeconds() <= 0){
return;
}
this.readIdle = readIdle;
}
public int getMaxPongTimeout() {
return maxPongTimeout;
}
public void setMaxPongTimeout(int maxPongTimeout) {
if (maxPongTimeout <= 0){
return;
}
this.maxPongTimeout = maxPongTimeout;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -21,13 +21,16 @@
*/
package com.farsunset.cim.constants;
import io.netty.util.AttributeKey;
public interface Constants {
String PUSH_MESSAGE_INNER_QUEUE = "signal/channel/PUSH_MESSAGE_INNER_QUEUE";
String BIND_MESSAGE_INNER_QUEUE = "signal/channel/BIND_MESSAGE_INNER_QUEUE";
String PING_MESSAGE_INNER_QUEUE = "signal/channel/PING_MESSAGE_INNER_QUEUE";
String APNS_DEVICE_TOKEN = "APNS_OPEN_%s";
AttributeKey<Long> SESSION_ID = AttributeKey.valueOf("session_id");
}

View File

@ -0,0 +1,76 @@
/*
* 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.constants;
public interface MessageAction {
/*
* 系统定制消息---语音通话请求
*/
String ACTION_900 = "900";
/*
* 系统定制消息---视频通话请求
*/
String ACTION_901 = "901";
/*
* 系统定制消息---通话接受
*/
String ACTION_902 = "902";
/*
* 系统定制消息---通话拒绝
*/
String ACTION_903 = "903";
/*
* 系统定制消息---对方正忙
*/
String ACTION_904 = "904";
/*
* 系统定制消息---对方挂断
*/
String ACTION_905 = "905";
/*
* 系统定制消息---取消呼叫
*/
String ACTION_906 = "906";
/*
* 系统定制消息---同步ICE SPD
*/
String ACTION_907 = "907";
/*
* 系统定制消息---同步Offer
*/
String ACTION_908 = "908";
/*
* 系统定制消息---同步Answer
*/
String ACTION_909 = "909";
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -23,22 +23,20 @@ package com.farsunset.cim.entity;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "t_hoxin_session")
public class Session implements Serializable {
@Table(name = "t_cim_session")
public class Session{
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 int STATE_ACTIVE = 0;
public static final int STATE_APNS = 1;
public static final 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";
public static final String CHANNEL_IOS = "ios";
public static final String CHANNEL_ANDROID = "android";
public static final String CHANNEL_WINDOWS = "windows";
public static final String CHANNEL_MAC = "mac";
public static final String CHANNEL_WEB = "web";
/**
* 数据库主键ID
@ -82,7 +80,7 @@ public class Session implements Serializable {
/**
* 终端设备类型
*/
@Column(name = "channel",length = 10,nullable = false)
@Column(name = "channel",length = 16,nullable = false)
private String channel;
/**
@ -109,24 +107,6 @@ public class Session implements Serializable {
@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;
/**
* 状态
*/
@ -212,30 +192,6 @@ public class Session implements Serializable {
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 String getLanguage() {
return language;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -21,13 +21,13 @@
*/
package com.farsunset.cim.mvc.controller.admin;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@Api(produces = "application/json", tags = "页面导航",hidden = true)
public class NavigationController {
@GetMapping(value = "/")

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -22,6 +22,7 @@
package com.farsunset.cim.mvc.controller.admin;
import com.farsunset.cim.service.SessionService;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@ -30,6 +31,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
@Controller
@Api(produces = "application/json", tags = "在线用户页面",hidden = true)
@RequestMapping("/console/session")
public class SessionController {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -19,7 +19,7 @@
* *
***************************************************************************************
*/
package com.farsunset.cim.mvc.controller.api;
package com.farsunset.cim.mvc.controller.message;
import com.farsunset.cim.service.SessionService;
import io.swagger.annotations.Api;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -19,10 +19,10 @@
* *
***************************************************************************************
*/
package com.farsunset.cim.mvc.controller.api;
package com.farsunset.cim.mvc.controller.message;
import com.farsunset.cim.component.push.DefaultMessagePusher;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.model.Message;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;

View File

@ -0,0 +1,76 @@
/*
* 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.webrtc;
import com.farsunset.cim.annotation.AccessToken;
import com.farsunset.cim.mvc.response.ResponseEntity;
import com.farsunset.cim.service.AccessTokenService;
import io.swagger.annotations.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/user")
@Api(produces = "application/json", tags = "用户登录接口" )
@Validated
public class UserController {
@Resource
private AccessTokenService accessTokenService;
@ApiOperation(httpMethod = "POST", value = "模拟登录")
@ApiImplicitParams({
@ApiImplicitParam(name = "telephone", value = "手机号码", paramType = "query", dataTypeClass = String.class),
@ApiImplicitParam(name = "password", value = "密码", paramType = "query", dataTypeClass = String.class),
})
@PostMapping(value = "/login")
public ResponseEntity<?> login(@RequestParam String telephone) {
Map<String,Object> body = new HashMap<>();
body.put("id",Long.parseLong(telephone));
body.put("name","测试用户");
body.put("telephone","telephone");
ResponseEntity<Map<String,Object>> result = new ResponseEntity<>();
result.setData(body);
result.setToken(accessTokenService.generate(telephone));
result.setTimestamp(System.currentTimeMillis());
return result;
}
@ApiOperation(httpMethod = "GET", value = "退出登录")
@GetMapping(value = "/logout")
public ResponseEntity<Void> logout(@ApiParam(hidden = true) @AccessToken String token) {
accessTokenService.delete(token);
return ResponseEntity.make();
}
}

View File

@ -0,0 +1,189 @@
/*
* 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.webrtc;
import com.farsunset.cim.annotation.UID;
import com.farsunset.cim.component.push.DefaultMessagePusher;
import com.farsunset.cim.constants.MessageAction;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.mvc.request.WebrtcRequest;
import com.farsunset.cim.mvc.response.ResponseEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/webrtc")
@Api(produces = "application/json", tags = "单人通话信令推送接口" )
public class WebrtcController {
@Resource
private DefaultMessagePusher defaultMessagePusher;
@ApiOperation(httpMethod = "POST", value = "发起单人语音通话")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/voice"})
public ResponseEntity<Void> voice(@ApiParam(hidden = true) @UID String uid,@RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_900);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "发起单人视频通话")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/video"})
public ResponseEntity<Void> video(@ApiParam(hidden = true) @UID String uid,@RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_901);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "接受通话")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/accept"})
public ResponseEntity<Void> accept(@ApiParam(hidden = true) @UID String uid,@RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_902);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "拒绝通话")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/reject"})
public ResponseEntity<Void> reject(@ApiParam(hidden = true) @UID String uid,@RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_903);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "反馈正忙")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/busy"})
public ResponseEntity<Void> busy(@ApiParam(hidden = true) @UID String uid, @RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_904);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "挂断通话")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/hangup"})
public ResponseEntity<Void> hangup(@ApiParam(hidden = true) @UID String uid,@RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_905);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "取消呼叫")
@ApiImplicitParam(name = "targetId", value = "对方用户ID", paramType = "query", dataTypeClass = Long.class)
@PostMapping(value = {"/cancel"})
public ResponseEntity<Void> cancel(@ApiParam(hidden = true) @UID String uid, @RequestParam String targetId) {
Message message = new Message();
message.setAction(MessageAction.ACTION_906);
message.setSender(uid);
message.setReceiver(targetId);
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "同步IceCandidate")
@PostMapping(value = {"/transmit/ice"})
public ResponseEntity<Void> ice(@ApiParam(hidden = true) @UID String uid,
@RequestBody WebrtcRequest request
) {
Message message = new Message();
message.setAction(MessageAction.ACTION_907);
message.setSender(uid);
message.setContent(request.getContent());
message.setReceiver(request.getUid());
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "同步offer")
@PostMapping(value = {"/transmit/offer"})
public ResponseEntity<Void> offer(@ApiParam(hidden = true) @UID String uid,
@RequestBody WebrtcRequest request
) {
Message message = new Message();
message.setAction(MessageAction.ACTION_908);
message.setSender(uid);
message.setContent(request.getContent());
message.setReceiver(request.getUid());
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
@ApiOperation(httpMethod = "POST", value = "同步answer")
@PostMapping(value = {"/transmit/answer"})
public ResponseEntity<Void> answer(@ApiParam(hidden = true) @UID String uid,
@RequestBody WebrtcRequest request
) {
Message message = new Message();
message.setAction(MessageAction.ACTION_909);
message.setSender(uid);
message.setContent(request.getContent());
message.setReceiver(request.getUid());
defaultMessagePusher.push(message);
return ResponseEntity.make();
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.interceptor;
import com.farsunset.cim.annotation.AccessToken;
import com.farsunset.cim.annotation.UID;
import com.farsunset.cim.service.AccessTokenService;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 在此鉴权获得UID
*/
@Component
public class TokenInterceptor implements HandlerInterceptor {
private static final String HEADER_TOKEN = "access-token";
@Resource
private AccessTokenService accessTokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader(HEADER_TOKEN);
String uid = accessTokenService.getUid(token);
/*
* 直接拒绝无token的接口调用请求或者token没有查询到对应的登录用户
*/
if (uid == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
request.setAttribute(UID.class.getName(), uid);
request.setAttribute(AccessToken.class.getName(), token);
return true;
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.request;
import com.farsunset.cim.annotation.CreateAction;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@ApiModel("单人通话ice、offer、answer同步请求体")
public class WebrtcRequest implements Serializable {
@NotNull(message = "UID不能为空",groups = CreateAction.class)
@ApiModelProperty("对方UID")
private String uid;
@NotEmpty(message = "content不能超过2000个字符",groups = CreateAction.class)
@ApiModelProperty("ice信息json、offer或者answer的sdp")
private String content;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.resolver;
import com.farsunset.cim.annotation.AccessToken;
import com.farsunset.cim.annotation.UID;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(AccessToken.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
return webRequest.getAttribute(AccessToken.class.getName(),RequestAttributes.SCOPE_REQUEST);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.resolver;
import com.farsunset.cim.annotation.UID;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class UidArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(UID.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
return webRequest.getAttribute(UID.class.getName(),RequestAttributes.SCOPE_REQUEST);
}
}

View File

@ -0,0 +1,109 @@
/*
* 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.response;
import org.springframework.http.HttpStatus;
public class ResponseEntity<T> {
private int code = HttpStatus.OK.value();
private String message;
private T data;
private String token;
private Long timestamp;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getToken() {
return token;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public void setToken(String token) {
this.token = token;
}
public static ResponseEntity<Void> make(){
return new ResponseEntity<>();
}
public static ResponseEntity<Void> make(int code){
return make(code,null);
}
public static <T> ResponseEntity<T> make(int code,String message){
ResponseEntity<T> result = new ResponseEntity<>();
result.setCode(code);
result.setMessage(message);
return result;
}
public static ResponseEntity<Void> make(HttpStatus status){
ResponseEntity<Void> result = new ResponseEntity<>();
result.setCode(status.value());
result.setMessage(status.getReasonPhrase());
return result;
}
public static <Q> ResponseEntity<Q> make(HttpStatus status,String message){
ResponseEntity<Q> result = new ResponseEntity<>();
result.setCode(status.value());
result.setMessage(message);
return result;
}
public static <Q> ResponseEntity<Q> ok(Q data){
ResponseEntity<Q> result = new ResponseEntity<>();
result.setData(data);
return result;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -33,17 +33,13 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(rollbackFor = Exception.class)
public interface SessionRepository extends JpaRepository<Session, Long> {
@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);
@Modifying
@Query("update Session set state = ?3 where uid = ?1 and nid = ?2")
void updateState(String uid,String nid,int state);
@Query("update Session set state = :state where id = :id")
void updateState(long id,int state);
@Modifying
@Query("update Session set state = " + Session.STATE_APNS + " where uid = ?1 and channel = ?2")

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -21,7 +21,8 @@
*/
package com.farsunset.cim.service;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.model.Message;
public interface APNsService {

View File

@ -0,0 +1,32 @@
/*
* 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;
public interface AccessTokenService {
String generate(String uid);
String getUid(String token);
void delete(String value);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -33,14 +33,14 @@ public interface SessionService {
void add(Session session);
void delete(String uid,String nid);
void delete(long id);
/**
* 删除本机的连接记录
*/
void deleteLocalhost();
void updateState(String uid,String nid,int state);
void updateState(long id,int state);
void openApns(String uid,String deviceToken);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -29,7 +29,7 @@ import com.eatthepath.pushy.apns.util.SimpleApnsPayloadBuilder;
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
import com.eatthepath.pushy.apns.util.TokenUtil;
import com.farsunset.cim.config.properties.APNsProperties;
import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.model.Message;
import com.farsunset.cim.service.APNsService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

View File

@ -19,43 +19,44 @@
* *
***************************************************************************************
*/
package com.farsunset.cim.sdk.server.handler;
package com.farsunset.cim.service.impl;
import com.farsunset.cim.component.redis.TokenRedisTemplate;
import com.farsunset.cim.service.AccessTokenService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.logging.LogLevel;
import javax.annotation.Resource;
import java.util.UUID;
@ChannelHandler.Sharable
public class LoggingHandler extends io.netty.handler.logging.LoggingHandler {
@Service
public class AccessTokenServiceImpl implements AccessTokenService {
@Resource
private TokenRedisTemplate tokenRedisTemplate;
public LoggingHandler() {
super(LogLevel.INFO);
@Override
public String getUid(String token) {
if (StringUtils.isBlank(token)){
return null;
}
return tokenRedisTemplate.get(token);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelRegistered();
public void delete(String token) {
tokenRedisTemplate.delete(token);
}
/**
* 方便调试这里生成token为永不过期
* @param uid
* @return
*/
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelUnregistered();
public String generate(String uid) {
String newToken = UUID.randomUUID().toString().replace("-","");
tokenRedisTemplate.save(newToken, uid);
return newToken;
}
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
ctx.deregister(promise);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelReadComplete();
}
@Override
public void flush(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.
@ -31,6 +31,7 @@ import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class SessionServiceImpl implements SessionService {
@ -56,18 +57,19 @@ public class SessionServiceImpl implements SessionService {
}
@Override
public void delete(String uid, String nid) {
sessionRepository.delete(uid,nid);
public void delete(long id) {
sessionRepository.deleteById(id);
}
@Override
public void deleteLocalhost() {
sessionRepository.deleteAll(host);
}
@Override
public void updateState(String uid, String nid, int state) {
sessionRepository.updateState(uid,nid,state);
public void updateState(long id, int state) {
sessionRepository.updateState(id,state);
}
@Override
@ -84,6 +86,9 @@ public class SessionServiceImpl implements SessionService {
@Override
public List<Session> findAll() {
return sessionRepository.findAll();
return sessionRepository.findAll()
.stream()
.filter(session -> session.getState() == Session.STATE_ACTIVE || session.getState() == Session.STATE_APNS)
.collect(Collectors.toList());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
* Copyright 2013-2022 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.

View File

@ -1,12 +1,21 @@
# 服务端文档地址
# https://www.yuque.com/yuanfangxiyang/ma4ytb/vvy3iz#pW3DQ
server.port=8080
spring.jackson.default-property-inclusion=non_empty
#单台服务器可设置为dev广播消息走本地消息事件(参见SignalRedisTemplate.java)
#多台服务器集群环境设置为prd广播消息走三方消息队列
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.password = f8HYPmssXL6XmZeK
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
@ -20,6 +29,7 @@ spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.validation-timeout=600000
##################################################################
# JPA Config #
##################################################################
@ -34,7 +44,7 @@ spring.jpa.hibernate.naming.physical-strategy= org.hibernate.boot.model.naming.P
# Redis Config #
##################################################################
spring.redis.host=127.0.0.1
spring.redis.password=RDSV587
spring.redis.port=6379
spring.redis.database=12
spring.redis.lettuce.pool.max-active=10
spring.redis.lettuce.pool.max-wait= 10s
@ -61,7 +71,20 @@ spring.messages.basename=i18n/messages
#commented to disable this port.
cim.app.port=23456
cim.app.enable=true
cim.app.write-idle=45s
cim.app.read-idle=60s
cim.app.max-pong-timeout=3
cim.websocket.enable=true
cim.websocket.port=34567
cim.websocket.path=/
## json or protobuf
cim.websocket.protocol=protobuf
cim.websocket.write-idle=45s
cim.websocket.read-idle=60s
cim.websocket.max-pong-timeout=3
#please setting your p12 info and appId.
cim.apns.p12.file=/apns/app.p12

View File

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8"/>
<title>CIM Webclient </title>
<title>CIM Webclient for protobuf</title>
<link rel="shortcut icon" href="/image/favicon.ico" type="image/x-icon">
<link charset="utf-8" rel="stylesheet" href="/bootstrap-3.3.7-dist/css/bootstrap.min.css" />
<link charset="utf-8" rel="stylesheet" href="/css/common.css" />
@ -29,18 +29,25 @@
function onReplyReceived(reply)
{
console.log(reply);
if(reply.key==='client_bind' && reply.code === "200" )
{
hideProcess();
$('#LoginDialog').fadeOut();
if (reply.key === KEY_CLIENT_BIND && reply.code === CODE_OK) {
hideProcess();
$('#LoginDialog').fadeOut();
$('#MessageDialog').fadeIn();
$('#MessageDialog').addClass("in");
$("#current_account").text($('#account').val());
}
/**
* 链接鉴权失败
*/
if(reply.key === KEY_HANDSHAKE && reply.code === CODE_UNAUTHORIZED){
hideProcess();
showETip("鉴权失败");
}
$('#MessageDialog').fadeIn();
$('#MessageDialog').addClass("in");
$("#current_account").text($('#account').val());
}
}
/** 当收到消息时候回调 **/

View File

@ -8,7 +8,6 @@ const CIM_URI = "ws://" + CIM_HOST + ":" + CIM_PORT;
const APP_VERSION = "1.0.0";
const APP_CHANNEL = "web";
const APP_PACKAGE = "com.farsunset.cim";
/*
*特殊的消息类型代表被服务端强制下线
@ -21,6 +20,16 @@ const REPLY_BODY = 4;
const SENT_BODY = 3;
const PING = 1;
const PONG = 0;
/*
* 握手鉴权常量
*/
const KEY_HANDSHAKE = "client_handshake";
const CODE_UNAUTHORIZED = "401";
const CODE_OK = "200";
const KEY_CLIENT_BIND = "client_bind";
/**
* PONG字符串转换后
* @type {Uint8Array}
@ -54,13 +63,12 @@ CIMPushManager.bind = function (account) {
let browser = getBrowser();
let body = new proto.com.farsunset.cim.sdk.web.model.SentBody();
body.setKey("client_bind");
body.setKey(KEY_CLIENT_BIND);
body.setTimestamp(new Date().getTime());
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("deviceName", browser.name);
body.getDataMap().set("language", navigator.language);
@ -106,7 +114,8 @@ CIMPushManager.innerOnMessageReceived = function (e) {
if (type === REPLY_BODY) {
let message = proto.com.farsunset.cim.sdk.web.model.ReplyBody.deserializeBinary(body);
/**
/*
* 将proto对象转换成json对象去除无用信息
*/
let reply = {};
@ -116,13 +125,21 @@ CIMPushManager.innerOnMessageReceived = function (e) {
reply.timestamp = message.getTimestamp();
reply.data = {};
/**
/*
* 注意遍历map这里的参数 value在前key在后
*/
message.getDataMap().forEach(function (v, k) {
reply.data[k] = v;
});
/*
* 判断是否是握手鉴权失败
* 终止后续自动重连
*/
if(reply.key === KEY_HANDSHAKE && reply.code === CODE_UNAUTHORIZED){
manualStop = true;
}
onReplyReceived(reply);
}
};

View File

@ -1,23 +0,0 @@
//
// CIMHeader.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#ifndef CIMHeader_h
#define CIMHeader_h
#import "GCDAsyncSocket.h"
#import "SentBody.pbobjc.h"
#import "Message.pbobjc.h"
#import "NSData+IM.h"
#import "NSString+IM.h"
#import "CIMSendMessageData.h"
#import "CIMService.h"
#endif /* CIMHeader_h */

View File

@ -1,103 +0,0 @@
//
// CIMMessageObserver.h
// CIMKit
//
// Created by mason on 2020/11/18.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "CIMMessageModel.h"
@class CIMService;
/// 消息回调
@protocol CIMPeerMessageObserver <NSObject>
/// 接受到消息
/// @param msg msg description
-(void)cimHandleMessage:(CIMMessageModel * _Nonnull)msg;
/// 消息解析失败
/// @param data data description
-(void)cimHandleMessageError:(NSData * _Nonnull)data;
@end
/// 服务器连接回调
@protocol CIMConnectionObserver <NSObject>
@optional
/// 用户绑定成功
/// @param bindSuccess bindSuccess description
-(void)cimDidBindUserSuccess:(BOOL)bindSuccess;
/// 连接成功
-(void)cimDidConnectSuccess;
/// 断开连接
-(void)cimDidConnectClose;
/// 连接失败
/// @param error res description
-(void)cimDidConnectError:(NSError *_Nullable)error;
@end
NS_ASSUME_NONNULL_BEGIN
@interface CIMService : NSObject
+(CIMService*)instance;
/// 配置IM服务器
/// @param host host description
/// @param port port description
-(void)configHost:(NSString *)host onPort:(NSInteger)port;
/// 连接服务器并绑定用户
/// @param userId userId description
-(void)connectionBindUserId:(NSString *)userId;
/// 添加消息监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 添加连接状态监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 移除监听
/// @param observer observer description
-(void)removeMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 移除监听回调
/// @param observer observer description
-(void)removeConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 退出后台 断开连接
-(void)enterBackground;
/// 进入前台重新连接
-(void)enterForeground;
/// 重新连接
-(void)reconnect;
/// 断开连接
-(void)disconnect;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,5 +0,0 @@
#### iOS版本SDK介绍
iOS版本SDK是由开发者Siter(siterwu@gmail.com)贡献提供的感谢Siter在百忙之中做出的贡献。
---
## 源码和集成方式参见下面地址
## [https://gitee.com/Siter/cimkit](https://gitee.com/Siter/cimkit)

View File

@ -1 +0,0 @@
集成方式请参考文档和cim-use-examples中对应的demo

View File

@ -1,23 +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-lite:3.0.1" level="project" />
<orderEntry type="module-library">
<library name="Maven: android:android:8.0.0">
<CLASSES>
<root url="jar://$MODULE_DIR$/libs/android.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>

View File

@ -6,46 +6,151 @@
<groupId>com.farsunset</groupId>
<artifactId>cim-android-sdk</artifactId>
<version>4.0.0</version>
<version>4.2.15</version>
<packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name>
<description>Netty based instant messaging android sdk</description>
<url>http://farsunset.com</url>
<licenses>
<license>
<name>Apache License</name>
<url>http://www.apache.org/licenses/</url>
</license>
</licenses>
<scm>
<connection>https://github.com/farsunset/cim.git</connection>
<url>https://github.com/farsunset/cim</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<protobuf.lite.version>3.0.1</protobuf.lite.version>
<google.protobuf.version>3.25.4</google.protobuf.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-lite</artifactId>
<version>${protobuf.lite.version}</version>
<artifactId>protobuf-javalite</artifactId>
<version>${google.protobuf.version}</version>
</dependency>
<dependency>
<groupId>android</groupId>
<artifactId>android</artifactId>
<scope>system</scope>
<version>8.0.0</version>
<version>15.0.0</version>
<systemPath>${project.basedir}/libs/android.jar</systemPath>
</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>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
<charset>UTF-8</charset>
<encoding>UTF-8</encoding>
<docencoding>UTF-8</docencoding>
<additionalparam>-Xdoclint:none</additionalparam>
<!-- TODO 临时解决不规范的javadoc生成报错,后面要规范化后把这行去掉 -->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!--Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<verbose>true</verbose>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!--Release -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.1</version>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<developers>
<developer>
<name>Jun Xia</name>
<email>3979434@qq.com</email>
<roles>
<role>Developer</role>
</roles>
<timezone>+8</timezone>
</developer>
</developers>
</project>

View File

@ -0,0 +1 @@
mvn clean install deploy -P release

View File

@ -0,0 +1 @@
mvn clean install deploy -P release

View File

@ -43,8 +43,21 @@ class CIMCacheManager {
public static final String KEY_CIM_CONNECTION_STATE = "KEY_CIM_CONNECTION_STATE";
public static final String KEY_NTC_SWITCH = "KEY_NTC_SWITCH";
public static final String KEY_NTC_CHANNEL_NAME = "KEY_NTC_CHANNEL_NAME";
public static final String KEY_NTC_CHANNEL_MESSAGE = "KEY_NTC_CHANNEL_MESSAGE";
public static final String KEY_NTC_CHANNEL_ICON = "KEY_NTC_ICON";
public static final String CONTENT_URI = "content://%s.cim.provider";
static final String COLUMN_KEY = "key";
static final String COLUMN_VALUE = "value";
public static void remove(Context context, String key) {
ContentResolver resolver = context.getContentResolver();
@ -55,8 +68,8 @@ class CIMCacheManager {
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put("value", value);
values.put("key", key);
values.put(COLUMN_KEY, key);
values.put(COLUMN_VALUE, value);
resolver.insert(Uri.parse(String.format(CONTENT_URI, context.getPackageName())), values);
}

View File

@ -33,7 +33,7 @@ public class CIMCacheProvider extends ContentProvider {
@Override
public int delete(Uri arg0, String key, String[] arg2) {
getContext().getSharedPreferences(MODEL_KEY, Context.MODE_PRIVATE).edit().remove(key).apply();
getContext().getSharedPreferences(MODEL_KEY, Context.MODE_PRIVATE).edit().remove(key).commit();
return 0;
}
@ -44,9 +44,9 @@ public class CIMCacheProvider extends ContentProvider {
@Override
public Uri insert(Uri arg0, ContentValues values) {
String key = values.getAsString("key");
String value = values.getAsString("value");
getContext().getSharedPreferences(MODEL_KEY, Context.MODE_PRIVATE).edit().putString(key, value).apply();
String key = values.getAsString(CIMCacheManager.COLUMN_KEY);
String value = values.getAsString(CIMCacheManager.COLUMN_VALUE);
getContext().getSharedPreferences(MODEL_KEY, Context.MODE_PRIVATE).edit().putString(key, value).commit();
return null;
}
@ -57,7 +57,7 @@ public class CIMCacheProvider extends ContentProvider {
@Override
public Cursor query(Uri arg0, String[] arg1, String key, String[] arg3, String arg4) {
MatrixCursor cursor = new MatrixCursor(new String[]{"value"});
MatrixCursor cursor = new MatrixCursor(new String[]{CIMCacheManager.COLUMN_VALUE});
String value = getContext().getSharedPreferences(MODEL_KEY, Context.MODE_PRIVATE).getString(arg1[0], null);
cursor.addRow(new Object[]{value});
return cursor;

View File

@ -24,36 +24,36 @@ package com.farsunset.cim.sdk.android;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import com.farsunset.cim.sdk.android.logger.CIMLogger;
import com.farsunset.cim.sdk.android.coder.ClientMessageDecoder;
import com.farsunset.cim.sdk.android.coder.ClientMessageEncoder;
import com.farsunset.cim.sdk.android.constant.BundleKey;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.constant.IntentAction;
import com.farsunset.cim.sdk.android.logger.CIMLogger;
import com.farsunset.cim.sdk.android.model.*;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
/*
* 连接服务端管理cim核心处理类管理连接以及消息处理
*/
class CIMConnectorManager {
private static CIMConnectorManager manager;
class CIMConnectManager {
private static final int READ_BUFFER_SIZE = 2048;
private static final int WRITE_BUFFER_SIZE = 1024;
private static final int CONNECT_TIME_OUT = 10 * 1000;
private static final int CONNECT_TIME_OUT = 5 * 1000;
/*
服务端在连接写空闲120秒的时候发送心跳请求给客户端所以客户端在空闲150秒后都没有收到任何数据则关闭链接并重新创建
@ -75,33 +75,27 @@ class CIMConnectorManager {
private final ClientMessageEncoder messageEncoder = new ClientMessageEncoder();
private final ClientMessageDecoder messageDecoder = new ClientMessageDecoder();
private CIMConnectorManager(Context context) {
private final Random random = new Random();
private final AtomicBoolean connecting = new AtomicBoolean(false);
public CIMConnectManager(Context context) {
this.context = context;
}
public static synchronized CIMConnectorManager getManager(Context context) {
if (manager == null) {
manager = new CIMConnectorManager(context);
}
return manager;
}
public void connect(final String host, final int port) {
if (!CIMPushManager.isNetworkConnected(context)) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECT_FAILED);
intent.setAction(IntentAction.ACTION_CONNECT_FAILED);
context.sendBroadcast(intent);
return;
}
if (isConnected()) {
if (isConnected() || connecting.get()) {
return;
}
@ -117,6 +111,8 @@ class CIMConnectorManager {
try {
connecting.set(true);
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
socketChannel.socket().setTcpNoDelay(true);
@ -128,6 +124,8 @@ class CIMConnectorManager {
handleConnectedEvent();
connecting.set(false);
/*
*开始读取来自服务端的消息先读取3个字节的消息头
*/
@ -140,10 +138,12 @@ class CIMConnectorManager {
*/
close();
} catch (ConnectException | SocketTimeoutException ignore) {
handleConnectAbortedEvent();
} catch (IOException ignore) {
} catch (ConnectException | SocketTimeoutException | UnknownHostException exception) {
handleConnectFailedEvent(exception);
} catch (IOException exception) {
handleDisconnectedEvent();
}finally {
connecting.set(false);
}
});
}
@ -154,19 +154,14 @@ class CIMConnectorManager {
return;
}
try {
socketChannel.close();
} catch (IOException ignore) {
} finally {
this.onSessionClosed();
}
this.closeForce();
}
public boolean isConnected() {
return socketChannel != null && socketChannel.isConnected();
}
public void sendHeartbeat() {
public void pong() {
send(Pong.getInstance());
}
@ -199,13 +194,22 @@ class CIMConnectorManager {
}
private void closeForce(){
try {
socketChannel.close();
} catch (IOException ignore) {
} finally {
this.onSessionClosed();
}
}
private void onSessionCreated() {
LOGGER.sessionCreated(socketChannel);
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECT_FINISHED);
intent.setAction(IntentAction.ACTION_CONNECT_FINISHED);
context.sendBroadcast(intent);
}
@ -218,7 +222,7 @@ class CIMConnectorManager {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED);
intent.setAction(IntentAction.ACTION_CONNECTION_CLOSED);
context.sendBroadcast(intent);
}
@ -237,7 +241,7 @@ class CIMConnectorManager {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED);
intent.setAction(IntentAction.ACTION_MESSAGE_RECEIVED);
intent.putExtra(Message.class.getName(), (Message) obj);
context.sendBroadcast(intent);
@ -246,7 +250,7 @@ class CIMConnectorManager {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED);
intent.setAction(IntentAction.ACTION_REPLY_RECEIVED);
intent.putExtra(ReplyBody.class.getName(), (ReplyBody) obj);
context.sendBroadcast(intent);
}
@ -260,7 +264,7 @@ class CIMConnectorManager {
if (message instanceof SentBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_SEND_FINISHED);
intent.setAction(IntentAction.ACTION_SEND_FINISHED);
intent.putExtra(SentBody.class.getName(), (SentBody) message);
context.sendBroadcast(intent);
}
@ -269,24 +273,36 @@ class CIMConnectorManager {
private final Handler idleHandler = new Handler() {
@Override
public void handleMessage(android.os.Message m) {
workerExecutor.execute(() -> onSessionIdle());
workerExecutor.execute(CIMConnectManager.this::onSessionIdle);
}
};
private void handleDisconnectedEvent() {
close();
closeForce();
}
private void handleConnectAbortedEvent() {
private void handleConnectFailedEvent(Exception exception) {
long interval = CIMConstant.RECONNECT_INTERVAL_TIME - (5 * 1000 - new Random().nextInt(15 * 1000));
long retryAfter;
LOGGER.connectFailure(interval);
if (exception instanceof UnknownHostException){
/*
* 通常是网络由WIFI切换为移动网出现这个异常
*/
retryAfter = 3000L;
}else {
/*
* 随机3-10秒后重连
*/
retryAfter = 3000L + random.nextInt(7001) ;
}
LOGGER.connectFailure(retryAfter);
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECT_FAILED);
intent.putExtra("interval", interval);
intent.setAction(IntentAction.ACTION_CONNECT_FAILED);
intent.putExtra(BundleKey.KEY_RECONNECT_AFTER, retryAfter);
context.sendBroadcast(intent);
}

View File

@ -25,8 +25,10 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.Build;
import com.farsunset.cim.sdk.android.constant.BundleKey;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.constant.IntentAction;
import com.farsunset.cim.sdk.android.constant.ServiceAction;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
@ -38,7 +40,6 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
protected Context context;
@SuppressWarnings("deprecation")
@Override
public void onReceive(Context context, Intent intent) {
@ -50,6 +51,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
* 操作事件广播用于提高service存活率
*/
if (Intent.ACTION_USER_PRESENT.equals(action)
|| Intent.ACTION_BOOT_COMPLETED.equals(action)
|| Intent.ACTION_POWER_CONNECTED.equals(action)
|| Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
startPushService();
@ -58,7 +60,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
/*
* 设备网络状态变化事件
*/
if (CIMConstant.IntentAction.ACTION_NETWORK_CHANGED.equals(action)
if (IntentAction.ACTION_NETWORK_CHANGED.equals(action)
|| ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
onDevicesNetworkChanged();
@ -67,36 +69,36 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
/*
* cim断开服务器事件
*/
if (CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED.equals(action)) {
if (IntentAction.ACTION_CONNECTION_CLOSED.equals(action)) {
onInnerConnectionClosed();
}
/*
* cim连接服务器失败事件
*/
if (CIMConstant.IntentAction.ACTION_CONNECT_FAILED.equals(action)) {
long interval = intent.getLongExtra("interval", CIMConstant.RECONNECT_INTERVAL_TIME);
if (IntentAction.ACTION_CONNECT_FAILED.equals(action)) {
long interval = intent.getLongExtra(BundleKey.KEY_RECONNECT_AFTER, CIMConstant.RECONNECT_INTERVAL_TIME);
onInnerConnectFailed(interval);
}
/*
* cim连接服务器成功事件
*/
if (CIMConstant.IntentAction.ACTION_CONNECT_FINISHED.equals(action)) {
if (IntentAction.ACTION_CONNECT_FINISHED.equals(action)) {
onInnerConnectFinished();
}
/*
* 收到推送消息事件
*/
if (CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED.equals(action)) {
if (IntentAction.ACTION_MESSAGE_RECEIVED.equals(action)) {
onInnerMessageReceived((Message) intent.getSerializableExtra(Message.class.getName()), intent);
}
/*
* 获取收到replyBody成功事件
*/
if (CIMConstant.IntentAction.ACTION_REPLY_RECEIVED.equals(action)) {
if (IntentAction.ACTION_REPLY_RECEIVED.equals(action)) {
onReplyReceived((ReplyBody) intent.getSerializableExtra(ReplyBody.class.getName()));
}
@ -104,49 +106,36 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
/*
* 获取sendBody发送成功事件
*/
if (CIMConstant.IntentAction.ACTION_SEND_FINISHED.equals(action)) {
if (IntentAction.ACTION_SEND_FINISHED.equals(action)) {
onSentSucceed((SentBody) intent.getSerializableExtra(SentBody.class.getName()));
}
/*
* 重新连接如果断开的话
*/
if (CIMConstant.IntentAction.ACTION_CONNECTION_RECOVERY.equals(action)) {
if (IntentAction.ACTION_CONNECTION_RECOVERY.equals(action)) {
connect(0);
}
}
private void startPushService() {
Intent intent = new Intent(context, CIMPushService.class);
intent.setAction(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
intent.setAction(ServiceAction.ACTION_ACTIVATE_PUSH_SERVICE);
CIMPushManager.startService(context,intent);
}
private void onInnerConnectionClosed() {
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
if (CIMPushManager.isNetworkConnected(context)) {
connect(0);
}
connect(0L);
onConnectionClosed();
}
private void onInnerConnectFailed(long interval) {
if (CIMPushManager.isNetworkConnected(context)) {
onConnectFailed();
onConnectFailed();
connect(interval);
connect(interval);
}
}
private void onInnerConnectFinished() {
@ -157,18 +146,13 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
}
private void onDevicesNetworkChanged() {
if (CIMPushManager.isNetworkConnected(context)) {
connect(0);
}
onNetworkChanged();
}
private void connect(long delay) {
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMPushService.KEY_DELAYED_TIME, delay);
serviceIntent.setAction(CIMPushManager.ACTION_CREATE_CIM_CONNECTION);
serviceIntent.putExtra(BundleKey.KEY_DELAYED_TIME, delay);
serviceIntent.setAction(ServiceAction.ACTION_CREATE_CONNECTION);
CIMPushManager.startService(context, serviceIntent);
}
@ -181,12 +165,11 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
}
private boolean isForceOfflineMessage(String action) {
return CIMConstant.MessageAction.ACTION_999.equals(action);
return CIMConstant.ACTION_999.equals(action);
}
/**
* 接收消息实现方法
*
* @param message
* @param intent
*/

View File

@ -33,35 +33,30 @@ public interface CIMEventListener {
/**
* 当收到服务端推送过来的消息时调用
*
* @param message
*/
void onMessageReceived(Message message);
/**
* 当调用CIMPushManager.sendRequest()向服务端发送请求获得相应时调用
*
* 当调用CIMPushManager.sendRequest()向服务端发送请求获得服务端响应时调用
* @param body
*/
void onReplyReceived(ReplyBody body);
/**
* 当调用CIMPushManager.sendRequest()向服务端发送请求成功时
*
* @param body
*/
void onSendFinished(SentBody body);
/**
* 当手机网络发生变化时调用
*
* @param info
*/
void onNetworkChanged(NetworkInfo info);
/**
* 当连接服务器成功时回调
*
* @param hasAutoBind true 已经自动绑定账号到服务器了不需要再手动调用bindAccount
*/
void onConnectFinished(boolean hasAutoBind);

View File

@ -22,21 +22,21 @@
package com.farsunset.cim.sdk.android;
import android.net.NetworkInfo;
import android.util.Log;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
/**
* CIM 消息监听器管理
*/
public class CIMListenerManager {
private static final ArrayList<CIMEventListener> cimListeners = new ArrayList<>();
private static final List<CIMEventListener> cimListeners = new LinkedList<>();
private static final ReceiveComparator comparator = new ReceiveComparator();
private CIMListenerManager() {
@ -56,32 +56,32 @@ public class CIMListenerManager {
}
public static void notifyOnNetworkChanged(NetworkInfo info) {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onNetworkChanged(info);
}
}
public static void notifyOnConnectFinished(boolean hasAutoBind) {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onConnectFinished(hasAutoBind);
}
}
public static void notifyOnMessageReceived(Message message) {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onMessageReceived(message);
}
}
public static void notifyOnConnectionClosed() {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onConnectionClosed();
}
}
public static void notifyOnConnectFailed() {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onConnectFailed();
}
@ -89,14 +89,14 @@ public class CIMListenerManager {
public static void notifyOnReplyReceived(ReplyBody body) {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onReplyReceived(body);
}
}
public static void notifyOnSendFinished(SentBody body) {
for (CIMEventListener cimListener : cimListeners) {
for (CIMEventListener cimListener : getListeners()) {
cimListener.onSendFinished(body);
}
}
@ -105,10 +105,8 @@ public class CIMListenerManager {
cimListeners.clear();
}
public static void logListenersName() {
for (CIMEventListener cimListener : cimListeners) {
Log.i(CIMEventListener.class.getSimpleName(), "#######" + cimListener.getClass().getName() + "#######");
}
public static List<CIMEventListener> getListeners() {
return new LinkedList<>(cimListeners);
}
/**

View File

@ -30,39 +30,27 @@ import android.net.NetworkInfo;
import android.os.Build;
import android.os.LocaleList;
import android.text.TextUtils;
import com.farsunset.cim.sdk.android.constant.BundleKey;
import com.farsunset.cim.sdk.android.constant.IntentAction;
import com.farsunset.cim.sdk.android.constant.RequestKey;
import com.farsunset.cim.sdk.android.constant.ServiceAction;
import com.farsunset.cim.sdk.android.logger.CIMLogger;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.SentBody;
import java.util.Locale;
import java.util.UUID;
/**
* CIM 功能接口
* CIM客户端sdk功能接口
*/
public class CIMPushManager {
protected static final String ACTION_CREATE_CIM_CONNECTION = "ACTION_CREATE_CIM_CONNECTION";
protected static final String ACTION_DESTROY_CIM_SERVICE = "ACTION_DESTROY_CIM_SERVICE";
protected static final String ACTION_ACTIVATE_PUSH_SERVICE = "ACTION_ACTIVATE_PUSH_SERVICE";
protected static final String ACTION_SEND_REQUEST_BODY = "ACTION_SEND_REQUEST_BODY";
protected static final String ACTION_CLOSE_CIM_CONNECTION = "ACTION_CLOSE_CIM_CONNECTION";
protected static final String ACTION_SET_LOGGER_EATABLE = "ACTION_SET_LOGGER_EATABLE";
protected static final String ACTION_SHOW_PERSIST_NOTIFICATION = "ACTION_SHOW_PERSIST_NOTIFICATION";
protected static final String ACTION_HIDE_PERSIST_NOTIFICATION = "ACTION_HIDE_PERSIST_NOTIFICATION";
protected static final String ACTION_CIM_CONNECTION_PONG = "ACTION_CIM_CONNECTION_PONG";
/**
* 初始化,连接服务端在程序启动页或者 在Application里调用
* @param context
* @param host cim服务端IP或者域名
* @param port cim服务端端口
*/
public static void connect(Context context, String host, int port) {
@ -79,40 +67,66 @@ public class CIMPushManager {
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_CREATE_CIM_CONNECTION);
serviceIntent.setAction(ServiceAction.ACTION_CREATE_CONNECTION);
startService(context, serviceIntent);
}
/**
* 设置SDK日志打印开关
* @param context
* @param enable
*/
public static void setLoggerEnable(Context context, boolean enable) {
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMPushService.KEY_LOGGER_ENABLE, enable);
serviceIntent.setAction(ACTION_SET_LOGGER_EATABLE);
serviceIntent.putExtra(BundleKey.KEY_LOGGER_ENABLE, enable);
serviceIntent.setAction(ServiceAction.ACTION_SET_LOGGER_EATABLE);
startService(context, serviceIntent);
}
/**
* 开启常驻通知栏
* @param context
* @param icon 通知图标
* @param channel 通知channel
* @param message 显示内容
*/
public static void startForeground(Context context,int icon, String channel , String message) {
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMPushService.KEY_NOTIFICATION_MESSAGE, message);
serviceIntent.putExtra(CIMPushService.KEY_NOTIFICATION_CHANNEL, channel);
serviceIntent.putExtra(CIMPushService.KEY_NOTIFICATION_ICON, icon);
serviceIntent.setAction(ACTION_SHOW_PERSIST_NOTIFICATION);
startService(context, serviceIntent);
}
public static void cancelForeground(Context context) {
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_HIDE_PERSIST_NOTIFICATION);
serviceIntent.putExtra(BundleKey.KEY_NOTIFICATION_MESSAGE, message);
serviceIntent.putExtra(BundleKey.KEY_NOTIFICATION_CHANNEL, channel);
serviceIntent.putExtra(BundleKey.KEY_NOTIFICATION_ICON, icon);
serviceIntent.setAction(ServiceAction.ACTION_SHOW_PERSIST_NOTIFICATION);
startService(context, serviceIntent);
}
/**
* 设置一个账号登录到服务端
* 关闭常驻通知栏
* @param context
*/
public static void cancelForeground(Context context) {
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ServiceAction.ACTION_HIDE_PERSIST_NOTIFICATION);
startService(context, serviceIntent);
}
/**
* bind账户
* 通知服务端 长连接和uid进行关联
* @param context
* @param uid 用户标识
*/
public static void bind(Context context, long uid) {
bind(context,String.valueOf(uid));
}
/**
* bind账户
* 通知服务端 长连接和uid进行关联
* @param context
* @param uid 用户标识
*/
public static void bind(Context context, String uid) {
if (isDestroyed(context)) {
@ -122,47 +136,61 @@ public class CIMPushManager {
sendBindRequest(context, uid);
}
/**
* 通知服务端给当前长连接设置tag
* @param context
* @param tag 标识
*/
public static void setTag(Context context, String tag) {
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_SET_TAG);
sent.setKey(RequestKey.CLIENT_SET_TAG);
sent.put("tag", tag);
sendRequest(context, sent);
}
/**
* 通知服务端清除tag
* @param context
*/
public static void removeTag(Context context) {
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_REMOVE_TAG);
sent.setKey(RequestKey.CLIENT_REMOVE_TAG);
sendRequest(context, sent);
}
/**
* 长连接发送一次心跳响应
* @param context
*/
public static void pong(Context context) {
if (isDestroyed(context) || isStopped(context)) {
return;
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_CIM_CONNECTION_PONG);
serviceIntent.setAction(ServiceAction.ACTION_CREATE_CONNECTION);
startService(context, serviceIntent);
}
private static void sendBindRequest(Context context, String uid) {
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_MANUAL_STOP, false);
CIMCacheManager.putString(context, CIMCacheManager.KEY_UID, uid);
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
sent.setKey(RequestKey.CLIENT_BIND);
sent.put("uid", String.valueOf(uid));
sent.put("channel", "android");
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());
sent.put("language", getLanguage());
sent.setTimestamp(System.currentTimeMillis());
sendRequest(context, sent);
@ -182,7 +210,9 @@ public class CIMPushManager {
}
/**
* 发送一个CIM请求
* 向服务端发送一次自定义业务请求
* @param context
* @param body 请求体
*/
public static void sendRequest(Context context, SentBody body) {
@ -191,8 +221,8 @@ public class CIMPushManager {
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMPushService.KEY_SEND_BODY, body);
serviceIntent.setAction(ACTION_SEND_REQUEST_BODY);
serviceIntent.putExtra(BundleKey.KEY_SEND_BODY, body);
serviceIntent.setAction(ServiceAction.ACTION_SEND_REQUEST_BODY);
startService(context, serviceIntent);
}
@ -209,7 +239,7 @@ public class CIMPushManager {
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_MANUAL_STOP, true);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_CLOSE_CIM_CONNECTION);
serviceIntent.setAction(ServiceAction.ACTION_CREATE_CONNECTION);
startService(context, serviceIntent);
}
@ -223,7 +253,7 @@ public class CIMPushManager {
CIMCacheManager.remove(context, CIMCacheManager.KEY_UID);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_DESTROY_CIM_SERVICE);
serviceIntent.setAction(ServiceAction.ACTION_CREATE_CONNECTION);
startService(context, serviceIntent);
}
@ -240,33 +270,59 @@ public class CIMPushManager {
autoBindAccount(context);
}
/**
* 获取sdk是否已经销毁的
* @param context
* @return
*/
public static boolean isDestroyed(Context context) {
return CIMCacheManager.getBoolean(context, CIMCacheManager.KEY_CIM_DESTROYED);
}
/**
* 判断是否暂停接收消息
* @param context
* @return
*/
public static boolean isStopped(Context context) {
return CIMCacheManager.getBoolean(context, CIMCacheManager.KEY_MANUAL_STOP);
}
/**
* 判断于服务端连接是否正常
* @param context
*/
public static boolean isConnected(Context context) {
return CIMCacheManager.getBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE);
}
/**
* 判断客户端网络连接是否正常
* @param context
*/
public static boolean isNetworkConnected(Context context) {
NetworkInfo networkInfo = getNetworkInfo(context);
return networkInfo != null && networkInfo.isConnected();
}
/**
* 获取服务端网络信息
* @param context
*/
public static NetworkInfo getNetworkInfo(Context context) {
return ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
}
public static void startService(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
protected static void startService(Context context, Intent intent) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(intent);
return;
}
try {
context.startForegroundService(intent);
}catch (Exception ignore){
context.sendBroadcast(new Intent(IntentAction.ACTION_CONNECTION_RECOVERY));
}
}
@ -276,8 +332,7 @@ public class CIMPushManager {
try {
PackageInfo mPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return mPackageInfo.versionName;
} catch (NameNotFoundException ignore) {
}
} catch (NameNotFoundException ignore) {}
return null;
}

View File

@ -26,18 +26,22 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.net.ConnectivityManager;
import android.net.Network;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.constant.BundleKey;
import com.farsunset.cim.sdk.android.constant.IntentAction;
import com.farsunset.cim.sdk.android.constant.ServiceAction;
import com.farsunset.cim.sdk.android.logger.CIMLogger;
import com.farsunset.cim.sdk.android.model.Pong;
import com.farsunset.cim.sdk.android.model.SentBody;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
/**
* 与服务端连接服务
@ -46,63 +50,44 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public class CIMPushService extends Service {
static final String KEY_SEND_BODY = "KEY_SEND_BODY";
static final String KEY_DELAYED_TIME = "KEY_DELAYED_TIME";
static final String KEY_LOGGER_ENABLE = "KEY_LOGGER_ENABLE";
static final String KEY_NOTIFICATION_MESSAGE = "KEY_NOTIFICATION_MESSAGE";
static final String KEY_NOTIFICATION_CHANNEL = "KEY_NOTIFICATION_CHANNEL";
static final String KEY_NOTIFICATION_ICON = "KEY_NOTIFICATION_ICON";
private static final String TRANSIENT_NTC_CHANNEL_ID = "CIM_PUSH_TRANSIENT_NTC_ID";
private static final String PERSIST_NTC_CHANNEL_ID = "CIM_PUSH_PERSIST_NTC_ID";
private static final String TRANSIENT_NTC_CHANNEL_ID = "PUSH_TRANSIENT_NTC_ID";
private static final String PERSIST_NTC_CHANNEL_ID = "PUSH_PERSIST_NTC_ID";
private static final int NOTIFICATION_ID = Integer.MAX_VALUE;
private static final int PERSIST_NOTIFICATION_ID = Integer.MIN_VALUE;
private CIMConnectManager connectManager;
private CIMConnectorManager connectorManager;
private KeepAliveBroadcastReceiver keepAliveReceiver;
private ConnectivityManager connectivityManager;
private NotificationManager notificationManager;
private final AtomicBoolean persistHolder = new AtomicBoolean(false);
@Override
public void onCreate() {
connectorManager = CIMConnectorManager.getManager(this.getApplicationContext());
connectManager = new CIMConnectManager(this);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
keepAliveReceiver = new KeepAliveBroadcastReceiver();
registerReceiver(keepAliveReceiver, keepAliveReceiver.getIntentFilter());
}
keepAliveReceiver = new KeepAliveBroadcastReceiver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
this.registerReceiver(keepAliveReceiver, keepAliveReceiver.getIntentFilter());
connectivityManager = getSystemService(ConnectivityManager.class);
connectivityManager = getSystemService(ConnectivityManager.class);
connectivityManager.registerDefaultNetworkCallback(networkCallback);
connectivityManager.registerDefaultNetworkCallback(networkCallback);
}
}
private final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
Intent intent = new Intent();
intent.setPackage(getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_NETWORK_CHANGED);
sendBroadcast(intent);
sendBroadcast(new Intent(IntentAction.ACTION_NETWORK_CHANGED).setPackage(getPackageName()));
handleKeepAlive();
}
@Override
public void onUnavailable() {
Intent intent = new Intent();
intent.setPackage(getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_NETWORK_CHANGED);
sendBroadcast(intent);
public void onLost(Network network) {
sendBroadcast(new Intent(IntentAction.ACTION_NETWORK_CHANGED).setPackage(getPackageName()));
}
};
private final Handler connectHandler = new Handler() {
@ -115,67 +100,82 @@ public class CIMPushService extends Service {
private final Handler notificationHandler = new Handler() {
@Override
public void handleMessage(android.os.Message message) {
if (persistHolder.get()){
return;
if (!CIMCacheManager.getBoolean(CIMPushService.this,CIMCacheManager.KEY_NTC_SWITCH)){
stopForeground(true);
}
stopForeground(true);
}
};
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return super.registerReceiver(keepAliveReceiver, keepAliveReceiver.getIntentFilter(),Context.RECEIVER_EXPORTED);
}else {
return super.registerReceiver(keepAliveReceiver, keepAliveReceiver.getIntentFilter());
}
}
private void startForegroundNotification(int id, Notification notification) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startForeground(id,notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING);
}else {
startForeground(id,notification);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent == null ? CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE : intent.getAction();
Intent newIntent = intent == null ? new Intent(ServiceAction.ACTION_ACTIVATE_PUSH_SERVICE) : intent;
if (!persistHolder.get()) {
createNotification();
String action = newIntent.getAction();
createTransientNotification();
if (ServiceAction.ACTION_CREATE_CONNECTION.equals(action)) {
this.prepareConnect(newIntent.getLongExtra(BundleKey.KEY_DELAYED_TIME, 0));
}
if (CIMPushManager.ACTION_CREATE_CIM_CONNECTION.equals(action)) {
this.prepareConnect(intent.getLongExtra(KEY_DELAYED_TIME, 0));
if (ServiceAction.ACTION_SEND_REQUEST_BODY.equals(action)) {
connectManager.send((SentBody) newIntent.getSerializableExtra(BundleKey.KEY_SEND_BODY));
}
if (CIMPushManager.ACTION_SEND_REQUEST_BODY.equals(action)) {
connectorManager.send((SentBody) intent.getSerializableExtra(KEY_SEND_BODY));
if (ServiceAction.ACTION_CLOSE_CONNECTION.equals(action)) {
connectManager.close();
}
if (CIMPushManager.ACTION_CLOSE_CIM_CONNECTION.equals(action)) {
connectorManager.close();
}
if (CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action)) {
if (ServiceAction.ACTION_ACTIVATE_PUSH_SERVICE.equals(action)) {
handleKeepAlive();
}
if (CIMPushManager.ACTION_DESTROY_CIM_SERVICE.equals(action)) {
connectorManager.close();
if (ServiceAction.ACTION_DESTROY_SERVICE.equals(action)) {
connectManager.close();
this.stopSelf();
}
if (CIMPushManager.ACTION_CIM_CONNECTION_PONG.equals(action)) {
connectorManager.send(Pong.getInstance());
if (ServiceAction.ACTION_CONNECTION_PONG.equals(action)) {
connectManager.send(Pong.getInstance());
}
if (CIMPushManager.ACTION_SET_LOGGER_EATABLE.equals(action)) {
boolean enable = intent.getBooleanExtra(KEY_LOGGER_ENABLE, true);
if (ServiceAction.ACTION_SET_LOGGER_EATABLE.equals(action)) {
boolean enable = newIntent.getBooleanExtra(BundleKey.KEY_LOGGER_ENABLE, true);
CIMLogger.getLogger().debugMode(enable);
}
if (CIMPushManager.ACTION_SHOW_PERSIST_NOTIFICATION.equals(action)) {
createPersistNotification(intent.getStringExtra(KEY_NOTIFICATION_CHANNEL),
intent.getStringExtra(KEY_NOTIFICATION_MESSAGE),
intent.getIntExtra(KEY_NOTIFICATION_ICON,0));
persistHolder.set(true);
if (ServiceAction.ACTION_HIDE_PERSIST_NOTIFICATION.equals(action)) {
this.stopForeground(true);
CIMCacheManager.putBoolean(this, CIMCacheManager.KEY_NTC_SWITCH,false);
}
if (CIMPushManager.ACTION_HIDE_PERSIST_NOTIFICATION.equals(action)) {
stopForeground(true);
persistHolder.set(false);
if (ServiceAction.ACTION_SHOW_PERSIST_NOTIFICATION.equals(action)) {
createPersistNotification(newIntent.getStringExtra(BundleKey.KEY_NOTIFICATION_CHANNEL),
newIntent.getStringExtra(BundleKey.KEY_NOTIFICATION_MESSAGE),
newIntent.getIntExtra(BundleKey.KEY_NOTIFICATION_ICON,0));
return super.onStartCommand(intent,flags,startId);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationHandler.sendEmptyMessageDelayed(0, 200);
}
notificationHandler.sendEmptyMessageDelayed(0, 200);
return super.onStartCommand(intent,flags,startId);
}
@ -187,6 +187,8 @@ public class CIMPushService extends Service {
return;
}
connectHandler.removeMessages(0);
connectHandler.sendEmptyMessageDelayed(0, delayMillis);
}
@ -199,12 +201,12 @@ public class CIMPushService extends Service {
String host = CIMCacheManager.getString(this, CIMCacheManager.KEY_CIM_SERVER_HOST);
int port = CIMCacheManager.getInt(this, CIMCacheManager.KEY_CIM_SERVER_PORT);
if (host == null || host.trim().length() == 0 || port <= 0) {
if (host == null || host.trim().isEmpty() || port <= 0) {
Log.e(this.getClass().getSimpleName(), "Invalid hostname or port. host:" + host + " port:" + port);
return;
}
connectorManager.connect(host, port);
connectManager.connect(host, port);
}
@ -212,8 +214,8 @@ public class CIMPushService extends Service {
CIMLogger.getLogger().connectState(true, CIMPushManager.isStopped(this), CIMPushManager.isDestroyed(this));
if (connectorManager.isConnected()) {
connectorManager.sendHeartbeat();
if (connectManager.isConnected()) {
connectManager.pong();
return;
}
@ -228,32 +230,31 @@ public class CIMPushService extends Service {
@Override
public void onDestroy() {
super.onDestroy();
release();
}
private void release() {
connectHandler.removeMessages(0);
stopForeground(true);
persistHolder.set(false);
unregisterReceiver(keepAliveReceiver);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
unregisterReceiver(keepAliveReceiver);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
connectivityManager.unregisterNetworkCallback(networkCallback);
}
private void createNotification() {
private void createTransientNotification() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
if (notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) != null) {
int icon = CIMCacheManager.getInt(this, CIMCacheManager.KEY_NTC_CHANNEL_ICON);
String title = CIMCacheManager.getString(this, CIMCacheManager.KEY_NTC_CHANNEL_NAME);
String message = CIMCacheManager.getString(this, CIMCacheManager.KEY_NTC_CHANNEL_MESSAGE);
Notification notification = makeNotification(PERSIST_NTC_CHANNEL_ID,icon,title,message);
startForegroundNotification(NOTIFICATION_ID, notification);
return;
}
if (notificationManager.getNotificationChannel(TRANSIENT_NTC_CHANNEL_ID) == null) {
NotificationChannel channel = new NotificationChannel(TRANSIENT_NTC_CHANNEL_ID, getClass().getSimpleName(), NotificationManager.IMPORTANCE_LOW);
channel.enableLights(false);
@ -262,17 +263,21 @@ public class CIMPushService extends Service {
notificationManager.createNotificationChannel(channel);
}
Notification notification = new Notification.Builder(this,TRANSIENT_NTC_CHANNEL_ID)
.setContentTitle(CIMPushService.class.getSimpleName())
.build();
Notification notification = makeNotification(TRANSIENT_NTC_CHANNEL_ID,0, CIMPushService.class.getSimpleName(),null);
startForegroundNotification(NOTIFICATION_ID, notification);
startForeground(NOTIFICATION_ID, notification);
}
private void createPersistNotification(String channelName ,String message,int icon) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) == null) {
CIMCacheManager.putString(this, CIMCacheManager.KEY_NTC_CHANNEL_NAME,channelName);
CIMCacheManager.putString(this, CIMCacheManager.KEY_NTC_CHANNEL_MESSAGE,message);
CIMCacheManager.putInt(this, CIMCacheManager.KEY_NTC_CHANNEL_ICON,icon);
CIMCacheManager.putBoolean(this, CIMCacheManager.KEY_NTC_SWITCH,true);
if (notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) == null) {
NotificationChannel channel = new NotificationChannel(PERSIST_NTC_CHANNEL_ID,channelName, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.setShowBadge(false);
@ -281,26 +286,36 @@ public class CIMPushService extends Service {
notificationManager.createNotificationChannel(channel);
}
Notification notification = makeNotification(PERSIST_NTC_CHANNEL_ID,icon,channelName,message);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setPackage(getPackageName());
startForegroundNotification(NOTIFICATION_ID,notification);
}
private Notification makeNotification(String channel,int icon,String title,String message){
Notification.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
builder = new Notification.Builder(this,PERSIST_NTC_CHANNEL_ID);
}else {
builder = new Notification.Builder(this);
}
builder = new Notification.Builder(this, channel);
builder.setAutoCancel(false)
.setOngoing(false)
.setSmallIcon(icon)
.setWhen(System.currentTimeMillis())
.setContentIntent(PendingIntent.getActivity(this, 0, intent, 0))
.setContentTitle(channelName)
.setContentText(message);
.setOngoing(false)
.setWhen(System.currentTimeMillis())
.setContentIntent(getPendingIntent())
.setContentTitle(title)
.setContentText(message);
startForeground(PERSIST_NOTIFICATION_ID, builder.build());
if (icon > 0){
builder.setSmallIcon(icon);
}
return builder.build();
}
private PendingIntent getPendingIntent(){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.setPackage(getPackageName());
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}
private class KeepAliveBroadcastReceiver extends BroadcastReceiver {
@ -315,6 +330,8 @@ public class CIMPushService extends Service {
intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
intentFilter.addAction(IntentAction.ACTION_CONNECTION_RECOVERY);
return intentFilter;
}

View File

@ -22,9 +22,9 @@
package com.farsunset.cim.sdk.android.coder;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.Ping;
import com.farsunset.cim.sdk.android.constant.ProtobufType;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.Ping;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.proto.MessageProto;
import com.farsunset.cim.sdk.android.model.proto.ReplyBodyProto;
@ -72,12 +72,12 @@ public class ClientMessageDecoder {
/*
消息读取完成后通过type来解析成对应的消息体
*/
if (CIMConstant.ProtobufType.PING == type) {
if (ProtobufType.PING == type) {
return Ping.getInstance();
}
if (CIMConstant.ProtobufType.REPLY_BODY == type) {
ReplyBodyProto.Model bodyProto = ReplyBodyProto.Model.parseFrom(bodyBuffer.array());
if (ProtobufType.REPLY_BODY == type) {
ReplyBodyProto.ReplyModel bodyProto = ReplyBodyProto.ReplyModel.parseFrom(bodyBuffer.array());
ReplyBody body = new ReplyBody();
body.setKey(bodyProto.getKey());
body.setTimestamp(bodyProto.getTimestamp());
@ -87,7 +87,7 @@ public class ClientMessageDecoder {
return body;
}
MessageProto.Model bodyProto = MessageProto.Model.parseFrom(bodyBuffer.array());
MessageProto.MessageModel bodyProto = MessageProto.MessageModel.parseFrom(bodyBuffer.array());
Message message = new Message();
message.setId(bodyProto.getId());
message.setAction(bodyProto.getAction());

View File

@ -0,0 +1,40 @@
/*
* 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.android.constant;
public interface BundleKey {
String KEY_SEND_BODY = "KEY_SEND_BODY";
String KEY_DELAYED_TIME = "KEY_DELAYED_TIME";
String KEY_LOGGER_ENABLE = "KEY_LOGGER_ENABLE";
String KEY_NOTIFICATION_MESSAGE = "KEY_NOTIFICATION_MESSAGE";
String KEY_NOTIFICATION_CHANNEL = "KEY_NOTIFICATION_CHANNEL";
String KEY_NOTIFICATION_ICON = "KEY_NOTIFICATION_ICON";
String KEY_RECONNECT_AFTER = "KEY_RECONNECT_AFTER";
}

View File

@ -23,91 +23,16 @@ package com.farsunset.cim.sdk.android.constant;
public interface CIMConstant {
long RECONNECT_INTERVAL_TIME = 30 * 1000;
long RECONNECT_INTERVAL_TIME = 5000L;
/*
* 消息头长度为3个字节第一个字节为消息类型第二第三字节 转换int后为消息长度
*/
int DATA_HEADER_LENGTH = 3;
interface ProtobufType {
/*
客户端->服务端 发送的心跳响应
*/
byte PONG = 0;
/*
服务端->客户端 发送的心跳请求
*/
byte PING = 1;
byte MESSAGE = 2;
byte SENT_BODY = 3;
byte REPLY_BODY = 4;
}
interface RequestKey {
String CLIENT_BIND = "client_bind";
String CLIENT_SET_TAG = "client_set_tag";
String CLIENT_REMOVE_TAG = "client_remove_tag";
}
interface MessageAction {
/*
被其他设备登录挤下线消息
*/
String ACTION_999 = "999";
}
interface IntentAction {
/*
消息广播action
*/
String ACTION_MESSAGE_RECEIVED = "com.farsunset.cim.MESSAGE_RECEIVED";
/*
发送sendBody成功广播
*/
String ACTION_SEND_FINISHED = "com.farsunset.cim.SEND_FINISHED";
/*
链接意外关闭广播
*/
String ACTION_CONNECTION_CLOSED = "com.farsunset.cim.CONNECTION_CLOSED";
/*
链接失败广播
*/
String ACTION_CONNECT_FAILED = "com.farsunset.cim.CONNECT_FAILED";
/*
链接成功广播
*/
String ACTION_CONNECT_FINISHED = "com.farsunset.cim.CONNECT_FINISHED";
/*
发送sendBody成功后获得replayBody回应广播
*/
String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED";
/*
网络变化广播
*/
String ACTION_NETWORK_CHANGED = "com.farsunset.cim.NETWORK_CHANGED";
/*
重试连接
*/
String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
}
/*
被其他设备登录挤下线消息
*/
String ACTION_999 = "999";
}

View File

@ -0,0 +1,66 @@
/*
* 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.android.constant;
public interface IntentAction {
/*
消息广播action
*/
String ACTION_MESSAGE_RECEIVED = "com.farsunset.cim.MESSAGE_RECEIVED";
/*
发送sendBody成功广播
*/
String ACTION_SEND_FINISHED = "com.farsunset.cim.SEND_FINISHED";
/*
链接意外关闭广播
*/
String ACTION_CONNECTION_CLOSED = "com.farsunset.cim.CONNECTION_CLOSED";
/*
链接失败广播
*/
String ACTION_CONNECT_FAILED = "com.farsunset.cim.CONNECT_FAILED";
/*
链接成功广播
*/
String ACTION_CONNECT_FINISHED = "com.farsunset.cim.CONNECT_FINISHED";
/*
发送sendBody成功后获得replayBody回应广播
*/
String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED";
/*
网络变化广播
*/
String ACTION_NETWORK_CHANGED = "com.farsunset.cim.NETWORK_CHANGED";
/*
重试连接
*/
String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
}

View File

@ -0,0 +1,41 @@
/*
* 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.android.constant;
public interface ProtobufType {
/*
客户端->服务端 发送的心跳响应
*/
byte PONG = 0;
/*
服务端->客户端 发送的心跳请求
*/
byte PING = 1;
byte MESSAGE = 2;
byte SENT_BODY = 3;
byte REPLY_BODY = 4;
}

View File

@ -0,0 +1,32 @@
/*
* 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.android.constant;
public interface RequestKey {
String CLIENT_BIND = "client_bind";
String CLIENT_SET_TAG = "client_set_tag";
String CLIENT_REMOVE_TAG = "client_remove_tag";
}

View File

@ -0,0 +1,43 @@
/*
* 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.android.constant;
public interface ServiceAction {
String ACTION_CREATE_CONNECTION = "ACTION_CREATE_CONNECTION";
String ACTION_DESTROY_SERVICE = "ACTION_DESTROY_SERVICE";
String ACTION_ACTIVATE_PUSH_SERVICE = "ACTION_ACTIVATE_PUSH_SERVICE";
String ACTION_SEND_REQUEST_BODY = "ACTION_SEND_REQUEST_BODY";
String ACTION_CLOSE_CONNECTION = "ACTION_CLOSE_CONNECTION";
String ACTION_SET_LOGGER_EATABLE = "ACTION_SET_LOGGER_EATABLE";
String ACTION_SHOW_PERSIST_NOTIFICATION = "ACTION_SHOW_PERSIST_NOTIFICATION";
String ACTION_HIDE_PERSIST_NOTIFICATION = "ACTION_HIDE_PERSIST_NOTIFICATION";
String ACTION_CONNECTION_PONG = "ACTION_CONNECTION_PONG";
}

View File

@ -21,7 +21,7 @@
*/
package com.farsunset.cim.sdk.android.model;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.constant.ProtobufType;
import java.io.Serializable;
@ -56,7 +56,7 @@ public class Pong implements Serializable, BinaryBody {
@Override
public byte getType() {
return CIMConstant.ProtobufType.PONG;
return ProtobufType.PONG;
}
}

View File

@ -21,8 +21,6 @@
*/
package com.farsunset.cim.sdk.android.model;
import android.util.ArrayMap;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

View File

@ -21,8 +21,7 @@
*/
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.constant.ProtobufType;
import com.farsunset.cim.sdk.android.model.proto.SentBodyProto;
import java.io.Serializable;
@ -98,7 +97,7 @@ public class SentBody implements Serializable, BinaryBody {
@Override
public byte[] getByteArray() {
SentBodyProto.Model.Builder builder = SentBodyProto.Model.newBuilder();
SentBodyProto.SentModel.Builder builder = SentBodyProto.SentModel.newBuilder();
builder.setKey(key);
builder.setTimestamp(timestamp);
if (!data.isEmpty()) {
@ -109,7 +108,7 @@ public class SentBody implements Serializable, BinaryBody {
@Override
public byte getType() {
return CIMConstant.ProtobufType.SENT_BODY;
return ProtobufType.SENT_BODY;
}
}

View File

@ -8,42 +8,49 @@ public final class ReplyBodyProto {
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public interface ModelOrBuilder extends
// @@protoc_insertion_point(interface_extends:com.farsunset.cim.sdk.android.model.proto.Model)
public interface ReplyModelOrBuilder extends
// @@protoc_insertion_point(interface_extends:com.farsunset.cim.sdk.android.model.proto.ReplyModel)
com.google.protobuf.MessageLiteOrBuilder {
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The key.
*/
String getKey();
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The bytes for key.
*/
com.google.protobuf.ByteString
getKeyBytes();
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return The code.
*/
String getCode();
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return The bytes for code.
*/
com.google.protobuf.ByteString
getCodeBytes();
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return The message.
*/
String getMessage();
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return The bytes for message.
*/
com.google.protobuf.ByteString
getMessageBytes();
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
* @return The timestamp.
*/
long getTimestamp();
@ -55,7 +62,7 @@ public final class ReplyBodyProto {
* <code>map&lt;string, string&gt; data = 5;</code>
*/
boolean containsData(
String key);
String key);
/**
* Use {@link #getDataMap()} instead.
*/
@ -71,185 +78,192 @@ public final class ReplyBodyProto {
* <code>map&lt;string, string&gt; data = 5;</code>
*/
String getDataOrDefault(
String key,
String defaultValue);
/* nullable */
String getDataOrDefault(
String key,
/* nullable */
String defaultValue);
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
String getDataOrThrow(
String key);
String key);
}
/**
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.Model}
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.ReplyModel}
*/
public static final class Model extends
public static final class ReplyModel extends
com.google.protobuf.GeneratedMessageLite<
Model, Model.Builder> implements
// @@protoc_insertion_point(message_implements:com.farsunset.cim.sdk.android.model.proto.Model)
ModelOrBuilder {
private Model() {
ReplyModel, ReplyModel.Builder> implements
// @@protoc_insertion_point(message_implements:com.farsunset.cim.sdk.android.model.proto.ReplyModel)
ReplyModelOrBuilder {
private ReplyModel() {
key_ = "";
code_ = "";
message_ = "";
}
private int bitField0_;
public static final int KEY_FIELD_NUMBER = 1;
private String key_;
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The key.
*/
@Override
public String getKey() {
return key_;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The bytes for key.
*/
@Override
public com.google.protobuf.ByteString
getKeyBytes() {
return com.google.protobuf.ByteString.copyFromUtf8(key_);
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The key to set.
*/
private void setKey(
String value) {
if (value == null) {
throw new NullPointerException();
}
Class<?> valueClass = value.getClass();
key_ = value;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
*/
private void clearKey() {
key_ = getDefaultInstance().getKey();
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The bytes for key to set.
*/
private void setKeyBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
checkByteStringIsUtf8(value);
key_ = value.toStringUtf8();
}
public static final int CODE_FIELD_NUMBER = 2;
private String code_;
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return The code.
*/
@Override
public String getCode() {
return code_;
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return The bytes for code.
*/
@Override
public com.google.protobuf.ByteString
getCodeBytes() {
return com.google.protobuf.ByteString.copyFromUtf8(code_);
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @param value The code to set.
*/
private void setCode(
String value) {
if (value == null) {
throw new NullPointerException();
}
Class<?> valueClass = value.getClass();
code_ = value;
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
*/
private void clearCode() {
code_ = getDefaultInstance().getCode();
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @param value The bytes for code to set.
*/
private void setCodeBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
checkByteStringIsUtf8(value);
code_ = value.toStringUtf8();
}
public static final int MESSAGE_FIELD_NUMBER = 3;
private String message_;
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return The message.
*/
@Override
public String getMessage() {
return message_;
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return The bytes for message.
*/
@Override
public com.google.protobuf.ByteString
getMessageBytes() {
return com.google.protobuf.ByteString.copyFromUtf8(message_);
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @param value The message to set.
*/
private void setMessage(
String value) {
if (value == null) {
throw new NullPointerException();
}
Class<?> valueClass = value.getClass();
message_ = value;
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
*/
private void clearMessage() {
message_ = getDefaultInstance().getMessage();
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @param value The bytes for message to set.
*/
private void setMessageBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
checkByteStringIsUtf8(value);
message_ = value.toStringUtf8();
}
public static final int TIMESTAMP_FIELD_NUMBER = 4;
private long timestamp_;
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
* @return The timestamp.
*/
@Override
public long getTimestamp() {
return timestamp_;
}
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
* @param value The timestamp to set.
*/
private void setTimestamp(long value) {
timestamp_ = value;
}
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
*/
private void clearTimestamp() {
@ -281,6 +295,7 @@ public final class ReplyBodyProto {
}
return data_;
}
@Override
public int getDataCount() {
return internalGetData().size();
@ -288,15 +303,17 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public boolean containsData(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
return internalGetData().containsKey(key);
}
/**
* Use {@link #getDataMap()} instead.
*/
@Override
@Deprecated
public java.util.Map<String, String> getData() {
return getDataMap();
@ -304,6 +321,7 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public java.util.Map<String, String> getDataMap() {
return java.util.Collections.unmodifiableMap(
@ -312,11 +330,12 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public String getDataOrDefault(
String key,
String defaultValue) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
internalGetData();
return map.containsKey(key) ? map.get(key) : defaultValue;
@ -324,10 +343,11 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public String getDataOrThrow(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
internalGetData();
if (!map.containsKey(key)) {
@ -343,111 +363,73 @@ public final class ReplyBodyProto {
return internalGetMutableData();
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (!key_.isEmpty()) {
output.writeString(1, getKey());
}
if (!code_.isEmpty()) {
output.writeString(2, getCode());
}
if (!message_.isEmpty()) {
output.writeString(3, getMessage());
}
if (timestamp_ != 0L) {
output.writeInt64(4, timestamp_);
}
for (java.util.Map.Entry<String, String> entry
: internalGetData().entrySet()) {
DataDefaultEntryHolder.defaultEntry.serializeTo(
output, 5, entry.getKey(), entry.getValue());
}
public static ReplyModel parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data);
}
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
if (!key_.isEmpty()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(1, getKey());
}
if (!code_.isEmpty()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(2, getCode());
}
if (!message_.isEmpty()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(3, getMessage());
}
if (timestamp_ != 0L) {
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(4, timestamp_);
}
for (java.util.Map.Entry<String, String> entry
: internalGetData().entrySet()) {
size += DataDefaultEntryHolder.defaultEntry.computeMessageSize(
5, entry.getKey(), entry.getValue());
}
memoizedSerializedSize = size;
return size;
public static ReplyModel parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data, extensionRegistry);
}
public static Model parseFrom(
public static ReplyModel parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data);
}
public static Model parseFrom(
public static ReplyModel parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data, extensionRegistry);
}
public static Model parseFrom(byte[] data)
public static ReplyModel parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data);
}
public static Model parseFrom(
public static ReplyModel parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data, extensionRegistry);
}
public static Model parseFrom(java.io.InputStream input)
public static ReplyModel parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, input);
}
public static Model parseFrom(
public static ReplyModel parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, input, extensionRegistry);
}
public static Model parseDelimitedFrom(java.io.InputStream input)
public static ReplyModel parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return parseDelimitedFrom(DEFAULT_INSTANCE, input);
}
public static Model parseDelimitedFrom(
public static ReplyModel parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);
}
public static Model parseFrom(
public static ReplyModel parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, input);
}
public static Model parseFrom(
public static ReplyModel parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
@ -456,41 +438,47 @@ public final class ReplyBodyProto {
}
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
return (Builder) DEFAULT_INSTANCE.createBuilder();
}
public static Builder newBuilder(Model prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
public static Builder newBuilder(ReplyModel prototype) {
return (Builder) DEFAULT_INSTANCE.createBuilder(prototype);
}
/**
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.Model}
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.ReplyModel}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageLite.Builder<
Model, Builder> implements
// @@protoc_insertion_point(builder_implements:com.farsunset.cim.sdk.android.model.proto.Model)
ModelOrBuilder {
// Construct using com.farsunset.cim.sdk.android.model.proto.ReplyBodyProto.Model.newBuilder()
ReplyModel, Builder> implements
// @@protoc_insertion_point(builder_implements:com.farsunset.cim.sdk.android.model.proto.ReplyModel)
ReplyModelOrBuilder {
// Construct using com.farsunset.cim.sdk.android.model.proto.ReplyBodyProto.ReplyModel.newBuilder()
private Builder() {
super(DEFAULT_INSTANCE);
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The key.
*/
@Override
public String getKey() {
return instance.getKey();
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The bytes for key.
*/
@Override
public com.google.protobuf.ByteString
getKeyBytes() {
return instance.getKeyBytes();
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The key to set.
* @return This builder for chaining.
*/
public Builder setKey(
String value) {
@ -499,7 +487,8 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return This builder for chaining.
*/
public Builder clearKey() {
copyOnWrite();
@ -507,7 +496,9 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The bytes for key to set.
* @return This builder for chaining.
*/
public Builder setKeyBytes(
com.google.protobuf.ByteString value) {
@ -517,20 +508,26 @@ public final class ReplyBodyProto {
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return The code.
*/
@Override
public String getCode() {
return instance.getCode();
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return The bytes for code.
*/
@Override
public com.google.protobuf.ByteString
getCodeBytes() {
return instance.getCodeBytes();
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @param value The code to set.
* @return This builder for chaining.
*/
public Builder setCode(
String value) {
@ -539,7 +536,8 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @return This builder for chaining.
*/
public Builder clearCode() {
copyOnWrite();
@ -547,7 +545,9 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional string code = 2;</code>
* <code>string code = 2;</code>
* @param value The bytes for code to set.
* @return This builder for chaining.
*/
public Builder setCodeBytes(
com.google.protobuf.ByteString value) {
@ -557,20 +557,26 @@ public final class ReplyBodyProto {
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return The message.
*/
@Override
public String getMessage() {
return instance.getMessage();
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return The bytes for message.
*/
@Override
public com.google.protobuf.ByteString
getMessageBytes() {
return instance.getMessageBytes();
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @param value The message to set.
* @return This builder for chaining.
*/
public Builder setMessage(
String value) {
@ -579,7 +585,8 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @return This builder for chaining.
*/
public Builder clearMessage() {
copyOnWrite();
@ -587,7 +594,9 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional string message = 3;</code>
* <code>string message = 3;</code>
* @param value The bytes for message to set.
* @return This builder for chaining.
*/
public Builder setMessageBytes(
com.google.protobuf.ByteString value) {
@ -597,13 +606,17 @@ public final class ReplyBodyProto {
}
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
* @return The timestamp.
*/
@Override
public long getTimestamp() {
return instance.getTimestamp();
}
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
* @param value The timestamp to set.
* @return This builder for chaining.
*/
public Builder setTimestamp(long value) {
copyOnWrite();
@ -611,7 +624,8 @@ public final class ReplyBodyProto {
return this;
}
/**
* <code>optional int64 timestamp = 4;</code>
* <code>int64 timestamp = 4;</code>
* @return This builder for chaining.
*/
public Builder clearTimestamp() {
copyOnWrite();
@ -619,6 +633,7 @@ public final class ReplyBodyProto {
return this;
}
@Override
public int getDataCount() {
return instance.getDataMap().size();
@ -626,10 +641,11 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public boolean containsData(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
return instance.getDataMap().containsKey(key);
}
@ -644,7 +660,7 @@ public final class ReplyBodyProto {
public Builder removeData(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
copyOnWrite();
instance.getMutableDataMap().remove(key);
return this;
@ -652,6 +668,7 @@ public final class ReplyBodyProto {
/**
* Use {@link #getDataMap()} instead.
*/
@Override
@Deprecated
public java.util.Map<String, String> getData() {
return getDataMap();
@ -659,6 +676,7 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public java.util.Map<String, String> getDataMap() {
return java.util.Collections.unmodifiableMap(
instance.getDataMap());
@ -666,11 +684,12 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public String getDataOrDefault(
String key,
String defaultValue) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
instance.getDataMap();
return map.containsKey(key) ? map.get(key) : defaultValue;
@ -678,10 +697,11 @@ public final class ReplyBodyProto {
/**
* <code>map&lt;string, string&gt; data = 5;</code>
*/
@Override
public String getDataOrThrow(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
instance.getDataMap();
if (!map.containsKey(key)) {
@ -695,8 +715,8 @@ public final class ReplyBodyProto {
public Builder putData(
String key,
String value) {
if (key == null) { throw new NullPointerException(); }
if (value == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
Class<?> valueClass = value.getClass();
copyOnWrite();
instance.getMutableDataMap().put(key, value);
return this;
@ -711,134 +731,82 @@ public final class ReplyBodyProto {
return this;
}
// @@protoc_insertion_point(builder_scope:com.farsunset.cim.sdk.android.model.proto.Model)
// @@protoc_insertion_point(builder_scope:com.farsunset.cim.sdk.android.model.proto.ReplyModel)
}
@Override
@SuppressWarnings({"unchecked", "fallthrough"})
protected final Object dynamicMethod(
MethodToInvoke method,
Object arg0, Object arg1) {
switch (method) {
case NEW_MUTABLE_INSTANCE: {
return new Model();
}
case IS_INITIALIZED: {
return DEFAULT_INSTANCE;
}
case MAKE_IMMUTABLE: {
data_.makeImmutable();
return null;
return new ReplyModel();
}
case NEW_BUILDER: {
return new Builder();
}
case VISIT: {
Visitor visitor = (Visitor) arg0;
Model other = (Model) arg1;
key_ = visitor.visitString(!key_.isEmpty(), key_,
!other.key_.isEmpty(), other.key_);
code_ = visitor.visitString(!code_.isEmpty(), code_,
!other.code_.isEmpty(), other.code_);
message_ = visitor.visitString(!message_.isEmpty(), message_,
!other.message_.isEmpty(), other.message_);
timestamp_ = visitor.visitLong(timestamp_ != 0L, timestamp_,
other.timestamp_ != 0L, other.timestamp_);
data_ = visitor.visitMap(
data_, other.internalGetData());
if (visitor == MergeFromVisitor
.INSTANCE) {
bitField0_ |= other.bitField0_;
}
return this;
}
case MERGE_FROM_STREAM: {
com.google.protobuf.CodedInputStream input =
(com.google.protobuf.CodedInputStream) arg0;
com.google.protobuf.ExtensionRegistryLite extensionRegistry =
(com.google.protobuf.ExtensionRegistryLite) arg1;
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!input.skipField(tag)) {
done = true;
}
break;
}
case 10: {
String s = input.readStringRequireUtf8();
key_ = s;
break;
}
case 18: {
String s = input.readStringRequireUtf8();
code_ = s;
break;
}
case 26: {
String s = input.readStringRequireUtf8();
message_ = s;
break;
}
case 32: {
timestamp_ = input.readInt64();
break;
}
case 42: {
if (!data_.isMutable()) {
data_ = data_.mutableCopy();
}
DataDefaultEntryHolder.defaultEntry.parseInto(data_, input, extensionRegistry); break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw new RuntimeException(e.setUnfinishedMessage(this));
} catch (java.io.IOException e) {
throw new RuntimeException(
new com.google.protobuf.InvalidProtocolBufferException(
e.getMessage()).setUnfinishedMessage(this));
} finally {
}
case BUILD_MESSAGE_INFO: {
Object[] objects = new Object[] {
"key_",
"code_",
"message_",
"timestamp_",
"data_",
DataDefaultEntryHolder.defaultEntry,
};
String info =
"\u0000\u0005\u0000\u0000\u0001\u0005\u0005\u0001\u0000\u0000\u0001\u0208\u0002\u0208" +
"\u0003\u0208\u0004\u0002\u00052";
return newMessageInfo(DEFAULT_INSTANCE, info, objects);
}
// fall through
case GET_DEFAULT_INSTANCE: {
return DEFAULT_INSTANCE;
}
case GET_PARSER: {
if (PARSER == null) { synchronized (Model.class) {
if (PARSER == null) {
PARSER = new DefaultInstanceBasedParser(DEFAULT_INSTANCE);
com.google.protobuf.Parser<ReplyModel> parser = PARSER;
if (parser == null) {
synchronized (ReplyModel.class) {
parser = PARSER;
if (parser == null) {
parser =
new DefaultInstanceBasedParser<ReplyModel>(
DEFAULT_INSTANCE);
PARSER = parser;
}
}
}
return PARSER;
}
return parser;
}
case GET_MEMOIZED_IS_INITIALIZED: {
return (byte) 1;
}
case SET_MEMOIZED_IS_INITIALIZED: {
return null;
}
}
throw new UnsupportedOperationException();
}
// @@protoc_insertion_point(class_scope:com.farsunset.cim.sdk.android.model.proto.Model)
private static final Model DEFAULT_INSTANCE;
// @@protoc_insertion_point(class_scope:com.farsunset.cim.sdk.android.model.proto.ReplyModel)
private static final ReplyModel DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new Model();
DEFAULT_INSTANCE.makeImmutable();
ReplyModel defaultInstance = new ReplyModel();
// New instances are implicitly immutable so no need to make
// immutable.
DEFAULT_INSTANCE = defaultInstance;
com.google.protobuf.GeneratedMessageLite.registerDefaultInstance(
ReplyModel.class, defaultInstance);
}
public static Model getDefaultInstance() {
public static ReplyModel getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static volatile com.google.protobuf.Parser<Model> PARSER;
private static volatile com.google.protobuf.Parser<ReplyModel> PARSER;
public static com.google.protobuf.Parser<Model> parser() {
public static com.google.protobuf.Parser<ReplyModel> parser() {
return DEFAULT_INSTANCE.getParserForType();
}
}

View File

@ -8,22 +8,25 @@ public final class SentBodyProto {
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public interface ModelOrBuilder extends
// @@protoc_insertion_point(interface_extends:com.farsunset.cim.sdk.android.model.proto.Model)
public interface SentModelOrBuilder extends
// @@protoc_insertion_point(interface_extends:com.farsunset.cim.sdk.android.model.proto.SentModel)
com.google.protobuf.MessageLiteOrBuilder {
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The key.
*/
String getKey();
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The bytes for key.
*/
com.google.protobuf.ByteString
getKeyBytes();
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
* @return The timestamp.
*/
long getTimestamp();
@ -35,7 +38,7 @@ public final class SentBodyProto {
* <code>map&lt;string, string&gt; data = 3;</code>
*/
boolean containsData(
String key);
String key);
/**
* Use {@link #getDataMap()} instead.
*/
@ -51,91 +54,96 @@ public final class SentBodyProto {
* <code>map&lt;string, string&gt; data = 3;</code>
*/
String getDataOrDefault(
String key,
String defaultValue);
/* nullable */
String getDataOrDefault(
String key,
/* nullable */
String defaultValue);
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
String getDataOrThrow(
String key);
String key);
}
/**
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.Model}
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.SentModel}
*/
public static final class Model extends
public static final class SentModel extends
com.google.protobuf.GeneratedMessageLite<
Model, Model.Builder> implements
// @@protoc_insertion_point(message_implements:com.farsunset.cim.sdk.android.model.proto.Model)
ModelOrBuilder {
private Model() {
SentModel, SentModel.Builder> implements
// @@protoc_insertion_point(message_implements:com.farsunset.cim.sdk.android.model.proto.SentModel)
SentModelOrBuilder {
private SentModel() {
key_ = "";
}
private int bitField0_;
public static final int KEY_FIELD_NUMBER = 1;
private String key_;
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The key.
*/
@Override
public String getKey() {
return key_;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The bytes for key.
*/
@Override
public com.google.protobuf.ByteString
getKeyBytes() {
return com.google.protobuf.ByteString.copyFromUtf8(key_);
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The key to set.
*/
private void setKey(
String value) {
if (value == null) {
throw new NullPointerException();
}
Class<?> valueClass = value.getClass();
key_ = value;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
*/
private void clearKey() {
key_ = getDefaultInstance().getKey();
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The bytes for key to set.
*/
private void setKeyBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
checkByteStringIsUtf8(value);
key_ = value.toStringUtf8();
}
public static final int TIMESTAMP_FIELD_NUMBER = 2;
private long timestamp_;
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
* @return The timestamp.
*/
@Override
public long getTimestamp() {
return timestamp_;
}
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
* @param value The timestamp to set.
*/
private void setTimestamp(long value) {
timestamp_ = value;
}
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
*/
private void clearTimestamp() {
@ -167,6 +175,7 @@ public final class SentBodyProto {
}
return data_;
}
@Override
public int getDataCount() {
return internalGetData().size();
@ -174,15 +183,17 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public boolean containsData(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
return internalGetData().containsKey(key);
}
/**
* Use {@link #getDataMap()} instead.
*/
@Override
@Deprecated
public java.util.Map<String, String> getData() {
return getDataMap();
@ -190,6 +201,7 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public java.util.Map<String, String> getDataMap() {
return java.util.Collections.unmodifiableMap(
@ -198,11 +210,12 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public String getDataOrDefault(
String key,
String defaultValue) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
internalGetData();
return map.containsKey(key) ? map.get(key) : defaultValue;
@ -210,10 +223,11 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public String getDataOrThrow(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
internalGetData();
if (!map.containsKey(key)) {
@ -229,97 +243,73 @@ public final class SentBodyProto {
return internalGetMutableData();
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (!key_.isEmpty()) {
output.writeString(1, getKey());
}
if (timestamp_ != 0L) {
output.writeInt64(2, timestamp_);
}
for (java.util.Map.Entry<String, String> entry
: internalGetData().entrySet()) {
DataDefaultEntryHolder.defaultEntry.serializeTo(
output, 3, entry.getKey(), entry.getValue());
}
public static SentModel parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data);
}
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
if (!key_.isEmpty()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(1, getKey());
}
if (timestamp_ != 0L) {
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(2, timestamp_);
}
for (java.util.Map.Entry<String, String> entry
: internalGetData().entrySet()) {
size += DataDefaultEntryHolder.defaultEntry.computeMessageSize(
3, entry.getKey(), entry.getValue());
}
memoizedSerializedSize = size;
return size;
public static SentModel parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data, extensionRegistry);
}
public static Model parseFrom(
public static SentModel parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data);
}
public static Model parseFrom(
public static SentModel parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data, extensionRegistry);
}
public static Model parseFrom(byte[] data)
public static SentModel parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data);
}
public static Model parseFrom(
public static SentModel parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, data, extensionRegistry);
}
public static Model parseFrom(java.io.InputStream input)
public static SentModel parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, input);
}
public static Model parseFrom(
public static SentModel parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, input, extensionRegistry);
}
public static Model parseDelimitedFrom(java.io.InputStream input)
public static SentModel parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return parseDelimitedFrom(DEFAULT_INSTANCE, input);
}
public static Model parseDelimitedFrom(
public static SentModel parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);
}
public static Model parseFrom(
public static SentModel parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageLite.parseFrom(
DEFAULT_INSTANCE, input);
}
public static Model parseFrom(
public static SentModel parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
@ -328,41 +318,47 @@ public final class SentBodyProto {
}
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
return (Builder) DEFAULT_INSTANCE.createBuilder();
}
public static Builder newBuilder(Model prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
public static Builder newBuilder(SentModel prototype) {
return (Builder) DEFAULT_INSTANCE.createBuilder(prototype);
}
/**
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.Model}
* Protobuf type {@code com.farsunset.cim.sdk.android.model.proto.SentModel}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageLite.Builder<
Model, Builder> implements
// @@protoc_insertion_point(builder_implements:com.farsunset.cim.sdk.android.model.proto.Model)
ModelOrBuilder {
// Construct using com.farsunset.cim.sdk.android.model.proto.SentBodyProto.Model.newBuilder()
SentModel, Builder> implements
// @@protoc_insertion_point(builder_implements:com.farsunset.cim.sdk.android.model.proto.SentModel)
SentModelOrBuilder {
// Construct using com.farsunset.cim.sdk.android.model.proto.SentBodyProto.SentModel.newBuilder()
private Builder() {
super(DEFAULT_INSTANCE);
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The key.
*/
@Override
public String getKey() {
return instance.getKey();
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return The bytes for key.
*/
@Override
public com.google.protobuf.ByteString
getKeyBytes() {
return instance.getKeyBytes();
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The key to set.
* @return This builder for chaining.
*/
public Builder setKey(
String value) {
@ -371,7 +367,8 @@ public final class SentBodyProto {
return this;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @return This builder for chaining.
*/
public Builder clearKey() {
copyOnWrite();
@ -379,7 +376,9 @@ public final class SentBodyProto {
return this;
}
/**
* <code>optional string key = 1;</code>
* <code>string key = 1;</code>
* @param value The bytes for key to set.
* @return This builder for chaining.
*/
public Builder setKeyBytes(
com.google.protobuf.ByteString value) {
@ -389,13 +388,17 @@ public final class SentBodyProto {
}
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
* @return The timestamp.
*/
@Override
public long getTimestamp() {
return instance.getTimestamp();
}
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
* @param value The timestamp to set.
* @return This builder for chaining.
*/
public Builder setTimestamp(long value) {
copyOnWrite();
@ -403,7 +406,8 @@ public final class SentBodyProto {
return this;
}
/**
* <code>optional int64 timestamp = 2;</code>
* <code>int64 timestamp = 2;</code>
* @return This builder for chaining.
*/
public Builder clearTimestamp() {
copyOnWrite();
@ -411,6 +415,7 @@ public final class SentBodyProto {
return this;
}
@Override
public int getDataCount() {
return instance.getDataMap().size();
@ -418,10 +423,11 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public boolean containsData(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
return instance.getDataMap().containsKey(key);
}
@ -436,7 +442,7 @@ public final class SentBodyProto {
public Builder removeData(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
copyOnWrite();
instance.getMutableDataMap().remove(key);
return this;
@ -444,6 +450,7 @@ public final class SentBodyProto {
/**
* Use {@link #getDataMap()} instead.
*/
@Override
@Deprecated
public java.util.Map<String, String> getData() {
return getDataMap();
@ -451,6 +458,7 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public java.util.Map<String, String> getDataMap() {
return java.util.Collections.unmodifiableMap(
instance.getDataMap());
@ -458,11 +466,12 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public String getDataOrDefault(
String key,
String defaultValue) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
instance.getDataMap();
return map.containsKey(key) ? map.get(key) : defaultValue;
@ -470,10 +479,11 @@ public final class SentBodyProto {
/**
* <code>map&lt;string, string&gt; data = 3;</code>
*/
@Override
public String getDataOrThrow(
String key) {
if (key == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
java.util.Map<String, String> map =
instance.getDataMap();
if (!map.containsKey(key)) {
@ -487,8 +497,8 @@ public final class SentBodyProto {
public Builder putData(
String key,
String value) {
if (key == null) { throw new NullPointerException(); }
if (value == null) { throw new NullPointerException(); }
Class<?> keyClass = key.getClass();
Class<?> valueClass = value.getClass();
copyOnWrite();
instance.getMutableDataMap().put(key, value);
return this;
@ -503,118 +513,80 @@ public final class SentBodyProto {
return this;
}
// @@protoc_insertion_point(builder_scope:com.farsunset.cim.sdk.android.model.proto.Model)
// @@protoc_insertion_point(builder_scope:com.farsunset.cim.sdk.android.model.proto.SentModel)
}
@Override
@SuppressWarnings({"unchecked", "fallthrough"})
protected final Object dynamicMethod(
MethodToInvoke method,
Object arg0, Object arg1) {
switch (method) {
case NEW_MUTABLE_INSTANCE: {
return new Model();
}
case IS_INITIALIZED: {
return DEFAULT_INSTANCE;
}
case MAKE_IMMUTABLE: {
data_.makeImmutable();
return null;
return new SentModel();
}
case NEW_BUILDER: {
return new Builder();
}
case VISIT: {
Visitor visitor = (Visitor) arg0;
Model other = (Model) arg1;
key_ = visitor.visitString(!key_.isEmpty(), key_,
!other.key_.isEmpty(), other.key_);
timestamp_ = visitor.visitLong(timestamp_ != 0L, timestamp_,
other.timestamp_ != 0L, other.timestamp_);
data_ = visitor.visitMap(
data_, other.internalGetData());
if (visitor == MergeFromVisitor
.INSTANCE) {
bitField0_ |= other.bitField0_;
}
return this;
}
case MERGE_FROM_STREAM: {
com.google.protobuf.CodedInputStream input =
(com.google.protobuf.CodedInputStream) arg0;
com.google.protobuf.ExtensionRegistryLite extensionRegistry =
(com.google.protobuf.ExtensionRegistryLite) arg1;
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
default: {
if (!input.skipField(tag)) {
done = true;
}
break;
}
case 10: {
String s = input.readStringRequireUtf8();
key_ = s;
break;
}
case 16: {
timestamp_ = input.readInt64();
break;
}
case 26: {
if (!data_.isMutable()) {
data_ = data_.mutableCopy();
}
DataDefaultEntryHolder.defaultEntry.parseInto(data_, input, extensionRegistry); break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw new RuntimeException(e.setUnfinishedMessage(this));
} catch (java.io.IOException e) {
throw new RuntimeException(
new com.google.protobuf.InvalidProtocolBufferException(
e.getMessage()).setUnfinishedMessage(this));
} finally {
}
case BUILD_MESSAGE_INFO: {
Object[] objects = new Object[] {
"key_",
"timestamp_",
"data_",
DataDefaultEntryHolder.defaultEntry,
};
String info =
"\u0000\u0003\u0000\u0000\u0001\u0003\u0003\u0001\u0000\u0000\u0001\u0208\u0002\u0002" +
"\u00032";
return newMessageInfo(DEFAULT_INSTANCE, info, objects);
}
// fall through
case GET_DEFAULT_INSTANCE: {
return DEFAULT_INSTANCE;
}
case GET_PARSER: {
if (PARSER == null) { synchronized (Model.class) {
if (PARSER == null) {
PARSER = new DefaultInstanceBasedParser(DEFAULT_INSTANCE);
com.google.protobuf.Parser<SentModel> parser = PARSER;
if (parser == null) {
synchronized (SentModel.class) {
parser = PARSER;
if (parser == null) {
parser =
new DefaultInstanceBasedParser<SentModel>(
DEFAULT_INSTANCE);
PARSER = parser;
}
}
}
return PARSER;
}
return parser;
}
case GET_MEMOIZED_IS_INITIALIZED: {
return (byte) 1;
}
case SET_MEMOIZED_IS_INITIALIZED: {
return null;
}
}
throw new UnsupportedOperationException();
}
// @@protoc_insertion_point(class_scope:com.farsunset.cim.sdk.android.model.proto.Model)
private static final Model DEFAULT_INSTANCE;
// @@protoc_insertion_point(class_scope:com.farsunset.cim.sdk.android.model.proto.SentModel)
private static final SentModel DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new Model();
DEFAULT_INSTANCE.makeImmutable();
SentModel defaultInstance = new SentModel();
// New instances are implicitly immutable so no need to make
// immutable.
DEFAULT_INSTANCE = defaultInstance;
com.google.protobuf.GeneratedMessageLite.registerDefaultInstance(
SentModel.class, defaultInstance);
}
public static Model getDefaultInstance() {
public static SentModel getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static volatile com.google.protobuf.Parser<Model> PARSER;
private static volatile com.google.protobuf.Parser<SentModel> PARSER;
public static com.google.protobuf.Parser<Model> parser() {
public static com.google.protobuf.Parser<SentModel> parser() {
return DEFAULT_INSTANCE.getParserForType();
}
}

View File

@ -1,7 +1,7 @@
syntax = "proto3";
package com.farsunset.cim.sdk.android.model.proto;
option java_outer_classname = "MessageProto";
message Model {
message MessageModel {
int64 id = 1;
string action = 2;
string content = 3;

View File

@ -2,7 +2,7 @@ syntax = "proto3";
package com.farsunset.cim.sdk.android.model.proto;
option java_outer_classname = "ReplyBodyProto";
message Model {
message ReplyModel {
string key = 1;
string code = 2;
string message = 3;

View File

@ -2,7 +2,7 @@ syntax = "proto3";
package com.farsunset.cim.sdk.android.model.proto;
option java_outer_classname = "SentBodyProto";
message Model {
message SentModel {
string key = 1;
int64 timestamp = 2;
map<string, string> data = 3;

Binary file not shown.

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31313.79
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CIM_Standard", "CIM_Standard\CIM_Standard.csproj", "{7CF35A93-CD9E-4A34-8B79-6835E4523BF7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CIM_SDK_Tests", "CIM_SDK_Tests\CIM_SDK_Tests.csproj", "{372F9F86-C3E8-49B7-A434-09E95BF42F84}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7CF35A93-CD9E-4A34-8B79-6835E4523BF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CF35A93-CD9E-4A34-8B79-6835E4523BF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CF35A93-CD9E-4A34-8B79-6835E4523BF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CF35A93-CD9E-4A34-8B79-6835E4523BF7}.Release|Any CPU.Build.0 = Release|Any CPU
{372F9F86-C3E8-49B7-A434-09E95BF42F84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{372F9F86-C3E8-49B7-A434-09E95BF42F84}.Debug|Any CPU.Build.0 = Debug|Any CPU
{372F9F86-C3E8-49B7-A434-09E95BF42F84}.Release|Any CPU.ActiveCfg = Release|Any CPU
{372F9F86-C3E8-49B7-A434-09E95BF42F84}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {48F81742-18F6-4EE4-9390-12A19B39B0D7}
EndGlobalSection
EndGlobal

Some files were not shown because too many files have changed in this diff Show More