Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ad0437730 | ||
|
|
6245fe37fc | ||
|
|
ca50872913 | ||
|
|
3c11c368a3 | ||
|
|
145709fd76 | ||
|
|
758c5de2c7 | ||
|
|
c159ff90e3 | ||
|
|
083b07fdba | ||
|
|
c6a8462ece | ||
|
|
afee0466e7 | ||
|
|
62b36cd2b4 | ||
|
|
99c5210935 | ||
|
|
75cb7f8b98 | ||
|
|
c89259e892 | ||
|
|
d40835aa18 | ||
|
|
b93c76c6c7 | ||
|
|
c29370ac61 | ||
|
|
68abeed907 | ||
|
|
11b7851b9f | ||
|
|
329791e70e | ||
|
|
b7b262be00 | ||
|
|
6a806aa10b | ||
|
|
6542b8ba55 | ||
|
|
c3bc62f1e1 | ||
|
|
8b649200d2 | ||
|
|
5f95b18e77 | ||
|
|
4d45aedc73 | ||
|
|
a038bedb12 | ||
|
|
43892dbe41 | ||
|
|
ad33abc424 | ||
|
|
290a3cea0e | ||
|
|
ca3bbb6435 | ||
|
|
704e6e0ec2 | ||
|
|
23871487e4 | ||
|
|
6e1ba9440e | ||
|
|
c284272b06 | ||
|
|
6746a54659 | ||
|
|
93be667e17 | ||
|
|
f11da6225d | ||
|
|
e28a4c6cbf | ||
|
|
fa8a2bef32 | ||
|
|
1c9d238734 | ||
|
|
2f7f4e6456 | ||
|
|
6e83ec85c7 | ||
|
|
cc561b846e | ||
|
|
4628b3b0b6 | ||
|
|
9c69fbc7d4 | ||
|
|
9047020d69 | ||
|
|
1c18d862a1 | ||
|
|
b0ddca985a | ||
|
|
996e06c451 | ||
|
|
612747203a | ||
|
|
f7853ae299 | ||
|
|
7443db3078 | ||
|
|
ad5f6cb228 | ||
|
|
1486b19ce1 | ||
|
|
3e1095f745 | ||
|
|
17039bd3c1 | ||
|
|
b5d8feab62 | ||
|
|
95b08ff7a3 | ||
|
|
ab8ae9d0c9 | ||
|
|
b4d163e144 | ||
|
|
3ccfd9a29b | ||
|
|
90504d1305 | ||
|
|
88199189a2 | ||
|
|
0b6612eacc | ||
|
|
d706f545d2 | ||
|
|
ae8d63b162 | ||
|
|
77e742e812 | ||
|
|
b2ee8b8d94 | ||
|
|
7080d85605 | ||
|
|
1275b2109f | ||
|
|
b2eab28cb9 | ||
|
|
67234ceaa6 | ||
|
|
45f9e20e97 | ||
|
|
6b7edc713a | ||
|
|
1ef8f94d67 | ||
|
|
9b0b644cd1 | ||
|
|
b233c49d73 | ||
|
|
b8d8d2f8ed | ||
|
|
731020ba0f | ||
|
|
4c00955639 | ||
|
|
cbc150905f | ||
|
|
a71b8cef73 | ||
|
|
66c67fa8d1 | ||
|
|
3ca7c70faa | ||
|
|
d4c6b1f616 | ||
|
|
ae3eb9c2df | ||
|
|
771a4d751f | ||
|
|
2bed06cf43 | ||
|
|
50f0330884 | ||
|
|
acd21faa9c | ||
|
|
6e570c74ae | ||
|
|
893b58cef4 | ||
|
|
bd2b037edb | ||
|
|
6acb1c968a | ||
|
|
6048748300 | ||
|
|
9be49c3d41 | ||
|
|
d9eccd39de | ||
|
|
ffaffc8fc1 | ||
|
|
5e1f4fe6c9 | ||
|
|
b5d884f9f6 | ||
|
|
c0840f3a73 | ||
|
|
34bd59f195 | ||
|
|
8e1d56b2ca | ||
|
|
a4eb64edd5 | ||
|
|
b141990661 | ||
|
|
0f9df0659f | ||
|
|
a2d4bf7d43 | ||
|
|
898c4f2419 | ||
|
|
e1a8a040df | ||
|
|
adb4f082f1 | ||
|
|
2724c79a79 | ||
|
|
ba01c90171 | ||
|
|
b8967ccaff | ||
|
|
0e6e23da13 | ||
|
|
88652af565 | ||
|
|
af58bf91a4 | ||
|
|
9d86539d01 | ||
|
|
2559fa7e48 | ||
|
|
20f71f5a21 | ||
|
|
326f76afd8 | ||
|
|
9f36d47ca8 | ||
|
|
57cdd57a30 |
@@ -11,10 +11,13 @@
|
||||
你认为正确的表现应该是什么样的。
|
||||
|
||||
#### 补充条件
|
||||
是否是毕现的,还是偶现的?是否只有在特殊的网络/设备/平台上出现,还是所有的都出现。还有您用的版本是什么时候的,是不是最新版
|
||||
是否是必现的,还是偶现的?是否只有在特殊的网络/设备/平台上出现,还是所有的都出现。还有您用的版本是什么时候的,是不是最新版
|
||||
|
||||
#### demo对比结果
|
||||
请用demo对比测试,demo上是什么状态。
|
||||
|
||||
#### 检索已有问题
|
||||
除了可以检索已有issue外,还可以去野火论坛查找已有问题,论坛地址为 https://bbs.wildfirechat.cn
|
||||
|
||||
#### star 我们
|
||||
给我们点个star,可以及时接收到我们回复信息,另外也是对我们支持人员辛苦工作的认可,激励我们更好更快地为大家服务。
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
## 功能特性
|
||||
* 极致地硬件利用率,IM服务最低128M内存即可运行,上不封顶。
|
||||
* 协议先进,采用MQTT+Protobuf组合,流量和性能极致优化。
|
||||
* 性能强大,专业版IM服务支持百万在线和集群部署。
|
||||
* 性能强大,专业版IM服务支持百万在线和集群部署,业内顶尖性能水平,详情参考野火性能报告。
|
||||
* 部署运维简单,依赖服务少,稍加配置一键启动。
|
||||
* 安全加密。网络连接AES加密。客户端数据库SqlCipher加密。安全无小事。
|
||||
* 全平台客户端,四端同时在线(移动端,pc端,web端和小程序端),数据和状态多端完美同步。
|
||||
* 全平台客户端,支持Android、iOS、Web、小程序、UniApp、Flutter、Windows、Mac OS、Linux等所有常见平台。
|
||||
* 四端同时在线(移动端,pc端,web端和小程序端),数据和状态多端完美同步。
|
||||
* 支持国产化。支持国产化操作系统、国产化芯片和国产操作系统。支持国密加密。
|
||||
* 客户端使用微信[mars](https://github.com/tencent/mars)连接库,野火IM可能是最适应中国网络国情的即时通讯服务。
|
||||
* 支持加速点加速,即可用于全球应用,也可用于政企内外双网复杂的网络环境。
|
||||
@@ -15,19 +16,23 @@
|
||||
* 音视频多种解决方案,丰俭由人,可自由选择。
|
||||
* 高级音视频功能强大,支持9人以上的群组视频通话,支持1080P视频,支持会议模式,支持百人以上会议,支持服务器端录制。
|
||||
* 全私有部署,可不依赖任何第三方服务,完全内网部署。
|
||||
* 功能齐全,涵盖所有常见即时通讯功能。另外具有强大的可扩展能力。Demo成熟完善,基本可以做到开箱即用,也可把SDK嵌入其它应用。
|
||||
* 功能齐全,涵盖所有常见即时通讯功能。另外具有强大的可扩展能力。代码开源率高,二次开发简单。
|
||||
* 结构设计合理,客户端分功能库、UI库和应用三层。应用成熟完善,开箱即用,也可把SDK嵌入其它应用。
|
||||
* 拥有应用开放平台,可以开发和创建自建应用,扩展您的工作台。
|
||||
* API丰富,方便与其它服务系统的对接。
|
||||
* 拥有机器人和频道功能。
|
||||
* 代码开源率高,二次开发简单。可以先试用3到6个月,二开搞定后再购买。
|
||||
* 拥有机器人和公众号功能,免费的频道(公众号)管理后台。
|
||||
* 超级群组功能,可以支持万人大群。
|
||||
* 社区版IM服务和移动端免费商用,可以免费构建出完备的移动互联网应用。
|
||||
* 收费项目非常便宜,野火独有的试用模式,可以先部署到客户环境试用6个月,试用满意后再购买,避免上当受骗。
|
||||
* 技术支持专业和高效,核心研发人员及时处理issue和论坛回复。
|
||||
|
||||
## 野火开源项目
|
||||
主要包括以下项目:
|
||||
|
||||
| [GitHub仓库地址](https://github.com/wildfirechat) | [码云仓库地址](https://gitee.com/wfchat) | 说明
|
||||
| [GitHub仓库](https://github.com/wildfirechat) | [码云仓库](https://gitee.com/wfchat) | 说明
|
||||
| ------------------------------------------------------------ | ----------------------------------------------------- | --------------------------------------------------------------------------
|
||||
| [im-server](https://github.com/wildfirechat/im-server) | [im-server](https://gitee.com/wfchat/im-server) | 野火社区版IM服务,野火IM的核心服务,处理所有IM相关业务。 |
|
||||
| [app_server](https://github.com/wildfirechat/app_server) | [app_server](https://gitee.com/wfchat/app_server) | Demo应用服务,模拟客户的应用服登陆处理逻辑及部分二次开发示例。 |
|
||||
| [app-server](https://github.com/wildfirechat/app-server) | [app-server](https://gitee.com/wfchat/app-server) | Demo应用服务,模拟客户的应用服登陆处理逻辑及部分二次开发示例。 |
|
||||
| [robot_server](https://github.com/wildfirechat/robot_server) | [robot_server](https://gitee.com/wfchat/robot_server) | 机器人服务,演示野火机器人对接其它系统的方法。 |
|
||||
| [push_server](https://github.com/wildfirechat/push_server) | [push_server](https://gitee.com/wfchat/push_server) | 推送服务器,可以对接所有的系统厂商推送服务或者第三方推送服务。 |
|
||||
| [wf-minio](https://github.com/wildfirechat/WF-minio) | [wf-minio](https://gitee.com/wfchat/WF-minio) | 私有对象存储服务,用来支持野火IM专业版的文件存储。 |
|
||||
@@ -35,19 +40,23 @@
|
||||
| [open-platform](https://github.com/wildfirechat/open-platform) | [open-platform](https://gitee.com/wfchat/open-platform) | 野火开放平台服务。 |
|
||||
| [daily-report](https://github.com/wildfirechat/daily-report) | [daily-report](https://github.com/wildfirechat/daily-report) | 野火开放平台日报 demo服务。 |
|
||||
| [channel-platform](https://github.com/wildfirechat/channel-platform) | [channel-platform](https://gitee.com/wfchat/channel-platform) | 野火频道(公众号)平台服务。 |
|
||||
| [organization-platform](https://github.com/wildfirechat/organization-platform) | [organization-platform](https://gitee.com/wfchat/organization-platform) | 野火组织通讯录服务。 |
|
||||
| [android-chat](https://github.com/wildfirechat/android-chat) | [android-chat](https://gitee.com/wfchat/android-chat) | 野火IM Android SDK源码和App源码。 |
|
||||
| [ios-chat](https://github.com/wildfirechat/ios-chat) | [ios-chat](https://gitee.com/wfchat/ios-chat) | 野火IM iOS SDK源码和App源码。|
|
||||
| [pc-chat](https://github.com/wildfirechat/vue-pc-chat) | [pc-chat](https://gitee.com/wfchat/vue-pc-chat) | 基于[Electron](https://electronjs.org/)的PC 端,支持Windows、Mac、Linux(包括国产化linux系统和CPU)。 |
|
||||
| [web-chat](https://github.com/wildfirechat/vue-chat) | [web-chat](https://gitee.com/wfchat/vue-chat) | 野火IM Web 端, [体验地址](https://web.wildfirechat.cn)。 |
|
||||
| [wx-chat](https://github.com/wildfirechat/wx-chat) | [wx-chat](https://gitee.com/wfchat/wx-chat) | 小程序平台的Demo(支持微信、百度、阿里、字节、QQ 等小程序平台)。 |
|
||||
| [uni-chat](https://github.com/wildfirechat/uni-chat) | [uni-chat](https://gitee.com/wfchat/uni-chat) | UniApp平台移动端应用(使用原生插件)。 |
|
||||
| [uni-wfc-client](https://github.com/wildfirechat/uni-wfc-client) | [uni-wfc-client](https://gitee.com/wfchat/uni-wfc-client) | UniApp平台原生插件。 |
|
||||
| [flutter_imclient](https://github.com/wildfirechat/flutter_imclient) | [flutter_imclient](https://gitee.com/wfchat/flutter_imclient) | Flutter平台原生插件。 |
|
||||
| [uni-wfc-client](https://github.com/wildfirechat/uni-wfc-client) | [uni-wfc-client](https://gitee.com/wfchat/uni-wfc-client) | UniApp平台原生插件。已[商店](https://ext.dcloud.net.cn/plugin?id=7895)上架 |
|
||||
| [wfc_flutter_plugins](https://github.com/wildfirechat/wfc_flutter_plugins) | [flutter_imclient](https://gitee.com/wfchat/wfc_flutter_plugins) | Flutter平台原生插件,支持IM和音视频通话。 |
|
||||
| [docs](https://github.com/wildfirechat/docs) | [docs](https://gitee.com/wfchat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明,[在线查看](https://docs.wildfirechat.cn/)。 |
|
||||
|
||||
## 野火开发文档
|
||||
[在线文档](https://docs.wildfirechat.cn/)
|
||||
|
||||
## 野火性能测试报告及测试方法
|
||||
[Github](https://github.com/wildfirechat/Performance_Test), [码云](https://gitee.com/wfchat/Performance_Test)。
|
||||
|
||||
## 野火Demo
|
||||
请使用微信扫码下载安装体验野火IM移动客户端
|
||||
|
||||
@@ -62,73 +71,161 @@ PC客户端点[这里](https://github.com/wildfirechat/vue-pc-chat/releases)下
|
||||

|
||||
|
||||
## 快速使用
|
||||
野火提供免费的社区版IM服务和移动端,包括完整的移动端即时通讯和实时音视频功能,可以无条件商用。您可以直接从开源项目里下载到完整的后端和移动端产品,包括社区版IM服务、应用服务、开放平台服务、频道(公众号)服务、机器人服务、推送服务以及Android和iOS端源码。可以按照[快速开始](https://docs.wildfirechat.cn/quick_start/)来部署应用服务和IM服务,然后打包移动端,以最小化运行。之后可以详细阅读文档部署其他支撑服务。
|
||||
可以按照[快速开始](https://docs.wildfirechat.cn/quick_start/)来部署应用服务和IM服务,然后打包移动端,就可以完成聊天和通话功能。
|
||||
|
||||
## 应用截图
|
||||

|
||||
之后再部署开放平台服务、频道(公众号)服务、机器人服务、推送服务、Turn服务(音视频服务)来实现完整的应用功能,详情可以详细阅读文档。
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-message-view.png" width = 50% height = 50% />
|
||||
## 联系我们
|
||||
商务合作请微信联系:
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-contact-view.png" width = 50% height = 50% />
|
||||
* 微信1:wildfirechat
|
||||
* 微信2:wfchat
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-discover-view.png" width = 50% height = 50% />
|
||||
## 问题交流
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-settings-view.png" width = 50% height = 50% />
|
||||
1. 如果大家发现bug,请在GitHub或码云提issue;如果有需求也请给我们提issue。
|
||||
2. 其他问题,请到[野火IM论坛](http://bbs.wildfirechat.cn/)进行交流学习
|
||||
3. 关注我们的公众号。我们有新版本发布或者有重大更新会通过公众号通知大家,另外我们也会不定期的发布一些关于野火IM的技术介绍。
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-messagelist-view.png" width = 50% height = 50% />
|
||||
<img src="http://static.wildfirechat.cn/wx_wfc_qrcode.jpg" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-chat-setting-view.png" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-takephoto-view.png" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-record-voice-view.png" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-location-view.png" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-voip-view.png" width = 50% height = 50% />
|
||||
我们有核心研发工程师轮流值班处理issue和论坛,会及时处理的,疑难Bug的修改和新需求的开发我们也会尽快解决。
|
||||
|
||||
|
||||
## 编译
|
||||
在安装JDK1.8以上及maven的前提下,在命令行中执行```mvn clean package```,生成的目标文件在```./distribution/target/distribution-xxxx-bundle-tar.tar.gz```
|
||||
> 由于使用了一个git的maven插件,如果本地没有git信息就会编译出错,请使用```git clone```的方法下载代码,或者下载压缩包解压后在根目录创建```.git```的空目录。建议用```git clone```的方式下载代码。
|
||||
```
|
||||
mvn clean package
|
||||
```
|
||||
生成的目标文件在```./distribution/target/distribution-xxxx-bundle-tar.tar.gz```
|
||||
|
||||
## 配置
|
||||
解压```distribution-xxxx-bundle-tar.tar.gz```,修改解压出来的```config```目录下的```wildfirechat.conf```。修改如下部分:
|
||||
1. 修改```server.ip```为您的服务器的公网IP,或者域名。如果用域名需要做好域名解析。
|
||||
2. 可以阅读配置文件注释和文档,对其它配置项进行调整。
|
||||
解压```distribution-xxxx-bundle-tar.tar.gz```,修改解压出来的```config```目录下的```wildfirechat.conf```,可以阅读配置文件注释和文档,对其它配置项进行调整。
|
||||
|
||||
## 运行
|
||||
在程序目录运行如下命令:
|
||||
在解压```distribution-xxxx-bundle-tar.tar.gz```后的目录下运行如下命令:
|
||||
```
|
||||
./bin/wildfirechat.sh
|
||||
```
|
||||
|
||||
## 验证
|
||||
1. 在浏览器中输入地址 ```http://${ip}/api/version```可以看到返回一个json文件。
|
||||
2. 部署[应用服务](应用服务),配置和编译[Android客户端](https://github.com/wildfirechat/android-chat)和[iOS客户端](https://github.com/wildfirechat/ios-chat)进行验证。详情可参考[快速开始](https://docs.wildfirechat.cn/quick_start/)。
|
||||
2. 部署[应用服务](https://github.com/wildfirechat/app-server),配置和编译[Android客户端](https://github.com/wildfirechat/android-chat)和[iOS客户端](https://github.com/wildfirechat/ios-chat)进行验证。详情可参考[快速开始](https://docs.wildfirechat.cn/quick_start/)。
|
||||
|
||||
## 打包RPM格式
|
||||
打包会生成Java包和deb安装包,如果需要rpm安装包,请在```distribution/pom.xml```中取消注释生成rpm包的plugin。另外还需要本地安装有rpm,在linux或者mac系统中很容易安装,在windows系统需要安装cygwin并安装rpm,具体信息请百度查询。
|
||||
|
||||
修改之后运行编译命令```mvn clean package```,rpm包生成在```distribution/target```目录下。
|
||||
|
||||
## 升级说明
|
||||
1. 从0.42 版本增加了群成员数限制,默认为2000。如果您从之前的版本升级到这个版本或以后,需要注意到群成员数的限制。升级之后超出限制的群不受影响,但不能继续加人,如果您想修改默认值,可以在升级版本之后,修改t_setting表,把默认的大小改为您期望的人数。另外修改t_group表,把已经存在的群组max_member_count改成您期望的,然后重启。
|
||||
2. 0.46和0.47版本升级到0.48及以后版本时,可能会提示flyway migrate 38错误,请执行 [修复脚本](https://github.com/wildfirechat/server/blob/wildfirechat/flyway_repaire_migrate_38.sql) 进行修复。0.46和0.47版本之外的版本不会出现此问题。
|
||||
3. 从0.54之前版本升级到0.54及以后版本时,会提示flyway migrate错误。因为0.54版本删除了sql脚本中默认敏感词的内容,flyway checksum失败。请执行```update flyway_schema_history set checksum = 0 where script = 'V17__add_default_sensitive_word.sql';```来修复。
|
||||
4. 从0.59之前的版本升级到之后的版本执行数据库升级时间比较长,请耐心等待提示运行成功,避免中途中断。
|
||||
2. 0.50版本添加了是否允许客户端发送群操作通知的配置。如果您在客户端自定义群通知,需要在服务器端配置允许,没有使用自定义群操作通知的不受影响。***
|
||||
3. 0.46和0.47版本升级到0.48及以后版本时,可能会提示flyway migrate 38错误,请执行 [修复脚本](https://github.com/wildfirechat/server/blob/wildfirechat/flyway_repaire_migrate_38.sql) 进行修复。0.46和0.47版本之外的版本不会出现此问题。
|
||||
4. 从0.54之前版本升级到0.54及以后版本时,会提示flyway migrate错误。因为0.54版本删除了sql脚本中默认敏感词的内容,flyway checksum失败。请执行```update flyway_schema_history set checksum = 0 where script = 'V17__add_default_sensitive_word.sql';```来修复。
|
||||
5. 从0.59之前的版本升级到之后的版本执行数据库升级时间比较长,请耐心等待提示运行成功,避免中途中断。
|
||||
6. 0.62/0.63 版本有严重的问题,请使用0.64及以后版本,或者0.61版。
|
||||
7. 从0.68 版本起添加了pc在线是否默认手机接收推送的开关,默认为开,与以前版本作用相反,请注意兼容(可以关掉与之前保持一致或者升级客户端)
|
||||
8. 从0.78 版本起把MySQL数据库中关键字都改为大小写敏感,另外生成id的方法也做了改变,只生成小写的id,避免出现id重复的问题,建议所有客户都升级
|
||||
9. 从0.79 版本起把log4j升级到log4j2,因为log4j已经不再维护而且还有已知的漏洞,建议所有客户都升级,升级时注意更新log4j2的配置文件
|
||||
10. 0.97版本更改了启动脚本```wildfirechat.sh```,如果是升级服务,请注意更新启动脚本。
|
||||
|
||||
## 应用截图
|
||||
登录界面
|
||||
|
||||
## 联系我们
|
||||
<img src="./screenshots/1_login.png" width = 50% height = 50% />
|
||||
|
||||
商务合作请使用如下邮箱和微信联系:
|
||||
会话列表
|
||||
|
||||
邮箱: support@wildfirechat.cn 微信1:wfchat 微信2:wildfirechat
|
||||
<img src="./screenshots/2_conversation_list.png" width = 50% height = 50% />
|
||||
|
||||
## 问题交流
|
||||
好友列表
|
||||
|
||||
1. 如果大家发现bug,请在GitHub提issue;如果有需求也请给我们提issue。
|
||||
2. 其他问题,请到[野火IM论坛](http://bbs.wildfirechat.cn/)进行交流学习
|
||||
3. 关注我们的公众号。我们有新版本发布或者有重大更新会通过公众号通知大家,另外我们也会不定期的发布一些关于野火IM的技术介绍。
|
||||
<img src="./screenshots/3_contacts_list.png" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/wx_wfc_qrcode.jpg" width = 50% height = 50% />
|
||||
工作台
|
||||
|
||||
> 我们有研发工程师轮流值班处理issue和论坛,一般简单问题几个小时就会回复一遍,疑难Bug的修改和新需求的开发我们也会尽快解决。
|
||||
<img src="./screenshots/4_workplatform.png" width = 50% height = 50% />
|
||||
|
||||
发现
|
||||
|
||||
<img src="./screenshots/5_discover.png" width = 50% height = 50% />
|
||||
|
||||
我的页面
|
||||
|
||||
<img src="./screenshots/6_settings.png" width = 50% height = 50% />
|
||||
|
||||
消息聊天
|
||||
|
||||
<img src="./screenshots/7_conversation.png" width = 50% height = 50% />
|
||||
|
||||
动态表情
|
||||
|
||||
<img src="./screenshots/8_conversation_sticker.png" width = 50% height = 50% />
|
||||
|
||||
语音消息
|
||||
|
||||
<img src="./screenshots/9_conversation_voice_msg.png" width = 50% height = 50% />
|
||||
|
||||
位置消息
|
||||
|
||||
<img src="./screenshots/10_conversation_location.png" width = 50% height = 50% />
|
||||
|
||||
拍摄图片或者小视频
|
||||
|
||||
<img src="./screenshots/11_conversation_capture.jpeg" width = 50% height = 50% />
|
||||
|
||||
会话设置
|
||||
|
||||
<img src="./screenshots/13_conversation_settings.png" width = 50% height = 50% />
|
||||
|
||||
朋友圈
|
||||
|
||||
<img src="./screenshots/14_moments.png" width = 50% height = 50% />
|
||||
|
||||
新好友
|
||||
|
||||
<img src="./screenshots/15_new_friends.png" width = 50% height = 50% />
|
||||
|
||||
多人视频通话
|
||||
|
||||
<img src="./screenshots/16_videocall.png" width = 50% height = 50% />
|
||||
|
||||
会议主页
|
||||
|
||||
<img src="./screenshots/17_conference_home.png" width = 50% height = 50% />
|
||||
|
||||
会议详情
|
||||
|
||||
<img src="./screenshots/18_conference_info.png" width = 50% height = 50% />
|
||||
|
||||
会议界面
|
||||
|
||||
<img src="./screenshots/19_conference.png" width = 50% height = 50% />
|
||||
|
||||
PC客户端界面
|
||||
|
||||
<img src="./screenshots/20_pc.png"/>
|
||||
|
||||
移动客户端、PC客户端和Web客户端三端同框
|
||||
|
||||
<img src="./screenshots/21_three_platform.png" />
|
||||
|
||||
小程序客户端
|
||||
|
||||
<img src="./screenshots/22_micro_app.jpeg" width = 50% height = 50% />
|
||||
|
||||
公众号管理后台
|
||||
|
||||
<img src="./screenshots/23_channel.png"/>
|
||||
|
||||
开放平台管理后台
|
||||
|
||||
<img src="./screenshots/24_open_platform.png" />
|
||||
|
||||
IM服务管理后台
|
||||
|
||||
<img src="./screenshots/25_im_admin.png" />
|
||||
|
||||
> 更多详细信息请下载demo进行体验。
|
||||
|
||||
## 特别感谢
|
||||
1. [moquette](https://github.com/moquette-io/moquette) 本项目是基于此项目二次开发而来,处理MQTT相关业务。
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#native2ascii -encoding UTF-8 messages.properties temp_messages.properties
|
||||
Above_Greeting_Message=\u4ee5\u4e0a\u662f\u6253\u62db\u547c\u4fe1\u606f
|
||||
Friend_Can_Start_Chat=\u4f60\u4eec\u5df2\u7ecf\u6210\u4e3a\u597d\u53cb\u4e86\uff0c\u73b0\u5728\u53ef\u4ee5\u5f00\u59cb\u804a\u5929\u4e86
|
||||
@@ -1,2 +0,0 @@
|
||||
Above_Greeting_Message=This's the greeting
|
||||
Friend_Can_Start_Chat=You're already friend, start chat now.
|
||||
@@ -1,2 +0,0 @@
|
||||
Above_Greeting_Message=This's the greeting
|
||||
Friend_Can_Start_Chat=You're already friend, start chat now.
|
||||
@@ -1,2 +0,0 @@
|
||||
Above_Greeting_Message=\u4ee5\u4e0a\u662f\u6253\u62db\u547c\u4fe1\u606f
|
||||
Friend_Can_Start_Chat=\u4f60\u4eec\u5df2\u7ecf\u6210\u4e3a\u597d\u53cb\u4e86\uff0c\u73b0\u5728\u53ef\u4ee5\u5f00\u59cb\u804a\u5929\u4e86
|
||||
@@ -1,2 +0,0 @@
|
||||
Above_Greeting_Message=\u4ee5\u4e0a\u662f\u6253\u62db\u547c\u4fe1\u606f
|
||||
Friend_Can_Start_Chat=\u4f60\u4eec\u5df2\u7ecf\u6210\u4e3a\u597d\u53cb\u4e86\uff0c\u73b0\u5728\u53ef\u4ee5\u5f00\u59cb\u804a\u5929\u4e86
|
||||
@@ -12,7 +12,7 @@
|
||||
#服务器的接入IP。给客户端提供是${server.ip}和${http_port}。
|
||||
#客户端会从${http_port}端口获取到长链接端口。这个地址一定要改成客户端可以访问到的IP地址
|
||||
#(如果您部署云服务器上或者具有独立公网出口的服务器上,请改为对应的公网IP;如果您部署在在内网环境下,在内网使用,这个地方改成内网地址)
|
||||
server.ip 192.168.3.124
|
||||
server.ip 192.168.1.81
|
||||
|
||||
##原生客户端长链接端口
|
||||
port 1883
|
||||
@@ -42,6 +42,9 @@ embed.db 1
|
||||
## 使用mongodb时次开关无效(因为mongodb设置了消息过期时间,会自动清理,仅专业版支持mongodb)。
|
||||
db.auto_clean_history_messages true
|
||||
|
||||
## h2db数据库的路径,默认为程序目录下的,可以指定其他目录。如果使用MySQL,可以忽略此配置
|
||||
h2db.path ./h2db/wfchat
|
||||
|
||||
##服务器管理接口密钥。如果修改此端口需要同步修改使用管理API的地方,比如应用服务。
|
||||
http.admin.secret_key 123456
|
||||
|
||||
@@ -56,6 +59,15 @@ token.key testim
|
||||
##token的过期时间,单位为毫秒,默认为无限期。如果需要设置无限期,客户端上一定需要加上token过期的处理。token过期的处理请参考文档的常见问题
|
||||
##token.expire_time 2592000000
|
||||
|
||||
##客户端(目前只有android)的应用签名(一个应用最取第一个签名),如果有多个签名(多个客户端),用英文逗号分开。获取签名方法请参考文档:https://docs.wildfirechat.cn/blogs/签名验证.html
|
||||
#connect.client_signature_list eNkezQ1g9OsnhfLSFUY1vzKDzhs=,xykezQ1g9OsnhfLSFUY1vzKDzhs=
|
||||
|
||||
##是否拒绝空签名的android客户端, 默认为true。当有旧的客户端需要兼容时改成false,当所有都是新客户端时,改成true。
|
||||
#connect.reject_empty_signature true
|
||||
|
||||
##是否使用AES256加密。默认客户端和服务器都是AES128加密,如果需要开启AES256,需要客户端和IM服务同时开通。
|
||||
#encrypt.use_aes256 true
|
||||
|
||||
##首次登录,是否接收之前的历史消息。
|
||||
##0 不接收历史消息,只接收${message.compensate_time_limit}毫秒以内的消息,由于服务器没有保存已经收取记录,所以如果有超过${message.compensate_time_limit}毫秒之前未收取的消息也不会收取下拉;
|
||||
##1接收,会接收 message.max_queue 配置的条数的历史消息
|
||||
@@ -76,6 +88,9 @@ message.chatroom_remote_history_message 1
|
||||
##是否禁止陌生人聊天
|
||||
message.disable_stranger_chat false
|
||||
|
||||
##当禁止陌生人聊天时,允许聊天的用户id,比如管理员或者文件传输助手等。用户id以英文逗号分割。
|
||||
message.allow_stranger_chat_list admin,FireRobot,wfc_file_transfer
|
||||
|
||||
##黑名单策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃
|
||||
message.blacklist.strategy 0
|
||||
|
||||
@@ -139,11 +154,8 @@ friend.reject_request_duration 2592000000
|
||||
##好友请求过期时间,单位是毫秒,默认是7天,0为无限长期限。
|
||||
friend.request_expiration_duration 604800000
|
||||
|
||||
##添加好友后会发送欢迎消息,比如"你们已经是好友了,可以聊天了"。这个开关控制是用旧的方式还是用新的方式。
|
||||
##旧的方式会发送notification消息(contenttype是80),内容会根据好友接收者的语言选择对应的语言,如果双方语言不一致会导致另外一方看到的不是本地语言。
|
||||
##新的方式会发送添加好友消息(contenttype是93)和欢迎消息(contenttype是92),需要客户端实现这两种消息。
|
||||
##如果客户端已经实现这两种消息可以打开这个开关(客户端2020.6.30添加了此消息类型)。
|
||||
friend.new_welcome_message true
|
||||
##请求添加机器人为好友时,机器人是否自动接受,默认为true
|
||||
friend.robot_auto_accept true
|
||||
|
||||
## 聊天室观众空闲退出时间,单位为毫秒,默认为15分钟,0为永远不退出
|
||||
chatroom.participant_idle_time 900000
|
||||
@@ -164,6 +176,10 @@ group.allow_robot_custom_operation_notification true
|
||||
## 0 不发送,1 退群时发送,2 踢人时发送,3 退群和踢人时都发送。
|
||||
group.visible_quit_or_kickoff_notification 0
|
||||
|
||||
## 禁止客户端群操作。第1位是禁止创建群组,第2位是禁止销毁群组,3位禁止加入群,4位禁止退出群,5位禁止邀请群成员,6位禁止移出群成员,7位禁止转移群,8位禁止设置群管理员,9位禁止白名单处理,10位禁止群禁言,11位禁止修改群组信息,12位禁止群成员禁言。
|
||||
## Server API不受此限制。
|
||||
#group.forbidden_client_operation 0xFFF
|
||||
|
||||
## 隐藏用户信息属性类型,2是性别,3是电话号码,4是邮箱,5是地址,6是公司信息,7是社交账号,8是Extra信息。当需要隐藏多个时以英文逗号分开;
|
||||
## 本配置是为了提高安全性,避免把对应信息同步到客户端,这样就能防止程序被破解从而拿到用户关键信息。仅对客户端有效,server api不受影响。
|
||||
## 注意,修改本配置不会对已经同步的信息产生影响。
|
||||
@@ -190,11 +206,6 @@ http.channel.rate_limit 1000
|
||||
##客户端请求频率限制,默认是5秒100次。通常情况下不要修改这个值。
|
||||
client.request_rate_limit 100
|
||||
|
||||
#*********************************************************************
|
||||
# hazelcase configuration
|
||||
#*********************************************************************
|
||||
hazelcast.configuration config/hazelcast.xml
|
||||
|
||||
#*********************************************************************
|
||||
# Media server configuration
|
||||
#*********************************************************************
|
||||
@@ -301,17 +312,23 @@ push.ios.server.address http://localhost:8085/ios/push
|
||||
##消息转发地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.forward.url http://localhost:8888/im_event/message
|
||||
##需要转发的消息类型,当有多个时以英文逗号分割。如果转发所有消息,请注释掉配置或者设置为空
|
||||
#message.forward.types 1,2,3
|
||||
##需要转发的消息类型,当有多个时以英文逗号分割,可以用-来指定区间,注意区间不能太大,因为要把区间内的所有数字都放入到Set中。如果转发所有消息,请注释掉配置或者设置为空
|
||||
#message.forward.types 1,2,3,5-10
|
||||
##需要转发的消息类型,当有多个时以英文逗号分割,可以用-来指定区间,注意区间不能太大,因为要把区间内的所有数字都放入到Set中。
|
||||
#message.forward.exclude_types 1,2,3,5-10
|
||||
|
||||
##敏感消息转发地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.sensitive.forward.url http://localhost:8888/im_event/message
|
||||
|
||||
##提醒消息转发地址,@全体用户和@某个用户消息会回调此地址。此转发不受${message.forward.types}限制。
|
||||
##提醒消息转发地址,@全体用户和@某个用户消息会回调此地址。
|
||||
##此转发不受${message.forward.types}和${message.forward.exclude_types}限制。
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.mentionmsg.forward.url http://localhost:8888/im_event/message
|
||||
|
||||
##撤回消息转发地址,当用户撤回消息会回调此地址。
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.recallmsg.forward.url http://localhost:8888/im_event/recall_message
|
||||
|
||||
##设备信息转发地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_group_member` add INDEX `group_member_mid_index` (`_mid`);
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
alter table `t_group` add column `_super_group` tinyint NOT NULL DEFAULT 0;
|
||||
|
||||
DROP TABLE IF EXISTS `t_group_messages`;
|
||||
CREATE TABLE `t_group_messages` (
|
||||
`_mid` bigint(20) NOT NULL PRIMARY KEY,
|
||||
`_sender` varchar(64) NOT NULL,
|
||||
`_gid` varchar(64) NOT NULL,
|
||||
`_line` int(11) NOT NULL,
|
||||
`_client_id` varchar(64) NULL,
|
||||
`_seq` bigint(20) NOT NULL,
|
||||
`_persist_flag` int(11) NOT NULL,
|
||||
`_mentioned_type` int(11) NOT NULL,
|
||||
`_mentioned_targets` BLOB NULL,
|
||||
`_to` BLOB NULL,
|
||||
`_cont_type` int(11) NOT NULL DEFAULT 0,
|
||||
`_duration` int(11) NOT NULL DEFAULT 0,
|
||||
`_dt` bigint(20) NOT NULL DEFAULT 0,
|
||||
INDEX `group_message_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_group_member` add INDEX `group_member_mid_index` (`_mid`);
|
||||
+2722
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,11 +1,11 @@
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<relativePath>../</relativePath>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.95</version>
|
||||
<version>1.1.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>moquette-broker</artifactId>
|
||||
@@ -120,7 +120,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.10</version>
|
||||
<version>1.13</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -90,6 +90,8 @@ public class FileAction extends Action {
|
||||
}
|
||||
|
||||
response.setContent(file);
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,11 @@ public class IMAction extends Action {
|
||||
if (userId == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null);
|
||||
} else {
|
||||
if(messagesStore.getUserStatus(userId) == ProtoConstants.UserStatus.Forbidden) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_USER_BLOCKED, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
ServerAPIHelper.sendRequest(userId, wrapper.getClientId(), wrapper.getRequest(), wrapper.getData().toByteArray(), new ServerAPIHelper.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
|
||||
@@ -39,17 +39,10 @@ public class RouteAction extends Action {
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest) request.getNettyRequest();
|
||||
boolean b = false;
|
||||
if ("web".equalsIgnoreCase(fullHttpRequest.headers().get("p"))) {
|
||||
b = true;
|
||||
}
|
||||
|
||||
final boolean base64Response = b;
|
||||
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
|
||||
@@ -57,15 +50,20 @@ public class RouteAction extends Action {
|
||||
try {
|
||||
bytes = Base64.getDecoder().decode(str);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null, base64Response);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
String cid = fullHttpRequest.headers().get("cid");
|
||||
byte[] cbytes = Base64.getDecoder().decode(cid);
|
||||
cbytes = AES.AESDecrypt(cbytes, "", true);
|
||||
boolean[] invalidTime = new boolean[1];
|
||||
cbytes = AES.AESDecrypt(cbytes, "", true, invalidTime);
|
||||
if (cbytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null, base64Response);
|
||||
if(invalidTime[0]) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIME_INCONSISTENT, null);
|
||||
} else {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
cid = new String(cbytes);
|
||||
@@ -74,7 +72,7 @@ public class RouteAction extends Action {
|
||||
byte[] ubytes = Base64.getDecoder().decode(uid);
|
||||
ubytes = AES.AESDecrypt(ubytes, "", true);
|
||||
if (ubytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null, base64Response);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);
|
||||
return true;
|
||||
}
|
||||
uid = new String(ubytes);
|
||||
@@ -84,7 +82,7 @@ public class RouteAction extends Action {
|
||||
if (session == null) {
|
||||
ErrorCode errorCode = sessionsStore.loadActiveSession(uid, cid);
|
||||
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
sendResponse(response, errorCode, null, base64Response);
|
||||
sendResponse(response, errorCode, null);
|
||||
return true;
|
||||
}
|
||||
session = sessionsStore.sessionForClientAndUser(uid, cid);
|
||||
@@ -94,16 +92,20 @@ public class RouteAction extends Action {
|
||||
if (session != null) {
|
||||
bytes = AES.AESDecrypt(bytes, session.getSecret(), true);
|
||||
} else {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (bytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(messagesStore.getUserStatus(uid) == ProtoConstants.UserStatus.Forbidden) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_USER_BLOCKED, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
WFCMessage.IMHttpWrapper wrapper = WFCMessage.IMHttpWrapper.parseFrom(bytes);
|
||||
@@ -111,22 +113,22 @@ public class RouteAction extends Action {
|
||||
String userId = Tokenor.getUserId(token.getBytes());
|
||||
LOG.info("RouteAction token={}, userId={}", token, userId);
|
||||
if (userId == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null, base64Response);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null);
|
||||
} else {
|
||||
ServerAPIHelper.sendRequest(userId, wrapper.getClientId(), wrapper.getRequest(), wrapper.getData().toByteArray(), new ServerAPIHelper.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
sendResponse(response, null, result, base64Response);
|
||||
sendResponse(response, null, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null, base64Response);
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null, base64Response);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,25 +141,21 @@ public class RouteAction extends Action {
|
||||
return false;
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null, false);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendResponse(Response response, ErrorCode errorCode, byte[] contents, boolean base64Response) {
|
||||
private void sendResponse(Response response, ErrorCode errorCode, byte[] contents) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if (contents == null) {
|
||||
ByteBuf ackPayload = Unpooled.buffer();
|
||||
ackPayload.ensureWritable(1).writeByte(errorCode.getCode());
|
||||
contents = ackPayload.array();
|
||||
}
|
||||
if (base64Response) {
|
||||
byte[] base64Data = Base64.getEncoder().encode(contents);
|
||||
response.setContent(base64Data);
|
||||
} else {
|
||||
response.setContent(contents);
|
||||
}
|
||||
|
||||
response.setContent(contents);
|
||||
response.send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,10 @@ public class UploadFileAction extends Action {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(remoteFileName != null && remoteFileName.length() > 2 && remoteFileName.startsWith("'") && remoteFileName.endsWith("'")) {
|
||||
remoteFileName = remoteFileName.substring(1, remoteFileName.length()-1);
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(remoteFileName)) {
|
||||
logger.warn("remoteFileName is empty!");
|
||||
|
||||
@@ -235,12 +239,17 @@ public class UploadFileAction extends Action {
|
||||
int offset = 0; // 断点续传开始位置
|
||||
|
||||
Date nowTime=new Date();
|
||||
SimpleDateFormat time=new SimpleDateFormat("yyyy/MM/dd/HH");
|
||||
SimpleDateFormat time=new SimpleDateFormat("yyyy/MM/dd/HH/mm/ss");
|
||||
String datePath = time.format(nowTime);
|
||||
|
||||
datePath = "fs/" + bucket[0] + "/" + datePath; //add bucket
|
||||
|
||||
String dir = "./" + MediaServerConfig.FILE_STROAGE_ROOT + "/" + datePath;
|
||||
String dir;
|
||||
if(MediaServerConfig.FILE_STROAGE_ROOT.startsWith("/") || MediaServerConfig.FILE_STROAGE_ROOT.startsWith("~/") || MediaServerConfig.FILE_STROAGE_ROOT.startsWith("./")) {
|
||||
dir = MediaServerConfig.FILE_STROAGE_ROOT + "/" + datePath;
|
||||
} else {
|
||||
dir = "./" + MediaServerConfig.FILE_STROAGE_ROOT + "/" + datePath;
|
||||
}
|
||||
|
||||
File dirFile = new File(dir);
|
||||
boolean bFile = dirFile.exists();
|
||||
@@ -248,6 +257,7 @@ public class UploadFileAction extends Action {
|
||||
if(!bFile) {
|
||||
bFile = dirFile.mkdirs();
|
||||
if (!bFile) {
|
||||
logger.error("create dirs error! {}", dir);
|
||||
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
response.setContent("服务器错误:无法创建文件");
|
||||
return false;
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.common.APIPath;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.InputUserId;
|
||||
import cn.wildfirechat.pojos.OutputGroupIds;
|
||||
import cn.wildfirechat.pojos.StringPairPojo;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
@Route(APIPath.Get_Common_Groups)
|
||||
@HttpMethod("POST")
|
||||
public class GetCommonGroupsAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
StringPairPojo input = getRequestBody(request.getNettyRequest(), StringPairPojo.class);
|
||||
if (input != null
|
||||
&& (!StringUtil.isNullOrEmpty(input.getFirst())) && (!StringUtil.isNullOrEmpty(input.getSecond()))) {
|
||||
|
||||
Set<String> groupIds = messagesStore.getCommonGroupIds(input.getFirst(), input.getSecond());
|
||||
OutputGroupIds outputGroupIds = new OutputGroupIds();
|
||||
outputGroupIds.setGroupIds(new ArrayList<>(groupIds));
|
||||
RestResult result = RestResult.ok(outputGroupIds);
|
||||
setResponseContent(result, response);
|
||||
} else {
|
||||
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.common.APIPath;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.InputGetGroup;
|
||||
import cn.wildfirechat.pojos.InputGetGroupMember;
|
||||
import cn.wildfirechat.pojos.OutputGroupMemberList;
|
||||
import cn.wildfirechat.pojos.PojoGroupMember;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Route(APIPath.Group_Member_Get)
|
||||
@HttpMethod("POST")
|
||||
public class GetGroupMemberAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetGroupMember input = getRequestBody(request.getNettyRequest(), InputGetGroupMember.class);
|
||||
if (input != null
|
||||
&& (!StringUtil.isNullOrEmpty(input.getGroupId()))
|
||||
&& (!StringUtil.isNullOrEmpty(input.getMemberId()))) {
|
||||
|
||||
WFCMessage.GroupMember groupMember = messagesStore.getGroupMember(input.getGroupId(), input.getMemberId());
|
||||
|
||||
RestResult result;
|
||||
if (groupMember == null || StringUtil.isNullOrEmpty(groupMember.getMemberId()) || groupMember.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
PojoGroupMember pm = new PojoGroupMember();
|
||||
pm.setMember_id(groupMember.getMemberId());
|
||||
pm.setAlias(groupMember.getAlias());
|
||||
pm.setType(groupMember.getType());
|
||||
pm.setExtra(groupMember.getExtra());
|
||||
pm.setCreateDt(groupMember.getCreateDt());
|
||||
result = RestResult.ok(pm);
|
||||
}
|
||||
setResponseContent(result, response);
|
||||
} else {
|
||||
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class GetUserAction extends AdminAction {
|
||||
}
|
||||
|
||||
RestResult result;
|
||||
if (user == null) {
|
||||
if (user == null || user.getDeleted() > 0) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
result = RestResult.ok(InputOutputUserInfo.fromPbUser(user));
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.channel;
|
||||
|
||||
import cn.wildfirechat.common.APIPath;
|
||||
import cn.wildfirechat.pojos.InputChannelSubscribe;
|
||||
import cn.wildfirechat.pojos.InputUserId;
|
||||
import cn.wildfirechat.pojos.OutputStringList;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Route(APIPath.Channel_Is_Subscriber)
|
||||
@HttpMethod("POST")
|
||||
public class GetIsChannelSubscriberAction extends ChannelAction {
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputUserId input = getRequestBody(request.getNettyRequest(), InputUserId.class);
|
||||
boolean isSubscriber = messagesStore.checkUserInChannel(input.getUserId(), channelInfo.getTargetId());
|
||||
setResponseContent(RestResult.ok(isSubscriber), response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ public class GetUserAction extends ChannelAction {
|
||||
|
||||
RestResult result;
|
||||
|
||||
if (user == null || StringUtil.isNullOrEmpty(user.getName())) {
|
||||
if (user == null || StringUtil.isNullOrEmpty(user.getName()) || user.getDeleted() > 0) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
if (channelInfo.getOwner().equals(inputUserId.getUserId()) ||
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.robot;
|
||||
|
||||
import cn.wildfirechat.common.APIPath;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.InputGetGroup;
|
||||
import cn.wildfirechat.pojos.InputGetGroupMember;
|
||||
import cn.wildfirechat.pojos.OutputGroupMemberList;
|
||||
import cn.wildfirechat.pojos.PojoGroupMember;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Route(APIPath.Robot_Group_Member_Get)
|
||||
@HttpMethod("POST")
|
||||
public class GetGroupMemberAction extends RobotAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetGroupMember input = getRequestBody(request.getNettyRequest(), InputGetGroupMember.class);
|
||||
String robotId = robot.getUid();
|
||||
if (input != null
|
||||
&& (!StringUtil.isNullOrEmpty(input.getGroupId()))
|
||||
&& (!StringUtil.isNullOrEmpty(input.getMemberId()))) {
|
||||
|
||||
List<WFCMessage.GroupMember> members = new ArrayList<>();
|
||||
ErrorCode errorCode = messagesStore.getGroupMembers(null, input.getGroupId(), 0, members);
|
||||
RestResult result;
|
||||
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
result = RestResult.resultOf(errorCode);
|
||||
} else {
|
||||
WFCMessage.GroupMember groupMember = null;
|
||||
boolean isInGroup = false;
|
||||
for (WFCMessage.GroupMember member : members) {
|
||||
if (member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {
|
||||
continue;
|
||||
}
|
||||
if(member.getMemberId().equals(robotId)) {
|
||||
isInGroup = true;
|
||||
if(groupMember != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(member.getMemberId().equals(input.getMemberId())) {
|
||||
groupMember = member;
|
||||
if(isInGroup) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!isInGroup) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_IN_GROUP);
|
||||
} else {
|
||||
if(groupMember == null) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
PojoGroupMember pm = new PojoGroupMember();
|
||||
pm.setMember_id(groupMember.getMemberId());
|
||||
pm.setAlias(groupMember.getAlias());
|
||||
pm.setType(groupMember.getType());
|
||||
pm.setExtra(groupMember.getExtra());
|
||||
pm.setCreateDt(groupMember.getCreateDt());
|
||||
result = RestResult.ok(pm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setResponseContent(result, response);
|
||||
} else {
|
||||
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ public class GetUserAction extends RobotAction {
|
||||
}
|
||||
|
||||
RestResult result;
|
||||
if (user == null) {
|
||||
if (user == null || user.getDeleted() > 0) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
result = RestResult.ok(InputOutputUserInfo.fromPbUser(user));
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import win.liyufan.im.Utility;
|
||||
@@ -34,7 +35,6 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
|
||||
Logger.info("Http request whit url {}", fullHttpRequest.uri());
|
||||
final Request request = Request.build(ctx, fullHttpRequest);
|
||||
final Response response = Response.build(ctx, request);
|
||||
|
||||
@@ -109,7 +109,7 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
* @param response 响应对象
|
||||
*/
|
||||
private void doAction(ChannelHandlerContext ctx, Request request, Response response){
|
||||
if(("/route".equalsIgnoreCase(request.getPath()) || request.getPath().startsWith("/fs/"))
|
||||
if(("/route".equalsIgnoreCase(request.getPath()) || (!StringUtil.isNullOrEmpty(request.getPath()) && request.getPath().startsWith("/fs/")))
|
||||
&& "OPTIONS".equalsIgnoreCase(request.getMethod())){
|
||||
handleOptions(ctx, request, response);
|
||||
return;
|
||||
@@ -124,6 +124,9 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
Action action;
|
||||
if (isValidePath(request.getPath())) {
|
||||
action = ServerSetting.getAction(request.getPath(), request.getMethod().toUpperCase());
|
||||
if (action != null) {
|
||||
Logger.info("Http request whit url {}", request.getPath());
|
||||
}
|
||||
} else {
|
||||
action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);
|
||||
}
|
||||
@@ -137,7 +140,11 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
action = ServerSetting.getAction(ServerSetting.MAPPING_ALL, request.getMethod());
|
||||
if(null == action){
|
||||
// 非Action方法,调用静态文件读取
|
||||
action = Singleton.get(FileAction.class);
|
||||
if(request.getPath().startsWith("/fs")) {
|
||||
action = Singleton.get(FileAction.class);
|
||||
} else {
|
||||
action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
action.ctx = ctx;
|
||||
|
||||
@@ -29,6 +29,8 @@ public final class BrokerConstants {
|
||||
public static final String HTTP_SERVER_PORT = "http_port";
|
||||
public static final String HTTP_LOCAL_PORT = "local_port";
|
||||
|
||||
public static final String ENCRYPT_AES256 = "encrypt.use_aes256";
|
||||
|
||||
public static final String HTTP_ADMIN_PORT = "http.admin.port";
|
||||
public static final String DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME = "moquette_store.mapdb";
|
||||
public static final String DEFAULT_PERSISTENT_PATH = System.getProperty("user.dir") + File.separator
|
||||
@@ -110,8 +112,13 @@ public final class BrokerConstants {
|
||||
public static final String TOKEN_SECRET_KEY = "token.key";
|
||||
public static final String TOKEN_EXPIRE_TIME = "token.expire_time";
|
||||
|
||||
public static final String CONNECT_CLIENT_SIGNATURE_LIST = "connect.client_signature_list";
|
||||
public static final String CONNECT_REJECT_EMPTY_SIGNATURE = "connect.reject_empty_signature";
|
||||
|
||||
public static final String EMBED_DB_PROPERTY_NAME = "embed.db";
|
||||
public static final String DB_AUTO_CLEAN_HISTORY_MESSAGES = "db.auto_clean_history_messages";
|
||||
public static final String H2DB_PATH = "h2db.path";
|
||||
|
||||
|
||||
public static final String SENSITIVE_Filter_Type = "sensitive.filter.type";
|
||||
|
||||
@@ -122,8 +129,9 @@ public final class BrokerConstants {
|
||||
public static final String MESSAGE_Forward_Url = "message.forward.url";
|
||||
public static final String MESSAGE_Sensitive_Forward_Url = "message.sensitive.forward.url";
|
||||
public static final String MESSAGE_Forward_Types = "message.forward.types";
|
||||
public static final String MESSAGE_Forward_Exclude_Types = "message.forward.exclude_types";
|
||||
public static final String MESSAGE_MentionMsg_Forward_Url = "message.mentionmsg.forward.url";
|
||||
|
||||
public static final String MESSAGE_RecallMsg_Forward_Url = "message.recallmsg.forward.url";
|
||||
|
||||
public static final String SERVER_MULTI_ENDPOINT = "server.multi_endpoint";
|
||||
public static final String SERVER_MULTI_PC_ENDPOINT = "server.multi_pc_endpoint";
|
||||
@@ -139,6 +147,7 @@ public final class BrokerConstants {
|
||||
public static final String MESSAGE_Max_Queue = "message.max_queue";
|
||||
|
||||
public static final String MESSAGE_Disable_Stranger_Chat = "message.disable_stranger_chat";
|
||||
public static final String MESSAGE_Allow_Stranger_Chat_List = "message.allow_stranger_chat_list";
|
||||
|
||||
public static final String MESSAGE_Blacklist_Strategy = "message.blacklist.strategy";
|
||||
|
||||
@@ -154,7 +163,8 @@ public final class BrokerConstants {
|
||||
public static final String FRIEND_Repeat_Request_Duration = "friend.repeat_request_duration";
|
||||
public static final String FRIEND_Reject_Request_Duration = "friend.reject_request_duration";
|
||||
public static final String FRIEND_Request_Expiration_Duration = "friend.request_expiration_duration";
|
||||
public static final String FRIEND_New_Welcome_Message = "friend.new_welcome_message";
|
||||
public static final String FRIEND_Request_Robot_Auto_Accept = "friend.robot_auto_accept";
|
||||
|
||||
|
||||
public static final String CHATROOM_Participant_Idle_Time = "chatroom.participant_idle_time";
|
||||
public static final String CHATROOM_Rejoin_When_Active = "chatroom.rejoin_when_active";
|
||||
@@ -165,6 +175,7 @@ public final class BrokerConstants {
|
||||
public static final String GROUP_Allow_Robot_Custom_Operation_Notification = "group.allow_robot_custom_operation_notificatio";
|
||||
|
||||
public static final String GROUP_Visible_Quit_Kickoff_Notification = "group.visible_quit_or_kickoff_notification";
|
||||
public static final String GROUP_Forbidden_Client_Operation = "group.forbidden_client_operation";
|
||||
|
||||
public static final String USER_HIDE_PROPERTIES = "user.hide_properties";
|
||||
public static final String USER_KEEP_DISPLAY_NAME_WHEN_DESTROY = "user.keep_display_name_when_destroy";
|
||||
|
||||
@@ -30,8 +30,10 @@ public class AddFriendHandler extends GroupHandler<WFCMessage.AddFriendRequest>
|
||||
if (user != null && user.getType() == ProtoConstants.UserType.UserType_Normal) {
|
||||
publisher.publishNotification(IMTopic.NotifyFriendRequestTopic, request.getTargetUid(), head[0], fromUser, request.getReason());
|
||||
} else if(user != null && user.getType() == ProtoConstants.UserType.UserType_Robot) {
|
||||
WFCMessage.HandleFriendRequest handleFriendRequest = WFCMessage.HandleFriendRequest.newBuilder().setTargetUid(fromUser).setStatus(ProtoConstants.FriendRequestStatus.RequestStatus_Accepted).build();
|
||||
mServer.onApiMessage(request.getTargetUid(), null, handleFriendRequest.toByteArray(), 0, fromUser, HandleFriendRequestTopic, requestSourceType);
|
||||
if(m_messagesStore.isRobotAutoAcceptFriendRequest()) {
|
||||
WFCMessage.HandleFriendRequest handleFriendRequest = WFCMessage.HandleFriendRequest.newBuilder().setTargetUid(fromUser).setStatus(ProtoConstants.FriendRequestStatus.RequestStatus_Accepted).build();
|
||||
mServer.onApiMessage(request.getTargetUid(), null, handleFriendRequest.toByteArray(), 0, fromUser, HandleFriendRequestTopic, requestSourceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errorCode;
|
||||
|
||||
@@ -24,6 +24,20 @@ public class AddGroupMember extends GroupHandler<WFCMessage.AddGroupMemberReques
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.AddGroupMemberRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if(request.getAddedMemberList().size() == 1 && request.getAddedMember(0).getMemberId().equals(fromUser)) {
|
||||
if ((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Join_Group) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
} else {
|
||||
if ((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Invite_Group_Member) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_messagesStore.addGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getAddedMemberList(), request.getExtra());
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import win.liyufan.im.IMTopic;
|
||||
public class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.CreateGroupRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
if(request.getGroup().getGroupInfo().getType() < 0 || request.getGroup().getGroupInfo().getType() > 2) {
|
||||
if(request.getGroup().getGroupInfo().getType() < 0 || request.getGroup().getGroupInfo().getType() > 3) {
|
||||
return ErrorCode.ERROR_CODE_INVALID_DATA;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,16 @@ public class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupReque
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(!isAdmin && request.getGroup().getGroupInfo().getType() == ProtoConstants.GroupType.GroupType_Organization) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Create_Group) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
WFCMessage.GroupInfo groupInfo = m_messagesStore.createGroup(fromUser, request.getGroup().getGroupInfo(), request.getGroup().getMembersList(), request.getMemberExtra(), isAdmin);
|
||||
if (groupInfo != null) {
|
||||
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
|
||||
@@ -26,7 +26,6 @@ public class DismissGroupHandler extends GroupHandler<WFCMessage.DismissGroupReq
|
||||
ErrorCode errorCode;
|
||||
if (groupInfo == null) {
|
||||
errorCode = m_messagesStore.dismissGroup(fromUser, request.getGroupId(), isAdmin);
|
||||
|
||||
} else if (isAdmin || (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted)
|
||||
&& groupInfo.getOwner() != null && groupInfo.getOwner().equals(fromUser)) {
|
||||
|
||||
@@ -38,6 +37,13 @@ public class DismissGroupHandler extends GroupHandler<WFCMessage.DismissGroupReq
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Dismiss_Group) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
//send notify message first, then dismiss group
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package io.moquette.imhandler;
|
||||
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
@Handler(IMTopic.GetCommonGroupsTopic)
|
||||
public class GetCommonGroupsHandler extends IMHandler<WFCMessage.IDBuf> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {
|
||||
WFCMessage.PullUserResult.Builder resultBuilder = WFCMessage.PullUserResult.newBuilder();
|
||||
Set<String> strings = m_messagesStore.getCommonGroupIds(fromUser, request.getId());
|
||||
WFCMessage.IDListBuf idListBuf = WFCMessage.IDListBuf.newBuilder().addAllId(strings).build();
|
||||
byte[] data = idListBuf.toByteArray();
|
||||
ackPayload.ensureWritable(data.length).writeBytes(data);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
public class GetGroupInfoHandler extends IMHandler<WFCMessage.PullUserRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.PullUserRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
List<WFCMessage.GroupInfo> infos = m_messagesStore.getGroupInfos(request.getRequestList());
|
||||
List<WFCMessage.GroupInfo> infos = m_messagesStore.getGroupInfos(request.getRequestList(), fromUser, requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin);
|
||||
|
||||
WFCMessage.PullGroupInfoResult result = WFCMessage.PullGroupInfoResult.newBuilder().addAllInfo(infos).build();
|
||||
byte[] data = result.toByteArray();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package io.moquette.imhandler;
|
||||
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
@Handler(IMTopic.GetMyGroupsTopic)
|
||||
public class GetMyGroupsHandler extends IMHandler<Void> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, Void request, Qos1PublishHandler.IMCallback callback) {
|
||||
WFCMessage.PullUserResult.Builder resultBuilder = WFCMessage.PullUserResult.newBuilder();
|
||||
Set<String> strings = m_messagesStore.getUserGroupIds(fromUser);
|
||||
WFCMessage.IDListBuf idListBuf = WFCMessage.IDListBuf.newBuilder().addAllId(strings).build();
|
||||
byte[] data = idListBuf.toByteArray();
|
||||
ackPayload.ensureWritable(data.length).writeBytes(data);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,10 @@ package io.moquette.imhandler;
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.moquette.persistence.MemorySessionStore;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.I18n;
|
||||
import win.liyufan.im.IMTopic;
|
||||
import win.liyufan.im.MessageShardingUtil;
|
||||
|
||||
@@ -43,17 +41,8 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build(), requestSourceType);
|
||||
}
|
||||
|
||||
MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);
|
||||
String language = "zh_CN";
|
||||
if (session != null && !StringUtil.isNullOrEmpty(session.getLanguage())) {
|
||||
language = session.getLanguage();
|
||||
}
|
||||
WFCMessage.MessageContent.Builder contentBuilder = WFCMessage.MessageContent.newBuilder();
|
||||
if (m_messagesStore.isNewFriendWelcomeMessage()) {
|
||||
contentBuilder.setType(92);
|
||||
} else {
|
||||
contentBuilder.setType(90).setContent(I18n.getString(language, "Above_Greeting_Message"));
|
||||
}
|
||||
contentBuilder.setType(92);
|
||||
|
||||
builder = WFCMessage.Message.newBuilder();
|
||||
builder.setFromUser(request.getTargetUid());
|
||||
@@ -64,13 +53,7 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
|
||||
messageId = MessageShardingUtil.generateId();
|
||||
builder.setMessageId(messageId);
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build(), requestSourceType);
|
||||
|
||||
if (m_messagesStore.isNewFriendWelcomeMessage()) {
|
||||
contentBuilder.setType(93);
|
||||
} else {
|
||||
contentBuilder.setContent(I18n.getString(language, "Friend_Can_Start_Chat"));
|
||||
}
|
||||
|
||||
contentBuilder.setType(93);
|
||||
builder.setContent(contentBuilder);
|
||||
messageId = MessageShardingUtil.generateId();
|
||||
builder.setMessageId(messageId);
|
||||
|
||||
@@ -29,6 +29,10 @@ public class KickoffGroupMember extends GroupHandler<WFCMessage.RemoveGroupMembe
|
||||
errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
} else {
|
||||
boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;
|
||||
if (!isAdmin && groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
boolean isAllow = isAdmin;
|
||||
if (!isAllow) {
|
||||
if (groupInfo.getOwner() != null) {
|
||||
@@ -58,6 +62,13 @@ public class KickoffGroupMember extends GroupHandler<WFCMessage.RemoveGroupMembe
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Kickoff_Group_Member) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
//send notify message first, then kickoff the member
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
|
||||
|
||||
@@ -31,6 +31,19 @@ public class ModifyGroupInfoHandler extends GroupHandler<WFCMessage.ModifyGroupI
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if(request.getType() == Modify_Group_Mute) {
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Mute_Group) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
} else {
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Modify_Group_Info) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode errorCode= m_messagesStore.modifyGroupInfo(fromUser, request.getGroupId(), request.getType(), request.getValue(), isAdmin);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
|
||||
@@ -31,7 +31,14 @@ public class QuitGroupHandler extends GroupHandler<WFCMessage.QuitGroupRequest>
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_messagesStore.quitGroup(fromUser, request.getGroupId());
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Quit_Group) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_messagesStore.quitGroup(fromUser, request.getGroupId(), isAdmin);
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());
|
||||
|
||||
@@ -40,6 +40,11 @@ public class RouteHandler extends IMHandler<WFCMessage.RouteRequest> {
|
||||
return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;
|
||||
}
|
||||
|
||||
if(request.getPlatform() != session.getPlatform() && m_messagesStore.existSignatures()) {
|
||||
LOG.error("Session <{}, {}> platform is {} mismatch the request {}", session.getUsername(), session.getClientID(), session.getPlatform(), request.getPlatform());
|
||||
return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;
|
||||
}
|
||||
|
||||
String serverIp = mServer.getServerIp();
|
||||
String longPort = mServer.getLongPort();
|
||||
String shortPort = mServer.getShortPort();
|
||||
|
||||
@@ -22,6 +22,7 @@ import cn.wildfirechat.common.ErrorCode;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import win.liyufan.im.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -33,6 +34,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
private String mForwardUrl = null;
|
||||
private String mSensitiveMessageForwardUrl = null;
|
||||
private Set<Integer> mForwardMessageTypes = new HashSet<>();
|
||||
private Set<Integer> mForwardExcludeMessageTypes = new HashSet<>();
|
||||
private String mMentionForwardUrl = null;
|
||||
private int mBlacklistStrategy = 0; //黑名单中时,0失败,1吞掉。
|
||||
private boolean mNoForwardAdminMessage = false;
|
||||
@@ -47,12 +49,9 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
mForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Url);
|
||||
if (!StringUtil.isNullOrEmpty(mForwardUrl)) {
|
||||
String forwardTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Types);
|
||||
if (!StringUtil.isNullOrEmpty(forwardTypes)) {
|
||||
String[] tss = forwardTypes.split(",");
|
||||
for (String ts:tss) {
|
||||
mForwardMessageTypes.add(Integer.parseInt(ts.trim()));
|
||||
}
|
||||
}
|
||||
parseTypes(mForwardMessageTypes, forwardTypes);
|
||||
String excludeTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Exclude_Types);
|
||||
parseTypes(mForwardExcludeMessageTypes, excludeTypes);
|
||||
}
|
||||
mSensitiveMessageForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Sensitive_Forward_Url);
|
||||
mMentionForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_MentionMsg_Forward_Url);
|
||||
@@ -97,6 +96,30 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
|
||||
}
|
||||
|
||||
private void parseTypes(Collection<Integer> collection, String types) {
|
||||
try {
|
||||
if (!StringUtil.isNullOrEmpty(types)) {
|
||||
String[] tss = types.split(",");
|
||||
for (String ts:tss) {
|
||||
if(ts.contains("-")) {
|
||||
String[] ss = ts.split("-");
|
||||
if(ss.length == 2) {
|
||||
int begin = Integer.parseInt(ss[0]);
|
||||
int end = Integer.parseInt(ss[1]);
|
||||
for (int i = begin; i <= end ; i++) {
|
||||
collection.add(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
collection.add(Integer.parseInt(ts.trim()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Message message, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
@@ -159,6 +182,15 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group) {
|
||||
if(m_messagesStore.getGroupInfo(message.getConversation().getTarget()) == null) {
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {
|
||||
WFCMessage.ChannelInfo channelData = m_messagesStore.getChannelInfo(message.getConversation().getTarget());
|
||||
if(channelData == null || channelData.getStatus() == ProtoConstants.ChannelState.Channel_State_Mask_Deleted) {
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
}
|
||||
|
||||
long timestamp = System.currentTimeMillis();
|
||||
@@ -179,7 +211,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(mForwardUrl) && (mForwardMessageTypes.isEmpty() || mForwardMessageTypes.contains(message.getContent().getType())) && !(isAdmin && mNoForwardAdminMessage)) {
|
||||
if (!StringUtil.isNullOrEmpty(mForwardUrl) && (mForwardMessageTypes.isEmpty() || mForwardMessageTypes.contains(message.getContent().getType())) && !(isAdmin && mNoForwardAdminMessage) && !mForwardExcludeMessageTypes.contains(message.getContent().getType())) {
|
||||
publisher.forwardMessage(message, mForwardUrl, outputClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,13 @@ public class SetGroupManagerHandler extends GroupHandler<WFCMessage.SetGroupMana
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Set_Group_Manage) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_messagesStore.setGroupManager(fromUser, request.getGroupId(), request.getType(), request.getUserIdList(), isAdmin);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
|
||||
@@ -30,6 +30,13 @@ public class TransferGroupHandler extends GroupHandler<WFCMessage.TransferGroupR
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
|
||||
int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();
|
||||
if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Transfer_Group) > 0) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_messagesStore.transferGroup(fromUser, request.getGroupId(), request.getNewOwner(), isAdmin);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
|
||||
@@ -25,9 +25,11 @@ public class UploadDeviceTokenHandler extends IMHandler<WFCMessage.UploadDeviceT
|
||||
session.setPlatform(request.getPlatform());
|
||||
session.setAppName(request.getAppName());
|
||||
if (request.getPlatform() == ProtoConstants.Platform.Platform_iOS && request.getPushType() == 2) {
|
||||
LOG.info("Set device token, userId {}", fromUser);
|
||||
session.setVoipDeviceToken(request.getDeviceToken());
|
||||
m_sessionsStore.updateSessionToken(session, true);
|
||||
} else {
|
||||
LOG.info("Set device token, userId {}, platform {}, pushType {}", fromUser, session.getPlatform(), request.getPushType());
|
||||
session.setDeviceToken(request.getDeviceToken());
|
||||
session.setPushType(request.getPushType());
|
||||
m_sessionsStore.updateSessionToken(session, false);
|
||||
|
||||
@@ -203,7 +203,7 @@ public class DatabaseStore {
|
||||
}
|
||||
|
||||
|
||||
sql += " and _type <> 2"; //can search normal user(0) and robot(1) and admin(100), can not search things
|
||||
sql += " and `_type` <> 2 and `_deleted` = 0"; //can search normal user(0) and robot(1) and admin(100), can not search things
|
||||
|
||||
if (searchType == SearchUserType_Name_Mobile || searchType == SearchUserType_Name || searchType == SearchUserType_Mobile) {
|
||||
sql += " limit 1";
|
||||
@@ -815,7 +815,7 @@ public class DatabaseStore {
|
||||
long beforeUid = before[0];
|
||||
String sql = "select `_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_dt`, `_to` from " + table +" where";
|
||||
if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
sql += " _type = ? and _line = ? and _mid < ? and ((_target = ? and _from = ?) or (_target = ? and _from = ?))";
|
||||
sql += " _type = ? and _line = ? and _mid < ? and ((_target = ? and _from = ?) or (_target = ? and _from = ?)) and (_to = '' or _to = ?)";
|
||||
} else if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Channel && !user.equals(channelOwner)) {
|
||||
sql += " _type = ? and _line = ? and _mid < ? and _target = ? and ((_from = ? and (_to = '' or _to = ?)) or (_from = ?))";
|
||||
} else {
|
||||
@@ -853,6 +853,7 @@ public class DatabaseStore {
|
||||
statement.setString(index++, user);
|
||||
statement.setString(index++, user);
|
||||
statement.setString(index++, conversation.getTarget());
|
||||
statement.setString(index++, user);
|
||||
} else if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Channel && !user.equals(channelOwner)) {
|
||||
statement.setString(index++, channelOwner);
|
||||
statement.setString(index++, user);
|
||||
@@ -914,7 +915,7 @@ public class DatabaseStore {
|
||||
return false;
|
||||
}
|
||||
|
||||
void persistUserMessage(final String userId, final long messageId, final long messageSeq, int type, String target, int line, boolean directing, final int messageContentType) {
|
||||
void persistUserMessage(final String userId, final String sender, final long messageId, final long messageSeq, int type, String target, int line, boolean directing, final int messageContentType) {
|
||||
mScheduler.execute(()->{
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
@@ -929,7 +930,7 @@ public class DatabaseStore {
|
||||
statement.setString(index++, userId);
|
||||
statement.setLong(index++, messageSeq);
|
||||
statement.setInt(index++, type);
|
||||
statement.setString(index++, target);
|
||||
statement.setString(index++, getPrivateChatUserMessageTarget(type, target, sender));
|
||||
statement.setInt(index++, line);
|
||||
statement.setInt(index++, directing ? 1 :0);
|
||||
statement.setInt(index++, messageContentType);
|
||||
@@ -945,6 +946,14 @@ public class DatabaseStore {
|
||||
});
|
||||
}
|
||||
|
||||
String getPrivateChatUserMessageTarget(int conversationType, String target, String userId) {
|
||||
if(conversationType == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
return target.compareTo(userId) > 0 ? (userId + "|" + target) : (target + "|" + userId);
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
void clearUserMessage(final String userId) {
|
||||
mScheduler.execute(()->{
|
||||
String tableName = getUserMessageTable(userId);
|
||||
@@ -1493,12 +1502,6 @@ public class DatabaseStore {
|
||||
if (!strEqual(session.getAppName(), request.getApp())) {
|
||||
sql += " `_package_name` = ?,";
|
||||
}
|
||||
if (session.getPlatform() != request.getPlatform()) {
|
||||
sql += " `_platform` = ?,";
|
||||
}
|
||||
if (session.getPushType() != request.getPushType()) {
|
||||
sql += " `_push_type` = ?,";
|
||||
}
|
||||
if (!strEqual(session.getDeviceName(), request.getDeviceName())) {
|
||||
sql += " `_device_name` = ?,";
|
||||
}
|
||||
@@ -1526,12 +1529,6 @@ public class DatabaseStore {
|
||||
if (!strEqual(session.getAppName(), request.getApp())) {
|
||||
statement.setString(index++, request.getApp());
|
||||
}
|
||||
if (session.getPlatform() != request.getPlatform()) {
|
||||
statement.setInt(index++, request.getPlatform());
|
||||
}
|
||||
if (session.getPushType() != request.getPushType()) {
|
||||
statement.setInt(index++, request.getPushType() >= 32 ? 0 : request.getPushType());
|
||||
}
|
||||
if (!strEqual(session.getDeviceName(), request.getDeviceName())) {
|
||||
statement.setString(index++, request.getDeviceName());
|
||||
}
|
||||
@@ -1712,6 +1709,35 @@ public class DatabaseStore {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> getCommonGroupIds(String userId1, String userId2) {
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
String sql = "select t1._gid from t_group_member t1, t_group_member t2 where t1._mid = ? and t2._mid = ? and t1._type <> 4 and t2._type <> 4 and t1._gid = t2._gid";
|
||||
statement = connection.prepareStatement(sql);
|
||||
|
||||
statement.setString(1, userId1);
|
||||
statement.setString(2, userId2);
|
||||
|
||||
rs = statement.executeQuery();
|
||||
Set<String> out = new HashSet<>();
|
||||
while (rs.next()) {
|
||||
String uid = rs.getString(1);
|
||||
out.add(uid);
|
||||
}
|
||||
return out;
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement, rs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void updateGroupMemberDt(final String groupId, final long dt) {
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
@@ -2385,59 +2411,55 @@ public class DatabaseStore {
|
||||
}
|
||||
|
||||
void deleteUserStatus(String userId) {
|
||||
mScheduler.execute(()->{
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
String sql = "delete from t_user_status where _uid = ?";
|
||||
statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, userId);
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement);
|
||||
}
|
||||
}
|
||||
|
||||
void updateUserStatus(String userId, int status) {
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
if (status == 0) {
|
||||
String sql = "delete from t_user_status where _uid = ?";
|
||||
statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, userId);
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement);
|
||||
} else {
|
||||
String sql = "insert into t_user_status (`_uid`, `_status`, `_dt`) values(?,?,?) ON DUPLICATE KEY UPDATE `_status` = ?";
|
||||
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setString(index++, userId);
|
||||
statement.setInt(index++, status);
|
||||
statement.setLong(index++, System.currentTimeMillis());
|
||||
statement.setInt(index++, status);
|
||||
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateUserStatus(String userId, int status) {
|
||||
mScheduler.execute(()->{
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
if (status == 0) {
|
||||
String sql = "delete from t_user_status where _uid = ?";
|
||||
statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, userId);
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
} else {
|
||||
String sql = "insert into t_user_status (`_uid`, `_status`, `_dt`) values(?,?,?) ON DUPLICATE KEY UPDATE `_status` = ?";
|
||||
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setString(index++, userId);
|
||||
statement.setInt(index++, status);
|
||||
statement.setLong(index++, System.currentTimeMillis());
|
||||
statement.setInt(index++, status);
|
||||
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement);
|
||||
}
|
||||
});
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement);
|
||||
}
|
||||
}
|
||||
|
||||
int getGeneratedId() {
|
||||
@@ -3316,47 +3338,45 @@ public class DatabaseStore {
|
||||
}
|
||||
|
||||
void updateChannelListener(final String channelId, final String listener, final boolean listen) {
|
||||
LOG.info("Database remove channel {}", channelId);
|
||||
mScheduler.execute(()->{
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
String sql;
|
||||
if (listen) {
|
||||
sql = "insert into t_channel_listener (`_cid`" +
|
||||
", `_mid`" +
|
||||
", `_dt`) values(?, ?, ?)" +
|
||||
" ON DUPLICATE KEY UPDATE " +
|
||||
"`_dt` = ?";
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setString(index++, channelId);
|
||||
statement.setString(index++, listener);
|
||||
statement.setLong(index++, System.currentTimeMillis());
|
||||
statement.setLong(index++, System.currentTimeMillis());
|
||||
LOG.info("updateChannelListener channel {}, listener {}, listen {}", channelId, listener, listen);
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
String sql;
|
||||
if (listen) {
|
||||
sql = "insert into t_channel_listener (`_cid`" +
|
||||
", `_mid`" +
|
||||
", `_dt`) values(?, ?, ?)" +
|
||||
" ON DUPLICATE KEY UPDATE " +
|
||||
"`_dt` = ?";
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setString(index++, channelId);
|
||||
statement.setString(index++, listener);
|
||||
statement.setLong(index++, System.currentTimeMillis());
|
||||
statement.setLong(index++, System.currentTimeMillis());
|
||||
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
} else {
|
||||
sql = "delete from t_channel_listener where `_cid`=? and `_mid`=?";
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
} else {
|
||||
sql = "delete from t_channel_listener where `_cid`=? and `_mid`=?";
|
||||
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setString(index++, channelId);
|
||||
statement.setString(index++, listener);
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setString(index++, channelId);
|
||||
statement.setString(index++, listener);
|
||||
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement);
|
||||
int count = statement.executeUpdate();
|
||||
LOG.info("Update rows {}", count);
|
||||
}
|
||||
});
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, RDBS_Exception);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getUserChannels(String userId) {
|
||||
|
||||
@@ -49,6 +49,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -121,6 +122,8 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
private Lock mReadLock = mLock.readLock();
|
||||
private Lock mWriteLock = mLock.writeLock();
|
||||
|
||||
private Lock mUserSettingLock = new ReentrantLock();
|
||||
|
||||
private final DatabaseStore databaseStore;
|
||||
private ConcurrentHashMap<String, Long> userMaxPullSeq = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -138,11 +141,15 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
private long mFriendRequestDuration = 7 * 24 * 60 * 60 * 1000;
|
||||
private long mFriendRejectDuration = 30 * 24 * 60 * 60 * 1000;
|
||||
private long mFriendRequestExpiration = 7 * 24 * 60 * 60 * 1000;
|
||||
private boolean mFriendNewWelcomeMessage = true;
|
||||
private boolean mFriendRobotAutoAccept = true;
|
||||
|
||||
private boolean mMultiPlatformNotification = false;
|
||||
private boolean mMobileDefaultSilentWhenPCOnline = true;
|
||||
private boolean mDisableStrangerChat = false;
|
||||
private Set<String> mAllowStrangerChatSet = new HashSet<>();
|
||||
|
||||
private Set<String> mClientSignatureSet = new HashSet<>();
|
||||
private boolean mRejectEmptySignature = true;
|
||||
|
||||
private long mChatroomParticipantIdleTime = 900000;
|
||||
private boolean mChatroomRejoinWhenActive = true;
|
||||
@@ -165,8 +172,10 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
private boolean mGroupAllowClientCustomOperationNotification;
|
||||
private boolean mGroupAllowRobotCustomOperationNotification;
|
||||
private int mGroupVisibleQuitKickoffNotification;
|
||||
private int mGroupForbiddenClientOperation;
|
||||
private int mSyncDataPartSize = 0;
|
||||
private boolean keepDisplayNameWhenDestroyUser = true;
|
||||
private String mRecallForwardUrl = null;
|
||||
|
||||
private boolean mForwardMessageWithClientInfo = false;
|
||||
private boolean mRobotCallbackWithClientInfo = false;
|
||||
@@ -188,6 +197,27 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
IS_CHATROOM_MESSAGE_REMOTE_HISTORY_MESSAGE = "1".equals(m_Server.getConfig().getProperty(MESSAGE_Remote_Chatroom_History_Message, "1"));
|
||||
Constants.MAX_MESSAGE_QUEUE = Integer.parseInt(m_Server.getConfig().getProperty(MESSAGE_Max_Queue));
|
||||
|
||||
try {
|
||||
String signatureList = m_Server.getConfig().getProperty(BrokerConstants.CONNECT_CLIENT_SIGNATURE_LIST);
|
||||
if(!StringUtil.isNullOrEmptyAfterTrim(signatureList)) {
|
||||
signatureList = signatureList.replace(",", ",");
|
||||
for (String s : signatureList.split(",")) {
|
||||
mClientSignatureSet.add(s.trim());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
if(!mClientSignatureSet.isEmpty()) {
|
||||
mRejectEmptySignature = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.CONNECT_REJECT_EMPTY_SIGNATURE, "true"));
|
||||
} else {
|
||||
mRejectEmptySignature = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
try {
|
||||
mDisableStrangerChat = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Disable_Stranger_Chat));
|
||||
} catch (Exception e) {
|
||||
@@ -196,6 +226,18 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
printMissConfigLog(MESSAGE_Disable_Stranger_Chat, mDisableStrangerChat + "");
|
||||
}
|
||||
|
||||
try {
|
||||
String allowStrangerList = m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Allow_Stranger_Chat_List);
|
||||
if(!StringUtil.isNullOrEmptyAfterTrim(allowStrangerList)) {
|
||||
allowStrangerList = allowStrangerList.replace(",", ",");
|
||||
for (String s : allowStrangerList.split(",")) {
|
||||
mAllowStrangerChatSet.add(s.trim());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
mMultiPlatformNotification = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_PLATFROM_NOTIFICATION, "false"));
|
||||
} catch (Exception e) {
|
||||
@@ -256,14 +298,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
printMissConfigLog(FRIEND_Request_Expiration_Duration, mFriendRequestExpiration + "");
|
||||
}
|
||||
|
||||
try {
|
||||
mFriendNewWelcomeMessage = Boolean.parseBoolean(m_Server.getConfig().getProperty(FRIEND_New_Welcome_Message));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
printMissConfigLog(FRIEND_New_Welcome_Message, mFriendNewWelcomeMessage + "");
|
||||
}
|
||||
|
||||
try {
|
||||
mFriendRobotAutoAccept = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Request_Robot_Auto_Accept, "true"));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
try {
|
||||
mChatroomRejoinWhenActive = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.CHATROOM_Rejoin_When_Active));
|
||||
@@ -430,6 +469,21 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
String s = server.getConfig().getProperty(GROUP_Forbidden_Client_Operation, null);
|
||||
if(!StringUtil.isNullOrEmptyAfterTrim(s)) {
|
||||
s = s.toLowerCase();
|
||||
if(s.startsWith("0x")) {
|
||||
s = s.substring(2);
|
||||
mGroupForbiddenClientOperation = Integer.parseInt(s, 16);
|
||||
} else {
|
||||
mGroupForbiddenClientOperation = Integer.parseInt(s);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
LOG.error("Invalid group.forbidden_client_operation {}", server.getConfig().getProperty(GROUP_Forbidden_Client_Operation, null));
|
||||
}
|
||||
|
||||
try {
|
||||
mSyncDataPartSize = Integer.parseInt(server.getConfig().getProperty(SYNC_Data_Part_Size, "0"));
|
||||
} catch (Exception e) {
|
||||
@@ -472,7 +526,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
try {
|
||||
mRecallForwardUrl = server.getConfig().getProperty(BrokerConstants.MESSAGE_RecallMsg_Forward_Url);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void printMissConfigLog(String config, String defaultValue) {
|
||||
@@ -540,11 +598,16 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
if (type == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
notifyReceivers.add(fromUser);
|
||||
notifyReceivers.add(message.getConversation().getTarget());
|
||||
if(message.getToCount() > 0) {
|
||||
if(message.getToList().contains(message.getConversation().getTarget())) {
|
||||
notifyReceivers.add(message.getConversation().getTarget());
|
||||
}
|
||||
} else {
|
||||
notifyReceivers.add(message.getConversation().getTarget());
|
||||
}
|
||||
pullType = ProtoConstants.PullType.Pull_Normal;
|
||||
} else if (type == ProtoConstants.ConversationType.ConversationType_Group) {
|
||||
notifyReceivers.add(fromUser);
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(message.getToUser())) {
|
||||
notifyReceivers.add(message.getToUser());
|
||||
} else if(message.getToList()!=null && !message.getToList().isEmpty()) {
|
||||
@@ -570,9 +633,6 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//如果是群助手的消息,返回pull type group,否则返回normal
|
||||
//群助手还没有实现
|
||||
pullType = ProtoConstants.PullType.Pull_Normal;
|
||||
} else if (type == ProtoConstants.ConversationType.ConversationType_ChatRoom) {
|
||||
boolean isDirect = !StringUtil.isNullOrEmpty(message.getToUser());
|
||||
@@ -778,6 +838,10 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
mReadLock.unlock();
|
||||
}
|
||||
|
||||
if(current == 0) {
|
||||
current = 2;
|
||||
head = 2;
|
||||
}
|
||||
builder.setCurrent(current);
|
||||
builder.setHead(head);
|
||||
return builder.build();
|
||||
@@ -931,7 +995,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
messageSeq = maxPullSeq + 1;
|
||||
}
|
||||
|
||||
if (messageSeq == 0) {
|
||||
if (messageSeq < messageId) {
|
||||
messageSeq = messageId;
|
||||
}
|
||||
|
||||
@@ -943,7 +1007,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
databaseStore.persistUserMessage(user, messageId, messageSeq, conversationType, target, line, directing, messageContentType);
|
||||
databaseStore.persistUserMessage(user, sender, messageId, messageSeq, conversationType, target, line, directing, messageContentType);
|
||||
return messageSeq;
|
||||
}
|
||||
|
||||
@@ -1267,6 +1331,9 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
int maxCount = Integer.MAX_VALUE;
|
||||
|
||||
if (!isAdmin) {
|
||||
if (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
boolean isMember = false;
|
||||
boolean isManager = false;
|
||||
WFCMessage.GroupMember gm = getGroupMember(groupId, operator);
|
||||
@@ -1407,18 +1474,22 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
void removeFavGroup(String groupId, List<String> memberIds) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
|
||||
databaseStore.removeFavGroup(groupId, memberIds);
|
||||
|
||||
for (String member : memberIds) {
|
||||
userSettingMap.remove(member);
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
for (String member : memberIds) {
|
||||
userSettingMap.remove(member);
|
||||
}
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode quitGroup(String operator, String groupId) {
|
||||
public ErrorCode quitGroup(String operator, String groupId, boolean admin) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);
|
||||
|
||||
@@ -1438,6 +1509,10 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
|
||||
if(!admin && groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if (groupInfo.getType() != ProtoConstants.GroupType.GroupType_Free && groupInfo.getOwner() != null && groupInfo.getOwner().equals(operator)) {
|
||||
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);
|
||||
Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);
|
||||
@@ -1480,7 +1555,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
int[] removedCount = new int[1];
|
||||
for (String groupId : groupIds) {
|
||||
removedCount[0] = 0;
|
||||
ErrorCode errorCode = quitGroup(userId, groupId);
|
||||
ErrorCode errorCode = quitGroup(userId, groupId, true);
|
||||
LOG.info("clear user {} group {} result {}", userId, groupId, errorCode);
|
||||
}
|
||||
}
|
||||
@@ -1488,13 +1563,17 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
private void removeGroupUserSettings(String groupId, List<String> users) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
|
||||
databaseStore.removeGroupUserSettings(groupId, users);
|
||||
for (String userId:users) {
|
||||
userSettingMap.remove(userId);
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
for (String userId:users) {
|
||||
userSettingMap.remove(userId);
|
||||
}
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1512,6 +1591,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
if (!isAdmin && (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Free ||
|
||||
groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization ||
|
||||
(groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal)
|
||||
&& (groupInfo.getOwner() == null || !groupInfo.getOwner().equals(operator)))) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
@@ -1555,13 +1635,21 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
if (!isAdmin) {
|
||||
if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted) {
|
||||
if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Organization && modifyType != Modify_Group_Extra && modifyType != Modify_Group_Mute && modifyType != Modify_Group_PrivateChat) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
WFCMessage.GroupMember gm = getGroupMember(groupId, operator);
|
||||
if (gm == null || gm.getType() == GroupMemberType_Removed) {
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_GROUP;
|
||||
}
|
||||
|
||||
if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted || oldInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {
|
||||
boolean isAllow = false;
|
||||
if ((oldInfo.getOwner() != null && oldInfo.getOwner().equals(operator))) {
|
||||
isAllow = true;
|
||||
} else {
|
||||
WFCMessage.GroupMember gm = getGroupMember(groupId, operator);
|
||||
if (gm != null && gm.getType() == GroupMemberType_Manager) {
|
||||
if (gm.getType() == GroupMemberType_Manager) {
|
||||
isAllow = true;
|
||||
}
|
||||
}
|
||||
@@ -1572,9 +1660,8 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Normal) {
|
||||
if (!operator.equals(oldInfo.getOwner())) {
|
||||
WFCMessage.GroupMember gm = getGroupMember(groupId, operator);
|
||||
boolean isManager = false;
|
||||
if (gm != null && gm.getType() == GroupMemberType_Manager) {
|
||||
if (gm.getType() == GroupMemberType_Manager) {
|
||||
isManager = true;
|
||||
}
|
||||
if (!isManager && modifyType != Modify_Group_Name && modifyType != Modify_Group_Portrait && modifyType != Modify_Group_Extra) {
|
||||
@@ -1668,12 +1755,12 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
}
|
||||
|
||||
if (operatorMember == null) {
|
||||
if (operatorMember == null || operatorMember.getType() == GroupMemberType_Removed) {
|
||||
LOG.error("Modify group member alias error, the operator {} is not in group", operator);
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_GROUP;
|
||||
}
|
||||
|
||||
if (targetMember == null) {
|
||||
if (targetMember == null || targetMember.getType() == GroupMemberType_Removed) {
|
||||
LOG.error("Modify group member alias error, the member {} is not in group", memberId);
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_GROUP;
|
||||
}
|
||||
@@ -1797,7 +1884,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests) {
|
||||
public List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests, String fromUser, boolean isAdmin) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);
|
||||
ArrayList<WFCMessage.GroupInfo> out = new ArrayList<>();
|
||||
@@ -1811,6 +1898,14 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
if (groupInfo != null && groupInfo.getUpdateDt() > request.getUpdateDt()) {
|
||||
if(!isAdmin && !StringUtil.isNullOrEmpty(fromUser)) {
|
||||
WFCMessage.GroupMember gm = getGroupMember(groupInfo.getTargetId(), fromUser);
|
||||
if(gm == null) {
|
||||
groupInfo = groupInfo.toBuilder().setMemberUpdateDt(-1).build();
|
||||
} else if(gm.getType() == GroupMemberType_Removed) {
|
||||
groupInfo = groupInfo.toBuilder().setMemberUpdateDt(-groupInfo.getMemberUpdateDt()).build();
|
||||
}
|
||||
}
|
||||
out.add(groupInfo);
|
||||
}
|
||||
}
|
||||
@@ -1832,6 +1927,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return databaseStore.getUserGroupIds(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getCommonGroupIds(String userId1, String userId2) {
|
||||
return databaseStore.getCommonGroupIds(userId1, userId2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode getGroupMembers(String fromUser, String groupId, long maxDt, List<WFCMessage.GroupMember> members) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
@@ -1916,6 +2016,10 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if (!isAdmin && groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
//check the new owner is in member list? is that necessary?
|
||||
long updateDt = System.currentTimeMillis();
|
||||
groupInfo = groupInfo.toBuilder().setOwner(newOwner).setUpdateDt(updateDt).setMemberUpdateDt(updateDt).build();
|
||||
@@ -2085,9 +2189,10 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
if (isAdmin) {
|
||||
canRecall = true;
|
||||
}
|
||||
if (!isAdmin && message.getFromUser().equals(operatorId)) {
|
||||
boolean isExpired = false;
|
||||
if (!canRecall && message.getFromUser().equals(operatorId)) {
|
||||
if (now - message.getServerTimestamp() > mRecallTimeLimit * 1000) {
|
||||
return ErrorCode.ERROR_CODE_RECALL_TIME_EXPIRED;
|
||||
isExpired = true;
|
||||
} else {
|
||||
canRecall = true;
|
||||
}
|
||||
@@ -2104,17 +2209,26 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
canRecall = true;
|
||||
}
|
||||
|
||||
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);
|
||||
Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());
|
||||
if (members == null || members.size() == 0) {
|
||||
members = loadGroupMemberFromDB(hzInstance, message.getConversation().getTarget());
|
||||
}
|
||||
for (WFCMessage.GroupMember member : members) {
|
||||
if (member.getMemberId().equals(operatorId)) {
|
||||
if (member.getType() == GroupMemberType_Manager || member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Owner) {
|
||||
canRecall = true;
|
||||
if(!canRecall && !message.getFromUser().equals(operatorId)) {
|
||||
boolean isOperatorManager = false;
|
||||
int senderType = GroupMemberType_Normal;
|
||||
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);
|
||||
Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());
|
||||
if (members == null || members.size() == 0) {
|
||||
members = loadGroupMemberFromDB(hzInstance, message.getConversation().getTarget());
|
||||
}
|
||||
for (WFCMessage.GroupMember member : members) {
|
||||
if (member.getMemberId().equals(operatorId)) {
|
||||
if (member.getType() == GroupMemberType_Manager || member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Owner) {
|
||||
isOperatorManager = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if(member.getMemberId().equals(message.getFromUser())) {
|
||||
senderType = member.getType();
|
||||
}
|
||||
}
|
||||
if(isOperatorManager && senderType != GroupMemberType_Manager && senderType != GroupMemberType_Owner) {
|
||||
canRecall = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2126,13 +2240,30 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
if (!canRecall) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
if(isExpired) {
|
||||
return ErrorCode.ERROR_CODE_RECALL_TIME_EXPIRED;
|
||||
} else {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if(message.getContent().getType() == 80) {
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
if(!StringUtil.isNullOrEmpty(mRecallForwardUrl)) {
|
||||
OutputRecallMessageData event = new OutputRecallMessageData(OutputMessageData.fromProtoMessage(message, null), operatorId, System.currentTimeMillis(), isAdmin);
|
||||
m_Server.getCallbackScheduler().execute(() -> {
|
||||
try {
|
||||
HttpUtils.httpJsonPost(mRecallForwardUrl, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Forward_Recall_Callback);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("s", message.getFromUser());
|
||||
json.put("ts", message.getServerTimestamp());
|
||||
@@ -2386,6 +2517,28 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOnlineValueEqual(WFCMessage.UserSettingEntry pcentry, String newValue) {
|
||||
if(pcentry == null) {
|
||||
return StringUtil.isNullOrEmpty(newValue);
|
||||
}
|
||||
|
||||
String oldValue = pcentry.getValue();
|
||||
if(StringUtil.isNullOrEmpty(oldValue) && StringUtil.isNullOrEmpty(newValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(StringUtil.isNullOrEmpty(oldValue) || StringUtil.isNullOrEmpty(newValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] ssOld = oldValue.split("\\|");
|
||||
String[] ssNew = newValue.split("\\|");
|
||||
if(ssOld.length != 4 || ssNew.length != 4 || !ssOld[1].equals(ssNew[1]) || !ssOld[2].equals(ssNew[2]) || !ssOld[3].equals(ssNew[3])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserOnlineSetting(MemorySessionStore.Session session, boolean online) {
|
||||
if(!mMultiPlatformNotification) {
|
||||
@@ -2417,14 +2570,8 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
WFCMessage.UserSettingEntry pcentry = getUserSetting(session.getUsername(), kUserSettingPCOnline, "PC");
|
||||
if (pcValue != null) {
|
||||
if (pcentry == null || StringUtil.isNullOrEmpty(pcentry.getValue())) {
|
||||
updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey("PC").setValue(pcValue).build(), session.clientID);
|
||||
}
|
||||
} else {
|
||||
if (pcentry != null && !StringUtil.isNullOrEmpty(pcentry.getValue())) {
|
||||
updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey("PC").setValue("").build(), session.clientID);
|
||||
}
|
||||
if (!isOnlineValueEqual(pcentry, pcValue)) {
|
||||
updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey("PC").setValue(pcValue==null?"":pcValue).build(), session.clientID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2780,6 +2927,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
|
||||
if (mDisableStrangerChat) {
|
||||
//在禁止私聊时,是否是允许私聊的用户id
|
||||
if(mAllowStrangerChatSet.contains(targetUser)) {
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
//在禁止私聊时,允许机器人,物联网设备及管理员进行私聊。
|
||||
IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);
|
||||
WFCMessage.User target = mUserMap.get(targetUser);
|
||||
@@ -3081,7 +3233,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
friendsMap.remove(userId);
|
||||
friendsMap.remove(request.getTargetUid());
|
||||
|
||||
callbackRelationEvent(userId, request.getTargetUid(), 0, "" + request.getStatus());
|
||||
callbackRelationEvent(userId, request.getTargetUid(), 0, request.getStatus() == 0?"1":"0");
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -3347,7 +3499,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
private String ensureSecretLength(String secret) {
|
||||
while ( secret.length() < 16) {
|
||||
while ( secret.length() < AES.keyLen) {
|
||||
secret += "w";
|
||||
secret += secret;
|
||||
}
|
||||
@@ -3363,10 +3515,12 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
if(robotData != null && !StringUtil.isNullOrEmpty(robotData.getCallback()) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {
|
||||
try {
|
||||
URL url = new URL(robotData.getCallback());
|
||||
if(url.getHost().equals(host)) {
|
||||
if(url.getHost() == null) {
|
||||
LOG.error("get application auth code error, application callback is invalid url");
|
||||
} else if(url.getHost().equals(host)) {
|
||||
secret = robotData.getSecret();
|
||||
} else {
|
||||
LOG.warn("get application auth code error, request host is not the same host with callback host");
|
||||
LOG.error("get application auth code error, request host is not the same host with callback host");
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
@@ -3387,10 +3541,12 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
if(channelData != null && !StringUtil.isNullOrEmpty(channelData.getCallback()) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {
|
||||
try {
|
||||
URL url = new URL(channelData.getCallback());
|
||||
if(url.getHost().equals(host)) {
|
||||
if(url.getHost() == null) {
|
||||
LOG.error("get application auth code error, application callback is invalid url");
|
||||
} else if(url.getHost().equals(host)) {
|
||||
secret = channelData.getSecret();
|
||||
} else {
|
||||
LOG.warn("get application auth code error, request host is not the same host with callback host");
|
||||
LOG.error("get application auth code error, request host is not the same host with callback host");
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
@@ -3496,11 +3652,6 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return ErrorCode.ERROR_CODE_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNewFriendWelcomeMessage() {
|
||||
return mFriendNewWelcomeMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode deleteFriend(String userId, String friendUid, long[] head) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
@@ -3550,9 +3701,15 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
IMap<String, WFCMessage.GroupInfo> mGroups = hzInstance.getMap(GROUPS_MAP);
|
||||
IMap<String, WFCMessage.ChannelInfo> mChannels = hzInstance.getMap(CHANNELS);
|
||||
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
Collection<WFCMessage.UserSettingEntry> entries;
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
}
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
|
||||
ErrorCode ec = ErrorCode.ERROR_CODE_NOT_MODIFIED;
|
||||
@@ -3631,17 +3788,22 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
}
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
}
|
||||
|
||||
if (entries != null) {
|
||||
for (WFCMessage.UserSettingEntry entry : entries) {
|
||||
if (entry.getScope() == scope && (key== null || key.equals(entry.getKey()))) {
|
||||
return entry;
|
||||
if (entries != null) {
|
||||
for (WFCMessage.UserSettingEntry entry : entries) {
|
||||
if (entry.getScope() == scope && (key== null || key.equals(entry.getKey()))) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -3652,19 +3814,25 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
}
|
||||
List<WFCMessage.UserSettingEntry> result;
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
}
|
||||
|
||||
List<WFCMessage.UserSettingEntry> result = new ArrayList<>();
|
||||
if (entries != null) {
|
||||
for (WFCMessage.UserSettingEntry entry : entries
|
||||
) {
|
||||
if (entry.getScope() == scope) {
|
||||
result.add(entry);
|
||||
result = new ArrayList<>();
|
||||
if (entries != null) {
|
||||
for (WFCMessage.UserSettingEntry entry : entries
|
||||
) {
|
||||
if (entry.getScope() == scope) {
|
||||
result.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3675,28 +3843,34 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
if (entries == null) {
|
||||
entries = new ArrayList<>();
|
||||
long updateDt = 0;
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
|
||||
if (entries == null || entries.size() == 0) {
|
||||
entries = loadPersistedUserSettings(userId, userSettingMap);
|
||||
if (entries == null) {
|
||||
entries = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long updateDt = System.currentTimeMillis();
|
||||
WFCMessage.UserSettingEntry settingEntry = WFCMessage.UserSettingEntry.newBuilder().setScope(request.getScope()).setKey(request.getKey()).setValue(request.getValue()).setUpdateDt(updateDt).build();
|
||||
databaseStore.persistUserSetting(userId, settingEntry);
|
||||
updateDt = System.currentTimeMillis();
|
||||
WFCMessage.UserSettingEntry settingEntry = WFCMessage.UserSettingEntry.newBuilder().setScope(request.getScope()).setKey(request.getKey()).setValue(request.getValue()).setUpdateDt(updateDt).build();
|
||||
databaseStore.persistUserSetting(userId, settingEntry);
|
||||
|
||||
for (WFCMessage.UserSettingEntry entry : entries
|
||||
) {
|
||||
if (entry.getScope() == request.getScope() && entry.getKey().equals(request.getKey())) {
|
||||
userSettingMap.remove(userId, entry);
|
||||
userSettingMap.put(userId, settingEntry);
|
||||
break;
|
||||
for (WFCMessage.UserSettingEntry entry : entries
|
||||
) {
|
||||
if (entry.getScope() == request.getScope() && entry.getKey().equals(request.getKey())) {
|
||||
userSettingMap.remove(userId, entry);
|
||||
userSettingMap.put(userId, settingEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userSettingMap.put(userId, settingEntry);
|
||||
userSettingMap.put(userId, settingEntry);
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
|
||||
if(request.getScope() == UserSettingScope.kUserSettingConversationSilent) {
|
||||
int firstSplit = request.getKey().indexOf("-");
|
||||
@@ -3721,8 +3895,14 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
public void clearUserSettings(String userId) {
|
||||
databaseStore.clearUserSetting(userId);
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
userSettingMap.remove(userId);
|
||||
|
||||
try {
|
||||
mUserSettingLock.lock();
|
||||
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
|
||||
userSettingMap.remove(userId);
|
||||
} finally {
|
||||
mUserSettingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -4113,6 +4293,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return mGroupVisibleQuitKickoffNotification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupForbiddenClientOperation() {
|
||||
return mGroupForbiddenClientOperation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForwardMessageWithClientInfo() {
|
||||
return mForwardMessageWithClientInfo;
|
||||
@@ -4128,6 +4313,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return mChannelCallbackWithClientInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRobotAutoAcceptFriendRequest() {
|
||||
return mFriendRobotAutoAccept;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getClientForbiddenSendTypes() {
|
||||
return mForbiddenClientSendTypes;
|
||||
@@ -4253,6 +4443,34 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return UUIDGenerator.getUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSignature(String signature) {
|
||||
if(mClientSignatureSet.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(StringUtil.isNullOrEmptyAfterTrim(signature)) {
|
||||
if(mRejectEmptySignature) {
|
||||
LOG.info("Failed check signature, no signature");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if(mClientSignatureSet.contains(signature)) {
|
||||
return true;
|
||||
} else {
|
||||
LOG.info("Failed check signature, signature no matched");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existSignatures() {
|
||||
return !mClientSignatureSet.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeRetained(Topic topic, StoredMessage storedMessage) {
|
||||
LOG.debug("Store retained message for topic={}, CId={}", topic, storedMessage.getClientID());
|
||||
|
||||
@@ -415,7 +415,7 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
remove = true;
|
||||
}
|
||||
} else if(platform == ProtoConstants.Platform.Platform_OSX || platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_LINUX) {
|
||||
if (s.getPlatform() == ProtoConstants.Platform.Platform_OSX || s.getPlatform() == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_LINUX) {
|
||||
if (s.getPlatform() == ProtoConstants.Platform.Platform_OSX || s.getPlatform() == ProtoConstants.Platform.Platform_Windows || s.getPlatform() == ProtoConstants.Platform.Platform_LINUX) {
|
||||
remove = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -232,18 +232,6 @@ public class Server {
|
||||
handlers = Collections.emptyList();
|
||||
}
|
||||
DBUtil.init(config);
|
||||
String strKey = "0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F";
|
||||
String[] strs = strKey.split(",");
|
||||
if(strs.length != 16) {
|
||||
LOG.error("Key error, it length should be 16");
|
||||
}
|
||||
byte[] keys = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
keys[i] = (byte)(Integer.parseInt(strs[i].replace("0X", "").replace("0x", ""), 16));
|
||||
}
|
||||
|
||||
|
||||
AES.init(keys);
|
||||
|
||||
LOG.info("Starting Moquette Server. MQTT message interceptors={}", getInterceptorIds(handlers));
|
||||
|
||||
@@ -378,7 +366,7 @@ public class Server {
|
||||
LOG.info("Configuring embedded Hazelcast instance");
|
||||
|
||||
serverIp = getServerIp(config);
|
||||
String hzConfigPath = "config/hazelcast.xml";
|
||||
String hzConfigPath = System.getProperty("hazelcast.configuration", "config/hazelcast.xml");
|
||||
if (hzConfigPath != null) {
|
||||
boolean isHzConfigOnClasspath = this.getClass().getClassLoader().getResource(hzConfigPath) != null;
|
||||
Config hzconfig = isHzConfigOnClasspath
|
||||
@@ -393,9 +381,13 @@ public class Server {
|
||||
|
||||
longPort = config.getProperty(BrokerConstants.PORT_PROPERTY_NAME);
|
||||
shortPort = config.getProperty(BrokerConstants.HTTP_SERVER_PORT);
|
||||
boolean aes256 = Boolean.parseBoolean(config.getProperty(ENCRYPT_AES256, "false"));
|
||||
|
||||
MessageShardingUtil.setNodeId(1);
|
||||
Tokenor.setKey(config.getProperty(BrokerConstants.TOKEN_SECRET_KEY));
|
||||
|
||||
AES.useAes256(aes256);
|
||||
|
||||
String expirTimeStr = config.getProperty(TOKEN_EXPIRE_TIME);
|
||||
if (!StringUtil.isNullOrEmpty(expirTimeStr)) {
|
||||
try {
|
||||
|
||||
@@ -110,15 +110,16 @@ public interface IMessagesStore {
|
||||
WFCMessage.GroupInfo createGroup(String operator, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList, String memberExtra, boolean isAdmin);
|
||||
ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList, String extra);
|
||||
ErrorCode kickoffGroupMembers(String operator, boolean isAdmin, String groupId, List<String> memberList);
|
||||
ErrorCode quitGroup(String operator, String groupId);
|
||||
ErrorCode quitGroup(String operator, String groupId, boolean admin);
|
||||
void clearUserGroups(String userId);
|
||||
ErrorCode dismissGroup(String operator, String groupId, boolean isAdmin);
|
||||
ErrorCode modifyGroupInfo(String operator, String groupId, int modifyType, String value, boolean isAdmin);
|
||||
ErrorCode modifyGroupMemberAlias(String operator, String groupId, String alias, String memberId, boolean isAdmin);
|
||||
ErrorCode modifyGroupMemberExtra(String operator, String groupId, String extra, String memberId, boolean isAdmin);
|
||||
List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests);
|
||||
List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests, String fromUser, boolean isAdmin);
|
||||
WFCMessage.GroupInfo getGroupInfo(String groupId);
|
||||
Set<String> getUserGroupIds(String userId);
|
||||
Set<String> getCommonGroupIds(String userId1, String userId2);
|
||||
ErrorCode getGroupMembers(String fromUser, String groupId, long maxDt, List<WFCMessage.GroupMember> members);
|
||||
WFCMessage.GroupMember getGroupMember(String groupId, String memberId);
|
||||
ErrorCode transferGroup(String operator, String groupId, String newOwner, boolean isAdmin);
|
||||
@@ -179,7 +180,6 @@ public interface IMessagesStore {
|
||||
|
||||
ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin);
|
||||
ErrorCode handleFriendRequest(String userId, WFCMessage.HandleFriendRequest request, WFCMessage.Message.Builder msgBuilder, long[] heads, boolean isAdmin);
|
||||
boolean isNewFriendWelcomeMessage();
|
||||
ErrorCode deleteFriend(String userId, String friendUid, long[] head);
|
||||
ErrorCode blackUserRequest(String fromUser, String targetUserId, int status, long[] head);
|
||||
FriendData getFriendData(String fromUser, String targetUserId);
|
||||
@@ -233,10 +233,14 @@ public interface IMessagesStore {
|
||||
boolean isAllowRobotCustomGroupNotification();
|
||||
int getVisibleQuitKickoffNotification();
|
||||
|
||||
int getGroupForbiddenClientOperation();
|
||||
|
||||
boolean isForwardMessageWithClientInfo();
|
||||
boolean isRobotCallbackWithClientInfo();
|
||||
boolean isChannelCallbackWithClientInfo();
|
||||
|
||||
boolean isRobotAutoAcceptFriendRequest();
|
||||
|
||||
List<Integer> getClientForbiddenSendTypes();
|
||||
List<Integer> getBlackListExceptionTypes();
|
||||
List<Integer> getGroupMuteExceptionTypes();
|
||||
@@ -249,6 +253,9 @@ public interface IMessagesStore {
|
||||
|
||||
//使用了数据库,会比较慢,仅能用户用户/群组等id的生成
|
||||
String getShortUUID();
|
||||
|
||||
boolean checkSignature(String signature);
|
||||
boolean existSignatures();
|
||||
/**
|
||||
* Used to initialize all persistent store structures
|
||||
*/
|
||||
|
||||
@@ -652,6 +652,8 @@ public class MessagesPublisher {
|
||||
pushContent = "[文件]";
|
||||
} else if(type == ProtoConstants.ContentType.Sticker) {
|
||||
pushContent = "[表情]";
|
||||
} else if (type == ProtoConstants.ContentType.Name_Card) {
|
||||
pushContent = "[名片]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import win.liyufan.im.HttpUtils;
|
||||
import win.liyufan.im.IMTopic;
|
||||
import win.liyufan.im.Utility;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -107,7 +108,7 @@ public class ProtocolProcessor {
|
||||
ConnectionDescriptor descriptor = connectionDescriptors.getConnection(session.getClientID());
|
||||
try {
|
||||
if (descriptor != null) {
|
||||
processDisconnect(descriptor.getChannel(), true, false);
|
||||
processDisconnect(descriptor.getChannel(), false, false);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
@@ -339,6 +340,24 @@ public class ProtocolProcessor {
|
||||
failedCredentials(channel);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(session.getPlatform() == ProtoConstants.Platform.Platform_Android || session.getPlatform() == ProtoConstants.Platform.Platform_APad) {
|
||||
byte[] signature = msg.payload().signatureInBytes();
|
||||
String basedSign = null;
|
||||
if (signature != null && signature.length > 0) {
|
||||
signature = AES.AESDecrypt(signature, session.getSecret(), true);
|
||||
}
|
||||
if (signature != null && signature.length > 0) {
|
||||
basedSign = Base64.getEncoder().encodeToString(signature);
|
||||
}
|
||||
|
||||
if (!m_messagesStore.checkSignature(basedSign)) {
|
||||
LOG.error("Bad signature of session <{}, {}>", session.getUsername(), session.getClientID());
|
||||
failedBadSignature(channel);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
session.setMqttVersion(mqttVersion);
|
||||
} else {
|
||||
LOG.error("Client didn't supply any password and MQTT anonymous mode is disabled CId={}", clientId);
|
||||
@@ -446,6 +465,11 @@ public class ProtocolProcessor {
|
||||
LOG.info("Client {} failed to connect with bad username or password.", session);
|
||||
}
|
||||
|
||||
private void failedBadSignature(Channel session) {
|
||||
session.writeAndFlush(connAck(CONNECTION_REFUSED_SIGNATURE_FAILURE));
|
||||
LOG.info("Client {} failed to connect with bad signature.", session);
|
||||
}
|
||||
|
||||
private void setIdleTime(ChannelPipeline pipeline, int idleTime) {
|
||||
if (pipeline.names().contains("idleStateHandler")) {
|
||||
pipeline.remove("idleStateHandler");
|
||||
@@ -584,8 +608,9 @@ public class ProtocolProcessor {
|
||||
channel.closeFuture();
|
||||
|
||||
//disconnect the session
|
||||
|
||||
m_sessionsStore.sessionForClient(clientID).disconnect(session.getUsername(), isDup, isRetain);
|
||||
if(session != null) {
|
||||
m_sessionsStore.sessionForClient(clientID).disconnect(session.getUsername(), isDup, isRetain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -626,12 +651,22 @@ public class ProtocolProcessor {
|
||||
if(connectionDescriptors.removeConnection(oldConnDescr)) {
|
||||
m_interceptor.notifyClientConnectionLost(clientID, username);
|
||||
}
|
||||
try {
|
||||
channel.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);
|
||||
if(connectionDescriptors.removeConnection(oldConnDescr)) {
|
||||
m_interceptor.notifyClientConnectionLost(clientID, username);
|
||||
}
|
||||
try {
|
||||
channel.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,6 +252,13 @@ public class Qos1PublishHandler extends QosPublishHandler {
|
||||
|
||||
MemorySessionStore.Session session = m_sessionStore.getSession(clientID);
|
||||
payloadContent = AES.AESDecrypt(payloadContent, session.getSecret(), true);
|
||||
if(payloadContent == null) {
|
||||
ByteBuf ackPayload = Unpooled.buffer();
|
||||
ackPayload.ensureWritable(1).writeByte(ERROR_CODE_INVALID_DATA.getCode());
|
||||
sendPubAck(clientID, messageID, ackPayload, ERROR_CODE_INVALID_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
imHandler(clientID, username, imtopic, payloadContent, (errorCode, ackPayload) -> sendPubAck(clientID, messageID, ackPayload, errorCode), ProtoConstants.RequestSourceType.Request_From_User);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public final class MqttConnectPayload {
|
||||
private final byte[] willMessage;
|
||||
private final String userName;
|
||||
private final byte[] password;
|
||||
private final byte[] signature;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link MqttConnectPayload#MqttConnectPayload(String,
|
||||
@@ -50,7 +51,7 @@ public final class MqttConnectPayload {
|
||||
willTopic,
|
||||
willMessage.getBytes(CharsetUtil.UTF_8),
|
||||
userName,
|
||||
password.getBytes(CharsetUtil.UTF_8));
|
||||
password.getBytes(CharsetUtil.UTF_8), null);
|
||||
}
|
||||
|
||||
public MqttConnectPayload(
|
||||
@@ -64,7 +65,7 @@ public final class MqttConnectPayload {
|
||||
willTopic,
|
||||
willMessage,
|
||||
userName,
|
||||
password);
|
||||
password, null);
|
||||
}
|
||||
|
||||
public MqttConnectPayload(
|
||||
@@ -73,13 +74,15 @@ public final class MqttConnectPayload {
|
||||
String willTopic,
|
||||
byte[] willMessage,
|
||||
String userName,
|
||||
byte[] password) {
|
||||
byte[] password,
|
||||
byte[] signature) {
|
||||
this.clientIdentifier = clientIdentifier;
|
||||
this.willProperties = MqttProperties.withEmptyDefaults(willProperties);
|
||||
this.willTopic = willTopic;
|
||||
this.willMessage = willMessage;
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public String clientIdentifier() {
|
||||
@@ -122,6 +125,10 @@ public final class MqttConnectPayload {
|
||||
return password;
|
||||
}
|
||||
|
||||
public byte[] signatureInBytes() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
|
||||
@@ -29,6 +29,7 @@ public enum MqttConnectReturnCode {
|
||||
CONNECTION_REFUSED_NOT_AUTHORIZED((byte) 0x05),
|
||||
CONNECTION_REFUSED_UNEXPECT_NODE((byte) 0X06),
|
||||
CONNECTION_REFUSED_SESSION_NOT_EXIST((byte) 0x07),
|
||||
CONNECTION_REFUSED_SIGNATURE_FAILURE((byte) 0x08),
|
||||
//MQTT 5 codes
|
||||
CONNECTION_REFUSED_UNSPECIFIED_ERROR((byte) 0x80),
|
||||
CONNECTION_REFUSED_MALFORMED_PACKET((byte) 0x81),
|
||||
|
||||
@@ -146,7 +146,7 @@ public final class MqttDecoder extends ReplayingDecoder<MqttDecoder.DecoderState
|
||||
* bytes for the remaining length.
|
||||
*
|
||||
* @see
|
||||
* https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180841
|
||||
* <a href="https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180841">...</a>
|
||||
*
|
||||
* @param buffer the buffer to decode from
|
||||
* @return the fixed header
|
||||
@@ -534,7 +534,7 @@ public final class MqttDecoder extends ReplayingDecoder<MqttDecoder.DecoderState
|
||||
|
||||
final MqttProperties willProperties;
|
||||
if (mqttConnectVariableHeader.isWillFlag()) {
|
||||
if (mqttVersion == MqttVersion.MQTT_5) {
|
||||
if (mqttVersion.protocolLevel() <= MqttVersion.MQTT_5.protocolLevel()) {
|
||||
final Result<MqttProperties> propertiesResult = decodeProperties(buffer);
|
||||
willProperties = propertiesResult.value;
|
||||
numberOfBytesConsumed += propertiesResult.numberOfBytesConsumed;
|
||||
@@ -550,6 +550,7 @@ public final class MqttDecoder extends ReplayingDecoder<MqttDecoder.DecoderState
|
||||
}
|
||||
Result<String> decodedUserName = null;
|
||||
byte[] decodedPassword = null;
|
||||
byte[] decodedSignature = null;
|
||||
if (mqttConnectVariableHeader.hasUserName()) {
|
||||
decodedUserName = decodeString(buffer);
|
||||
numberOfBytesConsumed += decodedUserName.numberOfBytesConsumed;
|
||||
@@ -558,6 +559,10 @@ public final class MqttDecoder extends ReplayingDecoder<MqttDecoder.DecoderState
|
||||
decodedPassword = decodeByteArray(buffer);
|
||||
numberOfBytesConsumed += decodedPassword.length + 2;
|
||||
}
|
||||
if (mqttConnectVariableHeader.isWillRetain()) {
|
||||
decodedSignature = decodeByteArray(buffer);
|
||||
numberOfBytesConsumed += decodedSignature.length + 2;
|
||||
}
|
||||
|
||||
final MqttConnectPayload mqttConnectPayload =
|
||||
new MqttConnectPayload(
|
||||
@@ -566,7 +571,9 @@ public final class MqttDecoder extends ReplayingDecoder<MqttDecoder.DecoderState
|
||||
decodedWillTopic != null ? decodedWillTopic.value : null,
|
||||
decodedWillMessage,
|
||||
decodedUserName != null ? decodedUserName.value : null,
|
||||
decodedPassword);
|
||||
decodedPassword,
|
||||
decodedSignature
|
||||
);
|
||||
return new Result<MqttConnectPayload>(mqttConnectPayload, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ public final class MqttMessageBuilders {
|
||||
keepAliveSecs,
|
||||
properties);
|
||||
MqttConnectPayload mqttConnectPayload =
|
||||
new MqttConnectPayload(clientId, willProperties, willTopic, willMessage, username, password);
|
||||
new MqttConnectPayload(clientId, willProperties, willTopic, willMessage, username, password, null);
|
||||
return new MqttConnectMessage(mqttFixedHeader, mqttConnectVariableHeader, mqttConnectPayload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.mchange.v2.c3p0.ComboPooledDataSource;
|
||||
import io.moquette.BrokerConstants;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.flywaydb.core.api.configuration.FlywayConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -50,6 +49,7 @@ public class DBUtil {
|
||||
|
||||
public static void init(IConfig config) {
|
||||
String embedDB = config.getProperty(BrokerConstants.EMBED_DB_PROPERTY_NAME);
|
||||
String h2dbPath = config.getProperty(BrokerConstants.H2DB_PATH, "./h2db/wfchat");
|
||||
boolean autoCleanMsgs = "true".equals(config.getProperty(BrokerConstants.DB_AUTO_CLEAN_HISTORY_MESSAGES));
|
||||
if (embedDB != null && embedDB.equals("1")) {
|
||||
IsEmbedDB = true;
|
||||
@@ -68,7 +68,7 @@ public class DBUtil {
|
||||
migrateLocation = "filesystem:./migrate/h2";
|
||||
comboPooledDataSource = new ComboPooledDataSource();
|
||||
|
||||
comboPooledDataSource.setJdbcUrl( "jdbc:h2:./h2db/wfchat;AUTO_SERVER=TRUE;MODE=MySQL" );
|
||||
comboPooledDataSource.setJdbcUrl( "jdbc:h2:" + h2dbPath + ";AUTO_SERVER=TRUE;MODE=MySQL" );
|
||||
comboPooledDataSource.setUser("SA");
|
||||
comboPooledDataSource.setPassword("SA");
|
||||
comboPooledDataSource.setMinPoolSize(5);
|
||||
|
||||
@@ -68,7 +68,9 @@ public class GitRepositoryState {
|
||||
public static GitRepositoryState getGitRepositoryState() throws IOException {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
InputStream inputStream = new FileInputStream("config/git.properties");
|
||||
String configPath = System.getProperty("wildfirechat.path", null);
|
||||
File f = new File(configPath, "config/git.properties");
|
||||
InputStream inputStream = new FileInputStream(f);
|
||||
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
|
||||
properties.load(bf);
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -50,7 +50,8 @@ public class HttpUtils {
|
||||
POST_TYPE_Channel_Message_Callback,
|
||||
POST_TYPE_Forward_Message_Callback,
|
||||
POST_TYPE_User_Online_Event_Callback,
|
||||
POST_TYPE_Server_Exception_Callback;
|
||||
POST_TYPE_Server_Exception_Callback,
|
||||
POST_TYPE_Forward_Recall_Callback;
|
||||
}
|
||||
|
||||
public static void httpJsonPost(String url, String jsonStr, HttpPostType postType) {
|
||||
@@ -87,8 +88,8 @@ public class HttpUtils {
|
||||
}
|
||||
System.out.println(logText);
|
||||
e.printStackTrace();
|
||||
LOG.info(logText);
|
||||
LOG.info("POST to {} with data {} failure", url, jsonStr);
|
||||
LOG.error(logText);
|
||||
LOG.error("POST to {} failed", url);
|
||||
if(httpCallback != null) {
|
||||
httpCallback.onFailure(-1, e.getMessage());
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package win.liyufan.im;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class I18n {
|
||||
private static ClassLoader Loader = null;
|
||||
static {
|
||||
String configPath = System.getProperty("wildfirechat.path", null);
|
||||
String resBundlePaht = "config/i18n";
|
||||
|
||||
File file = new File(configPath, resBundlePaht);
|
||||
URL[] urls = new URL[0];
|
||||
try {
|
||||
urls = new URL[]{file.toURI().toURL()};
|
||||
Loader = new URLClassLoader(urls);
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, ResourceBundle> bundleMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static String getString(String language, String key) {
|
||||
ResourceBundle bundle = bundleMap.get(language);
|
||||
|
||||
if (StringUtil.isNullOrEmpty(language)) language = "zh_CN";
|
||||
|
||||
if (bundle == null) {
|
||||
bundle = ResourceBundle.getBundle("messages", new Locale(language), Loader);
|
||||
bundleMap.put(language, bundle);
|
||||
}
|
||||
|
||||
try {
|
||||
return bundle.getString(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "糟糕,字符串 " + key + " 没有找到";
|
||||
}
|
||||
|
||||
public static void test() throws MalformedURLException {
|
||||
|
||||
// 设置定制的语言国家代码
|
||||
Locale locale1 = new Locale("zh");
|
||||
Locale locale2 = new Locale("en");
|
||||
ResourceBundle rb = ResourceBundle.getBundle("messages", locale1, Loader);
|
||||
|
||||
|
||||
|
||||
// 获得相应的key值
|
||||
String greeting = rb.getString("Above_Greeting_Message");
|
||||
String userInfo = rb.getString("Friend_Can_Start_Chat");
|
||||
|
||||
System.out.println(greeting);
|
||||
System.out.println(userInfo);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
test();
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,8 @@ public interface IMTopic {
|
||||
String GetGroupMemberTopic = "GPGM";
|
||||
String TransferGroupTopic = "GTG";
|
||||
String SetGroupManagerTopic = "GSM";
|
||||
String GetMyGroupsTopic = "GMGS";
|
||||
String GetCommonGroupsTopic = "GCGS";
|
||||
|
||||
String GetUserInfoTopic = "UPUI";
|
||||
String ModifyMyInfoTopic = "MMI";
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<Properties>
|
||||
<!--自定义一些常量,之后使用${变量名}引用-->
|
||||
<Property name="MSG_LOG_HOME">./logs</Property>
|
||||
<Property name="logFileName">test.log</Property>
|
||||
<property name="charset">UTF-8</property>
|
||||
<!--自定义的输出格式-->
|
||||
<property name="pattern">%d %-5p [%t] %C{2} (%F:%L) - %m%n</property>
|
||||
@@ -21,14 +20,14 @@
|
||||
|
||||
<RollingRandomAccessFile name="RollingFileInfo" immediateFlush="false"
|
||||
fileName="${MSG_LOG_HOME}/wildfirechat.log"
|
||||
filePattern="${MSG_LOG_HOME}/backup/wildfirechat.%d{yyyyMMddHH}.zip">
|
||||
filePattern="${MSG_LOG_HOME}/backup/wildfirechat.%d{yyyyMMddHHmm}.zip">
|
||||
<Filters>
|
||||
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</Filters>
|
||||
<PatternLayout pattern="${pattern}" />
|
||||
<Policies>
|
||||
<!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval="6" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate="true" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->
|
||||
<!-- <TimeBasedTriggeringPolicy interval="6" modulate="true"/>-->
|
||||
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
|
||||
<!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->
|
||||
<SizeBasedTriggeringPolicy size="100 MB"/>
|
||||
</Policies>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.95</version>
|
||||
<version>1.1.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ public interface APIPath {
|
||||
String Group_Get_Info = "/admin/group/get_info";
|
||||
String Group_Modify_Info = "/admin/group/modify";
|
||||
String Group_Member_List = "/admin/group/member/list";
|
||||
String Group_Member_Get = "/admin/group/member/get";
|
||||
String Group_Member_Add = "/admin/group/member/add";
|
||||
String Group_Member_Kickoff = "/admin/group/member/del";
|
||||
String Group_Member_Quit = "/admin/group/member/quit";
|
||||
@@ -77,6 +78,7 @@ public interface APIPath {
|
||||
String Get_User_Groups = "/admin/group/of_user";
|
||||
String Group_Set_Member_Alias = "/admin/group/member/set_alias";
|
||||
String Group_Set_Member_Extra = "/admin/group/member/set_extra";
|
||||
String Get_Common_Groups = "/admin/group/common_group";
|
||||
|
||||
String Create_Channel = "/admin/channel/create";
|
||||
String Destroy_Channel = "/admin/channel/destroy";
|
||||
@@ -89,9 +91,14 @@ public interface APIPath {
|
||||
String Health = "/admin/health";
|
||||
|
||||
String Conference_List = "/admin/conference/list";
|
||||
String Conference_Exist = "/admin/conference/exist";
|
||||
String Conference_List_Participant = "/admin/conference/list_participant";
|
||||
String Conference_Create = "/admin/conference/create";
|
||||
String Conference_Destroy = "/admin/conference/destroy";
|
||||
String Conference_Recording = "/admin/conference/recording";
|
||||
String Conference_Rtp_Forward = "/admin/conference/rtp_forward";
|
||||
String Conference_Stop_Rtp_Forward = "/admin/conference/stop_rtp_forward";
|
||||
String Conference_List_Rtp_Forward = "/admin/conference/list_rtp_forward";
|
||||
|
||||
String Channel_User_Info = "/channel/user_info";
|
||||
String Channel_Update_Profile = "/channel/update_profile";
|
||||
@@ -99,6 +106,7 @@ public interface APIPath {
|
||||
String Channel_Message_Send = "/channel/message/send";
|
||||
String Channel_Subscribe = "/channel/subscribe";
|
||||
String Channel_Subscriber_List = "/channel/subscriber_list";
|
||||
String Channel_Is_Subscriber = "/channel/is_subscriber";
|
||||
String Channel_Application_Get_UserInfo = "/channel/application/get_user_info";
|
||||
|
||||
String Robot_User_Info = "/robot/user_info";
|
||||
@@ -115,6 +123,7 @@ public interface APIPath {
|
||||
String Robot_Group_Dismiss = "/robot/group/del";
|
||||
String Robot_Group_Get_Info = "/robot/group/get_info";
|
||||
String Robot_Group_Member_List = "/robot/group/member/list";
|
||||
String Robot_Group_Member_Get = "/robot/group/member/get";
|
||||
String Robot_Group_Member_Kickoff = "/robot/group/member/del";
|
||||
String Robot_Group_Modify_Info = "/robot/group/modify";
|
||||
String Robot_Group_Set_Member_Alias = "/robot/group/member/set_alias";
|
||||
|
||||
@@ -48,6 +48,7 @@ public enum ErrorCode {
|
||||
ERROR_CODE_NOT_YOUR_LOCKED(26, "unload failure, not your lock"),
|
||||
ERROR_CODE_ROBOT_NO_TOKEN(27, "robot no token"),
|
||||
ERROR_CODE_WS_NOT_CONFIGURED_CORRECTLY(28, "ws not configured correctly"),
|
||||
ERROR_CODE_TIME_INCONSISTENT(30, "time inconsistent"),
|
||||
ERROR_CODE_CONFERENCE_ROOM_NOT_EXIST(60, "conference room not exist"),
|
||||
ERROR_CODE_CONFERENCE_SERVICE_NOT_AVAILABLE(61, "conference service not available"),
|
||||
|
||||
@@ -61,6 +62,8 @@ public enum ErrorCode {
|
||||
ERROR_CODE_SECRET_CHAT_MO_DISABLED(86, "origin side disable secret chat"),
|
||||
ERROR_CODE_SECRET_CHAT_MT_DISABLED(87, "target side disable secret chat"),
|
||||
|
||||
ERROR_CODE_CONFERENCE_ERROR(90, "Conference server response error"),
|
||||
|
||||
ERROR_CODE_FUNCTION_DISABLED(220, "function disabled"),
|
||||
|
||||
ERROR_CODE_CHANNEL_NO_EXIST(236, "channel no exist"),
|
||||
@@ -72,7 +75,7 @@ public enum ErrorCode {
|
||||
ERROR_CODE_SENSITIVE_MATCHED(242, "sensitive matched"),
|
||||
ERROR_CODE_SIGN_EXPIRED(243, "sign expired"),
|
||||
ERROR_CODE_AUTH_FAILURE(244, "auth failure"),
|
||||
ERROR_CODE_CLIENT_COUNT_OUT_OF_LIMIT(245, "client count out of limit"),
|
||||
ERROR_CODE_USER_BLOCKED(245, "user is blocked"),
|
||||
ERROR_CODE_IN_BLACK_LIST(246, "user in black list"),
|
||||
ERROR_CODE_FORBIDDEN_SEND_MSG(247, "forbidden send msg globally"),
|
||||
ERROR_CODE_NOT_RIGHT(248, "no right to operate"),
|
||||
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ArticlesContentBuilder extends MessageContentBuilder{
|
||||
public static class Article {
|
||||
public String id;
|
||||
public String cover;
|
||||
public String title;
|
||||
public String digest;
|
||||
public String url;
|
||||
public boolean readReport;
|
||||
}
|
||||
public Article topArticle;
|
||||
public List<Article> subArticles;
|
||||
|
||||
public static ArticlesContentBuilder newBuilder(String id, String cover, String title, String digest, String url, boolean readReport) {
|
||||
ArticlesContentBuilder builder = new ArticlesContentBuilder();
|
||||
builder.topArticle = new Article();
|
||||
builder.topArticle.id = id;
|
||||
builder.topArticle.cover = cover;
|
||||
builder.topArticle.title = title;
|
||||
builder.topArticle.digest = digest;
|
||||
builder.topArticle.url = url;
|
||||
builder.topArticle.readReport = readReport;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public ArticlesContentBuilder addSubArticle(String id, String cover, String title, String digest, String url, boolean readReport) {
|
||||
Article article = new Article();
|
||||
article.id = id;
|
||||
article.cover = cover;
|
||||
article.title = title;
|
||||
article.digest = digest;
|
||||
article.url = url;
|
||||
article.readReport = readReport;
|
||||
if(subArticles == null) {
|
||||
subArticles = new ArrayList<>();
|
||||
}
|
||||
subArticles.add(article);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static JSONObject toJSON(Article article) {
|
||||
JSONObject top = new JSONObject();
|
||||
if(!StringUtil.isNullOrEmpty(article.id))
|
||||
top.put("id", article.id);
|
||||
if(!StringUtil.isNullOrEmpty(article.cover))
|
||||
top.put("cover", article.cover);
|
||||
if(!StringUtil.isNullOrEmpty(article.title))
|
||||
top.put("title", article.title);
|
||||
if(!StringUtil.isNullOrEmpty(article.digest))
|
||||
top.put("digest", article.digest);
|
||||
if(!StringUtil.isNullOrEmpty(article.url))
|
||||
top.put("url", article.url);
|
||||
if(article.readReport)
|
||||
top.put("rr", article.readReport);
|
||||
return top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload build() {
|
||||
MessagePayload payload = encodeBase();
|
||||
payload.setType(ProtoConstants.ContentType.Articles);
|
||||
payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count);
|
||||
payload.setSearchableContent(topArticle.title);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("top", toJSON(topArticle));
|
||||
if(subArticles != null && !subArticles.isEmpty()) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
subArticles.forEach(article -> jsonArray.add(toJSON(article)));
|
||||
jsonObject.put("subArticles", jsonArray);
|
||||
}
|
||||
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8)));
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -13,16 +13,18 @@ public class ArticleContent {
|
||||
public String id;
|
||||
public String cover;
|
||||
public String title;
|
||||
public String digest;
|
||||
public String url;
|
||||
public boolean rr;
|
||||
|
||||
public Article() {
|
||||
}
|
||||
|
||||
public Article(String id, String cover, String title, String url, boolean rr) {
|
||||
public Article(String id, String cover, String title, String digest, String url, boolean rr) {
|
||||
this.id = id;
|
||||
this.cover = cover;
|
||||
this.title = title;
|
||||
this.digest = digest;
|
||||
this.url = url;
|
||||
this.rr = rr;
|
||||
}
|
||||
@@ -33,14 +35,14 @@ public class ArticleContent {
|
||||
public ArticleContent() {
|
||||
}
|
||||
|
||||
public ArticleContent(String id, String cover, String title, String url, boolean rr) {
|
||||
this.top = new Article(id, cover, title, url, rr);
|
||||
public ArticleContent(String id, String cover, String title, String digest, String url, boolean rr) {
|
||||
this.top = new Article(id, cover, title, digest, url, rr);
|
||||
}
|
||||
|
||||
public ArticleContent addSubArticle(String id, String cover, String title, String url, boolean rr) {
|
||||
public ArticleContent addSubArticle(String id, String cover, String title, String digest, String url, boolean rr) {
|
||||
if (subArticles == null)
|
||||
subArticles = new ArrayList<>();
|
||||
subArticles.add(new Article(id, cover, title, url, rr));
|
||||
subArticles.add(new Article(id, cover, title, digest, url, rr));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,5 +3,7 @@ package cn.wildfirechat.pojos;
|
||||
public class ConferenceLeaveEvent {
|
||||
public String userId;
|
||||
public String roomId;
|
||||
public boolean rejoin;
|
||||
public boolean kicked;
|
||||
public boolean screenSharing;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ public class InputCreateGroup extends InputGroupBase {
|
||||
if(group_info.max_member_count > 0) {
|
||||
groupInfoBuilder.setMaxMemberCount(group_info.max_member_count);
|
||||
}
|
||||
if(group_info.isSuper_group()) {
|
||||
groupInfoBuilder.setSuperGroup(1);
|
||||
}
|
||||
|
||||
groupBuilder.setGroupInfo(groupInfoBuilder);
|
||||
if(group.getMembers() != null) {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
public class InputGetGroupMember {
|
||||
private String groupId;
|
||||
private String memberId;
|
||||
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getMemberId() {
|
||||
return memberId;
|
||||
}
|
||||
|
||||
public void setMemberId(String memberId) {
|
||||
this.memberId = memberId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
public class OutputRecallMessageData {
|
||||
private OutputMessageData message;
|
||||
private String userId;
|
||||
private long timestamp;
|
||||
private boolean isAdmin;
|
||||
|
||||
public OutputRecallMessageData() {
|
||||
}
|
||||
|
||||
public OutputRecallMessageData(OutputMessageData message, String userId, long timestamp, boolean isAdmin) {
|
||||
this.message = message;
|
||||
this.userId = userId;
|
||||
this.timestamp = timestamp;
|
||||
this.isAdmin = isAdmin;
|
||||
}
|
||||
|
||||
public OutputMessageData getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(OutputMessageData message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public boolean isAdmin() {
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
public void setAdmin(boolean admin) {
|
||||
isAdmin = admin;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PojoConferenceParticipant {
|
||||
public static class Stream {
|
||||
public String type;
|
||||
public String mid;
|
||||
public String codec;
|
||||
}
|
||||
|
||||
public String userId;
|
||||
public boolean publishing;
|
||||
public List<Stream> streams;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
public class PojoConferenceRecording {
|
||||
public String roomId;
|
||||
public boolean recording;
|
||||
public boolean advance;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
public class PojoConferenceRtpForwardReq {
|
||||
public String roomId;
|
||||
public String publisherId;
|
||||
public String host;
|
||||
public int audioPort;
|
||||
public int audioPt;
|
||||
public long audioSSRC;
|
||||
public int videoPort;
|
||||
public int videoPt;
|
||||
public long videoSSRC;
|
||||
|
||||
public PojoConferenceRtpForwardReq() {
|
||||
}
|
||||
|
||||
public PojoConferenceRtpForwardReq(String roomId, String publisherId, String host, int audioPort, int audioPt, long audioSSRC, int videoPort, int videoPt, long videoSSRC) {
|
||||
this.roomId = roomId;
|
||||
this.publisherId = publisherId;
|
||||
this.host = host;
|
||||
this.audioPort = audioPort;
|
||||
this.audioPt = audioPt;
|
||||
this.audioSSRC = audioSSRC;
|
||||
this.videoPort = videoPort;
|
||||
this.videoPt = videoPt;
|
||||
this.videoSSRC = videoSSRC;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PojoConferenceRtpForwarders {
|
||||
public static class RtpForwarder {
|
||||
public static class RtpStream {
|
||||
public long streamId;
|
||||
public String type;
|
||||
public String host;
|
||||
public int port;
|
||||
public long ssrc;
|
||||
public int pt;
|
||||
}
|
||||
|
||||
public String publisherId;
|
||||
public List<RtpStream> streams;
|
||||
}
|
||||
public String roomId;
|
||||
public List<RtpForwarder> forwarders;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
public class PojoConferenceStopRtpForwardReq {
|
||||
public String roomId;
|
||||
public String publisherId;
|
||||
public long streamId;
|
||||
|
||||
public PojoConferenceStopRtpForwardReq() {
|
||||
}
|
||||
|
||||
public PojoConferenceStopRtpForwardReq(String roomId, String publisherId, long streamId) {
|
||||
this.roomId = roomId;
|
||||
this.publisherId = publisherId;
|
||||
this.streamId = streamId;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public class PojoGroupInfo {
|
||||
int searchable;
|
||||
int max_member_count;
|
||||
int history_message;
|
||||
boolean super_group;
|
||||
|
||||
public String getTarget_id() {
|
||||
return target_id;
|
||||
@@ -117,4 +118,12 @@ public class PojoGroupInfo {
|
||||
public void setHistory_message(int history_message) {
|
||||
this.history_message = history_message;
|
||||
}
|
||||
|
||||
public boolean isSuper_group() {
|
||||
return super_group;
|
||||
}
|
||||
|
||||
public void setSuper_group(boolean super_group) {
|
||||
this.super_group = super_group;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ public class ProtoConstants {
|
||||
int ConversationType_ChatRoom = 2;
|
||||
int ConversationType_Channel = 3;
|
||||
int ConversationType_Things = 4;
|
||||
int ConversationType_SecretChat = 5;
|
||||
}
|
||||
|
||||
//message GroupInfo -> type
|
||||
@@ -19,6 +20,8 @@ public class ProtoConstants {
|
||||
int GroupType_Free = 1;
|
||||
//member can only quit, owner can do all the operations
|
||||
int GroupType_Restricted = 2;
|
||||
//member can not do anything, server api manage the group
|
||||
int GroupType_Organization = 3;
|
||||
}
|
||||
|
||||
//message GroupMember -> type
|
||||
@@ -290,6 +293,34 @@ public class ProtoConstants {
|
||||
int ApplicationType_Admin = 2;
|
||||
}
|
||||
|
||||
//禁止客户端群操作。
|
||||
// 第1位是禁止创建群组,
|
||||
// 第2位是禁止销毁群组,
|
||||
// 3位禁止加入群,
|
||||
// 4位禁止退出群,
|
||||
// 5位禁止邀请群成员,
|
||||
// 6位禁止移出群成员,
|
||||
// 7位禁止转移群
|
||||
// 8位禁止设置群管理员
|
||||
// 9位禁止允许群成员(专业版支持),
|
||||
// 10位禁止群禁言
|
||||
// 11位禁止修改群组信息,
|
||||
// 12位禁止群成员禁言(专业版支持)
|
||||
public interface ForbiddenClientGroupOperationMask {
|
||||
int Forbidden_Create_Group = 0x01;
|
||||
int Forbidden_Dismiss_Group = 0x02;
|
||||
int Forbidden_Join_Group = 0x04;
|
||||
int Forbidden_Quit_Group = 0x08;
|
||||
int Forbidden_Invite_Group_Member = 0x10;
|
||||
int Forbidden_Kickoff_Group_Member = 0x20;
|
||||
int Forbidden_Transfer_Group = 0x40;
|
||||
int Forbidden_Set_Group_Manage = 0x80;
|
||||
int Forbidden_Allow_Group_Member = 0x100;
|
||||
int Forbidden_Mute_Group = 0x200;
|
||||
int Forbidden_Modify_Group_Info = 0x400;
|
||||
int Forbidden_Mute_Group_Member = 0x800;
|
||||
}
|
||||
|
||||
public static final int MESSAGE_CONTENT_TYPE_CREATE_GROUP = 104;
|
||||
public static final int MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER = 105;
|
||||
public static final int MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER = 106;
|
||||
|
||||
@@ -1641,6 +1641,16 @@ public final class WFCMessage {
|
||||
* <code>optional int32 history_message = 15;</code>
|
||||
*/
|
||||
int getHistoryMessage();
|
||||
|
||||
// optional int32 super_group = 16;
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
boolean hasSuperGroup();
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
int getSuperGroup();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code GroupInfo}
|
||||
@@ -1768,6 +1778,11 @@ public final class WFCMessage {
|
||||
historyMessage_ = input.readInt32();
|
||||
break;
|
||||
}
|
||||
case 128: {
|
||||
bitField0_ |= 0x00008000;
|
||||
superGroup_ = input.readInt32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
@@ -2183,6 +2198,22 @@ public final class WFCMessage {
|
||||
return historyMessage_;
|
||||
}
|
||||
|
||||
// optional int32 super_group = 16;
|
||||
public static final int SUPER_GROUP_FIELD_NUMBER = 16;
|
||||
private int superGroup_;
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
public boolean hasSuperGroup() {
|
||||
return ((bitField0_ & 0x00008000) == 0x00008000);
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
public int getSuperGroup() {
|
||||
return superGroup_;
|
||||
}
|
||||
|
||||
private void initFields() {
|
||||
targetId_ = "";
|
||||
name_ = "";
|
||||
@@ -2199,6 +2230,7 @@ public final class WFCMessage {
|
||||
searchable_ = 0;
|
||||
maxMemberCount_ = 0;
|
||||
historyMessage_ = 0;
|
||||
superGroup_ = 0;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
public final boolean isInitialized() {
|
||||
@@ -2265,6 +2297,9 @@ public final class WFCMessage {
|
||||
if (((bitField0_ & 0x00004000) == 0x00004000)) {
|
||||
output.writeInt32(15, historyMessage_);
|
||||
}
|
||||
if (((bitField0_ & 0x00008000) == 0x00008000)) {
|
||||
output.writeInt32(16, superGroup_);
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
@@ -2334,6 +2369,10 @@ public final class WFCMessage {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeInt32Size(15, historyMessage_);
|
||||
}
|
||||
if (((bitField0_ & 0x00008000) == 0x00008000)) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeInt32Size(16, superGroup_);
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@@ -2480,6 +2519,8 @@ public final class WFCMessage {
|
||||
bitField0_ = (bitField0_ & ~0x00002000);
|
||||
historyMessage_ = 0;
|
||||
bitField0_ = (bitField0_ & ~0x00004000);
|
||||
superGroup_ = 0;
|
||||
bitField0_ = (bitField0_ & ~0x00008000);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2568,6 +2609,10 @@ public final class WFCMessage {
|
||||
to_bitField0_ |= 0x00004000;
|
||||
}
|
||||
result.historyMessage_ = historyMessage_;
|
||||
if (((from_bitField0_ & 0x00008000) == 0x00008000)) {
|
||||
to_bitField0_ |= 0x00008000;
|
||||
}
|
||||
result.superGroup_ = superGroup_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
onBuilt();
|
||||
return result;
|
||||
@@ -2639,6 +2684,9 @@ public final class WFCMessage {
|
||||
if (other.hasHistoryMessage()) {
|
||||
setHistoryMessage(other.getHistoryMessage());
|
||||
}
|
||||
if (other.hasSuperGroup()) {
|
||||
setSuperGroup(other.getSuperGroup());
|
||||
}
|
||||
this.mergeUnknownFields(other.getUnknownFields());
|
||||
return this;
|
||||
}
|
||||
@@ -3374,6 +3422,39 @@ public final class WFCMessage {
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional int32 super_group = 16;
|
||||
private int superGroup_ ;
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
public boolean hasSuperGroup() {
|
||||
return ((bitField0_ & 0x00008000) == 0x00008000);
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
public int getSuperGroup() {
|
||||
return superGroup_;
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
public Builder setSuperGroup(int value) {
|
||||
bitField0_ |= 0x00008000;
|
||||
superGroup_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional int32 super_group = 16;</code>
|
||||
*/
|
||||
public Builder clearSuperGroup() {
|
||||
bitField0_ = (bitField0_ & ~0x00008000);
|
||||
superGroup_ = 0;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:GroupInfo)
|
||||
}
|
||||
|
||||
@@ -67224,179 +67305,180 @@ public final class WFCMessage {
|
||||
"dRequest\022\022\n\ntarget_uid\030\001 \002(\t\022\016\n\006reason\030\002" +
|
||||
" \002(\t\022\r\n\005extra\030\003 \001(\t\":\n\014Conversation\022\014\n\004t" +
|
||||
"ype\030\001 \002(\005\022\016\n\006target\030\002 \002(\t\022\014\n\004line\030\003 \002(\005\"" +
|
||||
"\253\002\n\tGroupInfo\022\021\n\ttarget_id\030\001 \001(\t\022\014\n\004name" +
|
||||
"\300\002\n\tGroupInfo\022\021\n\ttarget_id\030\001 \001(\t\022\014\n\004name" +
|
||||
"\030\002 \002(\t\022\020\n\010portrait\030\003 \001(\t\022\r\n\005owner\030\004 \001(\t\022" +
|
||||
"\014\n\004type\030\005 \002(\005\022\024\n\014member_count\030\006 \001(\005\022\r\n\005e" +
|
||||
"xtra\030\007 \001(\t\022\021\n\tupdate_dt\030\010 \001(\003\022\030\n\020member_" +
|
||||
"update_dt\030\t \001(\003\022\014\n\004mute\030\n \001(\005\022\021\n\tjoin_ty" +
|
||||
"pe\030\013 \001(\005\022\024\n\014private_chat\030\014 \001(\005\022\022\n\nsearch",
|
||||
"able\030\r \001(\005\022\030\n\020max_member_count\030\016 \001(\005\022\027\n\017" +
|
||||
"history_message\030\017 \001(\005\"r\n\013GroupMember\022\021\n\t" +
|
||||
"member_id\030\001 \002(\t\022\r\n\005alias\030\002 \001(\t\022\014\n\004type\030\003" +
|
||||
" \002(\005\022\021\n\tupdate_dt\030\004 \001(\003\022\021\n\tcreate_dt\030\005 \001" +
|
||||
"(\003\022\r\n\005extra\030\006 \001(\t\"F\n\005Group\022\036\n\ngroup_info" +
|
||||
"\030\001 \002(\0132\n.GroupInfo\022\035\n\007members\030\002 \003(\0132\014.Gr" +
|
||||
"oupMember\"\313\001\n\013ChannelMenu\022\014\n\004type\030\001 \002(\t\022" +
|
||||
"\014\n\004name\030\002 \002(\t\022\013\n\003key\030\003 \001(\t\022\013\n\003url\030\004 \001(\t\022" +
|
||||
"\020\n\010media_id\030\005 \001(\t\022\022\n\narticle_id\030\006 \001(\t\022\016\n" +
|
||||
"\006app_id\030\007 \001(\t\022\020\n\010app_page\030\010 \001(\t\022\036\n\010sub_m",
|
||||
"enu\030\t \003(\0132\014.ChannelMenu\022\017\n\007menu_id\030\n \001(\t" +
|
||||
"\022\r\n\005extra\030\013 \001(\t\"-\n\017ChannelMenuList\022\032\n\004me" +
|
||||
"nu\030\001 \003(\0132\014.ChannelMenu\"\340\001\n\013ChannelInfo\022\021" +
|
||||
"\n\ttarget_id\030\001 \001(\t\022\014\n\004name\030\002 \002(\t\022\020\n\010portr" +
|
||||
"ait\030\003 \001(\t\022\r\n\005owner\030\004 \001(\t\022\016\n\006status\030\005 \001(\005" +
|
||||
"\022\014\n\004desc\030\006 \001(\t\022\r\n\005extra\030\007 \001(\t\022\021\n\tupdate_" +
|
||||
"dt\030\010 \001(\003\022\016\n\006secret\030\t \001(\t\022\020\n\010callback\030\n \001" +
|
||||
"(\t\022\021\n\tautomatic\030\013 \001(\005\022\032\n\004menu\030\014 \003(\0132\014.Ch" +
|
||||
"annelMenu\"D\n\021ModifyChannelInfo\022\022\n\nchanne" +
|
||||
"l_id\030\001 \002(\t\022\014\n\004type\030\002 \002(\005\022\r\n\005value\030\003 \002(\t\"",
|
||||
"8\n\017TransferChannel\022\022\n\nchannel_id\030\001 \002(\t\022\021" +
|
||||
"\n\tnew_owner\030\002 \002(\t\"3\n\017PullChannelInfo\022\022\n\n" +
|
||||
"channel_id\030\001 \002(\t\022\014\n\004head\030\002 \002(\003\"H\n\023PullCh" +
|
||||
"annelListener\022\022\n\nchannel_id\030\001 \002(\t\022\016\n\006off" +
|
||||
"set\030\002 \002(\005\022\r\n\005count\030\003 \002(\005\"R\n\031PullChannelL" +
|
||||
"istenerResult\022\023\n\013total_count\030\001 \002(\005\022\016\n\006of" +
|
||||
"fset\030\002 \002(\005\022\020\n\010listener\030\003 \003(\t\"3\n\rListenCh" +
|
||||
"annel\022\022\n\nchannel_id\030\001 \002(\t\022\016\n\006listen\030\002 \002(" +
|
||||
"\005\"E\n\023SearchChannelResult\022\035\n\007channel\030\001 \003(" +
|
||||
"\0132\014.ChannelInfo\022\017\n\007keyword\030\002 \002(\t\"\235\002\n\016Mes",
|
||||
"sageContent\022\014\n\004type\030\001 \002(\005\022\032\n\022searchable_" +
|
||||
"content\030\002 \001(\t\022\024\n\014push_content\030\003 \001(\t\022\017\n\007c" +
|
||||
"ontent\030\004 \001(\t\022\014\n\004data\030\005 \001(\014\022\021\n\tmediaType\030" +
|
||||
"\006 \001(\005\022\026\n\016remoteMediaUrl\030\007 \001(\t\022\024\n\014persist" +
|
||||
"_flag\030\010 \001(\005\022\027\n\017expire_duration\030\t \001(\005\022\026\n\016" +
|
||||
"mentioned_type\030\n \001(\005\022\030\n\020mentioned_target" +
|
||||
"\030\013 \003(\t\022\r\n\005extra\030\014 \001(\t\022\021\n\tpush_data\030\r \001(\t" +
|
||||
"\"\226\001\n\025AddGroupMemberRequest\022\020\n\010group_id\030\001" +
|
||||
" \002(\t\022\"\n\014added_member\030\002 \003(\0132\014.GroupMember" +
|
||||
"\022\017\n\007to_line\030\003 \003(\005\022\'\n\016notify_content\030\004 \001(",
|
||||
"\0132\017.MessageContent\022\r\n\005extra\030\005 \001(\t\"{\n\022Cre" +
|
||||
"ateGroupRequest\022\025\n\005group\030\001 \002(\0132\006.Group\022\017" +
|
||||
"\n\007to_line\030\002 \003(\005\022\'\n\016notify_content\030\003 \001(\0132" +
|
||||
"\017.MessageContent\022\024\n\014member_extra\030\004 \001(\t\"a" +
|
||||
"\n\023DismissGroupRequest\022\020\n\010group_id\030\001 \002(\t\022" +
|
||||
"\017\n\007to_line\030\002 \003(\005\022\'\n\016notify_content\030\003 \001(\013" +
|
||||
"2\017.MessageContent\"\245\001\n\rFriendRequest\022\020\n\010f" +
|
||||
"rom_uid\030\001 \001(\t\022\016\n\006to_uid\030\002 \002(\t\022\016\n\006reason\030" +
|
||||
"\003 \002(\t\022\016\n\006status\030\004 \001(\005\022\021\n\tupdate_dt\030\005 \001(\003" +
|
||||
"\022\030\n\020from_read_status\030\006 \001(\010\022\026\n\016to_read_st",
|
||||
"atus\030\007 \001(\010\022\r\n\005extra\030\010 \001(\t\"#\n\rGeneralResu" +
|
||||
"lt\022\022\n\nerror_code\030\001 \002(\005\"?\n\025GetUploadToken" +
|
||||
"Request\022\022\n\nmedia_type\030\001 \002(\005\022\022\n\nmedia_pat" +
|
||||
"h\030\002 \002(\t\"S\n\024GetUploadTokenResult\022\016\n\006domai" +
|
||||
"n\030\001 \002(\t\022\r\n\005token\030\002 \002(\t\022\016\n\006server\030\003 \002(\t\022\014" +
|
||||
"\n\004port\030\004 \001(\005\"H\n\023HandleFriendRequest\022\022\n\nt" +
|
||||
"arget_uid\030\001 \002(\t\022\016\n\006status\030\002 \002(\005\022\r\n\005extra" +
|
||||
"\030\003 \001(\t\"\023\n\005IDBuf\022\n\n\002id\030\001 \002(\t\"\027\n\tIDListBuf" +
|
||||
"\022\n\n\002id\030\001 \003(\t\"\256\001\n\007Message\022#\n\014conversation" +
|
||||
"\030\001 \002(\0132\r.Conversation\022\021\n\tfrom_user\030\002 \002(\t",
|
||||
"\022 \n\007content\030\003 \002(\0132\017.MessageContent\022\022\n\nme" +
|
||||
"ssage_id\030\004 \001(\003\022\030\n\020server_timestamp\030\005 \001(\003" +
|
||||
"\022\017\n\007to_user\030\006 \001(\t\022\n\n\002to\030\007 \003(\t\"\353\001\n\004User\022\013" +
|
||||
"\n\003uid\030\001 \002(\t\022\014\n\004name\030\002 \001(\t\022\024\n\014display_nam" +
|
||||
"e\030\003 \001(\t\022\020\n\010portrait\030\004 \001(\t\022\016\n\006mobile\030\005 \001(" +
|
||||
"\t\022\r\n\005email\030\006 \001(\t\022\017\n\007address\030\007 \001(\t\022\017\n\007com" +
|
||||
"pany\030\010 \001(\t\022\r\n\005extra\030\t \001(\t\022\021\n\tupdate_dt\030\n" +
|
||||
" \001(\003\022\016\n\006gender\030\013 \001(\005\022\016\n\006social\030\014 \001(\t\022\014\n\004" +
|
||||
"type\030\r \001(\005\022\017\n\007deleted\030\016 \001(\005\"c\n\005Robot\022\013\n\003" +
|
||||
"uid\030\001 \002(\t\022\r\n\005state\030\002 \002(\005\022\r\n\005owner\030\003 \001(\t\022",
|
||||
"\016\n\006secret\030\004 \001(\t\022\020\n\010callback\030\005 \001(\t\022\r\n\005ext" +
|
||||
"ra\030\006 \001(\t\"(\n\017GetRobotsResult\022\025\n\005entry\030\001 \003" +
|
||||
"(\0132\006.Robot\"g\n\030UploadDeviceTokenRequest\022\020" +
|
||||
"\n\010platform\030\001 \002(\005\022\020\n\010app_name\030\002 \002(\t\022\024\n\014de" +
|
||||
"vice_token\030\003 \002(\t\022\021\n\tpush_type\030\004 \002(\005\"\201\001\n\026" +
|
||||
"ModifyGroupInfoRequest\022\020\n\010group_id\030\001 \002(\t" +
|
||||
"\022\014\n\004type\030\002 \002(\005\022\r\n\005value\030\003 \002(\t\022\017\n\007to_line" +
|
||||
"\030\004 \003(\005\022\'\n\016notify_content\030\005 \001(\0132\017.Message" +
|
||||
"Content\"\203\001\n\026SetGroupManagerRequest\022\020\n\010gr" +
|
||||
"oup_id\030\001 \002(\t\022\014\n\004type\030\002 \002(\005\022\017\n\007user_id\030\003 ",
|
||||
"\003(\t\022\017\n\007to_line\030\004 \003(\005\022\'\n\016notify_content\030\005" +
|
||||
" \001(\0132\017.MessageContent\"(\n\tInfoEntry\022\014\n\004ty" +
|
||||
"pe\030\001 \002(\005\022\r\n\005value\030\002 \002(\t\"0\n\023ModifyMyInfoR" +
|
||||
"equest\022\031\n\005entry\030\001 \003(\0132\n.InfoEntry\";\n\rNot" +
|
||||
"ifyMessage\022\014\n\004type\030\001 \002(\005\022\014\n\004head\030\002 \002(\003\022\016" +
|
||||
"\n\006target\030\003 \001(\t\"=\n\022PullMessageRequest\022\n\n\002" +
|
||||
"id\030\001 \002(\003\022\014\n\004type\030\002 \002(\005\022\r\n\005delay\030\003 \001(\003\"M\n" +
|
||||
"\021PullMessageResult\022\031\n\007message\030\001 \003(\0132\010.Me" +
|
||||
"ssage\022\017\n\007current\030\002 \002(\003\022\014\n\004head\030\003 \002(\003\"/\n\023" +
|
||||
"PullGroupInfoResult\022\030\n\004info\030\001 \003(\0132\n.Grou",
|
||||
"pInfo\"6\n\026PullGroupMemberRequest\022\016\n\006targe" +
|
||||
"t\030\001 \002(\t\022\014\n\004head\030\002 \002(\003\"5\n\025PullGroupMember" +
|
||||
"Result\022\034\n\006member\030\001 \003(\0132\014.GroupMember\"-\n\013" +
|
||||
"UserRequest\022\013\n\003uid\030\001 \002(\t\022\021\n\tupdate_dt\030\002 " +
|
||||
"\001(\003\"0\n\017PullUserRequest\022\035\n\007request\030\001 \003(\0132" +
|
||||
"\014.UserRequest\"/\n\nUserResult\022\023\n\004user\030\001 \002(" +
|
||||
"\0132\005.User\022\014\n\004code\030\002 \002(\005\"-\n\016PullUserResult" +
|
||||
"\022\033\n\006result\030\001 \003(\0132\013.UserResult\"^\n\020QuitGro" +
|
||||
"upRequest\022\020\n\010group_id\030\001 \002(\t\022\017\n\007to_line\030\002" +
|
||||
" \003(\005\022\'\n\016notify_content\030\003 \001(\0132\017.MessageCo",
|
||||
"ntent\"~\n\030RemoveGroupMemberRequest\022\020\n\010gro" +
|
||||
"up_id\030\001 \002(\t\022\026\n\016removed_member\030\002 \003(\t\022\017\n\007t" +
|
||||
"o_line\030\003 \003(\005\022\'\n\016notify_content\030\004 \001(\0132\017.M" +
|
||||
"essageContent\"u\n\024TransferGroupRequest\022\020\n" +
|
||||
"\010group_id\030\001 \002(\t\022\021\n\tnew_owner\030\002 \002(\t\022\017\n\007to" +
|
||||
"_line\030\003 \003(\005\022\'\n\016notify_content\030\004 \001(\0132\017.Me" +
|
||||
"ssageContent\"\206\001\n\026ModifyGroupMemberAlias\022" +
|
||||
"\020\n\010group_id\030\001 \002(\t\022\r\n\005alias\030\002 \002(\t\022\017\n\007to_l" +
|
||||
"ine\030\003 \003(\005\022\'\n\016notify_content\030\004 \001(\0132\017.Mess" +
|
||||
"ageContent\022\021\n\tmember_id\030\005 \001(\t\"\206\001\n\026Modify",
|
||||
"GroupMemberExtra\022\020\n\010group_id\030\001 \002(\t\022\017\n\007to" +
|
||||
"_line\030\002 \003(\005\022\'\n\016notify_content\030\003 \001(\0132\017.Me" +
|
||||
"ssageContent\022\r\n\005extra\030\004 \001(\t\022\021\n\tmember_id" +
|
||||
"\030\005 \001(\t\"P\n\020UserSettingEntry\022\r\n\005scope\030\001 \002(" +
|
||||
"\005\022\013\n\003key\030\002 \002(\t\022\r\n\005value\030\003 \002(\t\022\021\n\tupdate_" +
|
||||
"dt\030\004 \002(\003\"A\n\024ModifyUserSettingReq\022\r\n\005scop" +
|
||||
"e\030\001 \002(\005\022\013\n\003key\030\002 \002(\t\022\r\n\005value\030\003 \002(\t\"\032\n\007V" +
|
||||
"ersion\022\017\n\007version\030\001 \002(\003\"8\n\024GetUserSettin" +
|
||||
"gResult\022 \n\005entry\030\001 \003(\0132\021.UserSettingEntr" +
|
||||
"y\"f\n\006Friend\022\013\n\003uid\030\001 \002(\t\022\r\n\005state\030\002 \002(\005\022",
|
||||
"\021\n\tupdate_dt\030\003 \002(\003\022\r\n\005alias\030\004 \001(\t\022\017\n\007bla" +
|
||||
"cked\030\005 \001(\005\022\r\n\005extra\030\006 \001(\t\"*\n\020GetFriendsR" +
|
||||
"esult\022\026\n\005entry\030\001 \003(\0132\007.Friend\"7\n\026GetFrie" +
|
||||
"ndRequestResult\022\035\n\005entry\030\001 \003(\0132\016.FriendR" +
|
||||
"equest\"\243\001\n\021ConnectAckPayload\022\020\n\010msg_head" +
|
||||
"\030\001 \001(\003\022\023\n\013friend_head\030\002 \001(\003\022\026\n\016friend_rq" +
|
||||
"_head\030\003 \001(\003\022\024\n\014setting_head\030\004 \001(\003\022\021\n\tnod" +
|
||||
"e_addr\030\005 \001(\t\022\021\n\tnode_port\030\006 \001(\005\022\023\n\013serve" +
|
||||
"r_time\030\007 \001(\003\"P\n\rIMHttpWrapper\022\r\n\005token\030\001" +
|
||||
" \002(\t\022\021\n\tclient_id\030\002 \002(\t\022\017\n\007request\030\003 \002(\t",
|
||||
"\022\014\n\004data\030\004 \001(\014\"A\n\021SearchUserRequest\022\017\n\007k" +
|
||||
"eyword\030\001 \002(\t\022\r\n\005fuzzy\030\002 \001(\005\022\014\n\004page\030\003 \001(" +
|
||||
"\005\"(\n\020SearchUserResult\022\024\n\005entry\030\001 \003(\0132\005.U" +
|
||||
"ser\"@\n\026GetChatroomInfoRequest\022\023\n\013chatroo" +
|
||||
"m_id\030\001 \002(\t\022\021\n\tupdate_dt\030\002 \001(\003\"\227\001\n\014Chatro" +
|
||||
"omInfo\022\r\n\005title\030\001 \002(\t\022\014\n\004desc\030\002 \001(\t\022\020\n\010p" +
|
||||
"ortrait\030\003 \001(\t\022\024\n\014member_count\030\004 \001(\005\022\021\n\tc" +
|
||||
"reate_dt\030\005 \001(\003\022\021\n\tupdate_dt\030\006 \001(\003\022\r\n\005ext" +
|
||||
"ra\030\007 \001(\t\022\r\n\005state\030\010 \001(\005\"F\n\034GetChatroomMe" +
|
||||
"mberInfoRequest\022\023\n\013chatroom_id\030\001 \002(\t\022\021\n\t",
|
||||
"max_count\030\002 \001(\005\";\n\022ChatroomMemberInfo\022\024\n" +
|
||||
"\014member_count\030\001 \001(\005\022\017\n\007members\030\002 \003(\t\"\026\n\010" +
|
||||
"INT64Buf\022\n\n\002id\030\001 \002(\003\"4\n\023NotifyRecallMess" +
|
||||
"age\022\n\n\002id\030\001 \002(\003\022\021\n\tfrom_user\030\002 \002(\t\"/\n\020Bl" +
|
||||
"ackUserRequest\022\013\n\003uid\030\001 \002(\t\022\016\n\006status\030\002 " +
|
||||
"\002(\005\"\323\001\n\014RouteRequest\022\013\n\003app\030\001 \001(\t\022\020\n\010pla" +
|
||||
"tform\030\002 \001(\005\022\021\n\tpush_type\030\003 \001(\005\022\023\n\013device" +
|
||||
"_name\030\004 \001(\t\022\026\n\016device_version\030\005 \001(\t\022\022\n\np" +
|
||||
"hone_name\030\006 \001(\t\022\020\n\010language\030\007 \001(\t\022\024\n\014car" +
|
||||
"rier_name\030\010 \001(\t\022\023\n\013app_version\030\t \001(\t\022\023\n\013",
|
||||
"sdk_version\030\n \001(\t\"D\n\rRouteResponse\022\014\n\004ho" +
|
||||
"st\030\001 \002(\t\022\021\n\tlong_port\030\002 \002(\005\022\022\n\nshort_por" +
|
||||
"t\030\003 \002(\005\"G\n\017GetTokenRequest\022\017\n\007user_id\030\001 " +
|
||||
"\002(\t\022\021\n\tclient_id\030\002 \002(\t\022\020\n\010platform\030\003 \001(\005" +
|
||||
"\"r\n\022LoadRemoteMessages\022#\n\014conversation\030\001" +
|
||||
" \002(\0132\r.Conversation\022\022\n\nbefore_uid\030\002 \002(\003\022" +
|
||||
"\r\n\005count\030\003 \002(\005\022\024\n\014content_type\030\004 \003(\005\"a\n\020" +
|
||||
"MultiCastMessage\022\021\n\tfrom_user\030\001 \002(\t\022 \n\007c" +
|
||||
"ontent\030\002 \002(\0132\017.MessageContent\022\n\n\002to\030\003 \003(" +
|
||||
"\t\022\014\n\004line\030\004 \002(\005\"E\n\035RecallMultiCastMessag",
|
||||
"eRequest\022\022\n\nmessage_id\030\001 \002(\003\022\020\n\010receiver" +
|
||||
"\030\002 \003(\t\"@\n\017AuthCodeRequest\022\021\n\ttarget_id\030\001" +
|
||||
" \002(\t\022\014\n\004type\030\002 \002(\005\022\014\n\004host\030\003 \002(\t\"o\n\030Appl" +
|
||||
"icationConfigRequest\022\r\n\005appId\030\001 \002(\t\022\017\n\007a" +
|
||||
"ppType\030\002 \002(\005\022\021\n\ttimestamp\030\003 \002(\003\022\r\n\005nonce" +
|
||||
"\030\004 \002(\t\022\021\n\tsignature\030\005 \002(\tB#\n\025cn.wildfire" +
|
||||
"chat.protoB\nWFCMessage"
|
||||
"history_message\030\017 \001(\005\022\023\n\013super_group\030\020 \001" +
|
||||
"(\005\"r\n\013GroupMember\022\021\n\tmember_id\030\001 \002(\t\022\r\n\005" +
|
||||
"alias\030\002 \001(\t\022\014\n\004type\030\003 \002(\005\022\021\n\tupdate_dt\030\004" +
|
||||
" \001(\003\022\021\n\tcreate_dt\030\005 \001(\003\022\r\n\005extra\030\006 \001(\t\"F" +
|
||||
"\n\005Group\022\036\n\ngroup_info\030\001 \002(\0132\n.GroupInfo\022" +
|
||||
"\035\n\007members\030\002 \003(\0132\014.GroupMember\"\313\001\n\013Chann" +
|
||||
"elMenu\022\014\n\004type\030\001 \002(\t\022\014\n\004name\030\002 \002(\t\022\013\n\003ke" +
|
||||
"y\030\003 \001(\t\022\013\n\003url\030\004 \001(\t\022\020\n\010media_id\030\005 \001(\t\022\022" +
|
||||
"\n\narticle_id\030\006 \001(\t\022\016\n\006app_id\030\007 \001(\t\022\020\n\010ap",
|
||||
"p_page\030\010 \001(\t\022\036\n\010sub_menu\030\t \003(\0132\014.Channel" +
|
||||
"Menu\022\017\n\007menu_id\030\n \001(\t\022\r\n\005extra\030\013 \001(\t\"-\n\017" +
|
||||
"ChannelMenuList\022\032\n\004menu\030\001 \003(\0132\014.ChannelM" +
|
||||
"enu\"\340\001\n\013ChannelInfo\022\021\n\ttarget_id\030\001 \001(\t\022\014" +
|
||||
"\n\004name\030\002 \002(\t\022\020\n\010portrait\030\003 \001(\t\022\r\n\005owner\030" +
|
||||
"\004 \001(\t\022\016\n\006status\030\005 \001(\005\022\014\n\004desc\030\006 \001(\t\022\r\n\005e" +
|
||||
"xtra\030\007 \001(\t\022\021\n\tupdate_dt\030\010 \001(\003\022\016\n\006secret\030" +
|
||||
"\t \001(\t\022\020\n\010callback\030\n \001(\t\022\021\n\tautomatic\030\013 \001" +
|
||||
"(\005\022\032\n\004menu\030\014 \003(\0132\014.ChannelMenu\"D\n\021Modify" +
|
||||
"ChannelInfo\022\022\n\nchannel_id\030\001 \002(\t\022\014\n\004type\030",
|
||||
"\002 \002(\005\022\r\n\005value\030\003 \002(\t\"8\n\017TransferChannel\022" +
|
||||
"\022\n\nchannel_id\030\001 \002(\t\022\021\n\tnew_owner\030\002 \002(\t\"3" +
|
||||
"\n\017PullChannelInfo\022\022\n\nchannel_id\030\001 \002(\t\022\014\n" +
|
||||
"\004head\030\002 \002(\003\"H\n\023PullChannelListener\022\022\n\nch" +
|
||||
"annel_id\030\001 \002(\t\022\016\n\006offset\030\002 \002(\005\022\r\n\005count\030" +
|
||||
"\003 \002(\005\"R\n\031PullChannelListenerResult\022\023\n\013to" +
|
||||
"tal_count\030\001 \002(\005\022\016\n\006offset\030\002 \002(\005\022\020\n\010liste" +
|
||||
"ner\030\003 \003(\t\"3\n\rListenChannel\022\022\n\nchannel_id" +
|
||||
"\030\001 \002(\t\022\016\n\006listen\030\002 \002(\005\"E\n\023SearchChannelR" +
|
||||
"esult\022\035\n\007channel\030\001 \003(\0132\014.ChannelInfo\022\017\n\007",
|
||||
"keyword\030\002 \002(\t\"\235\002\n\016MessageContent\022\014\n\004type" +
|
||||
"\030\001 \002(\005\022\032\n\022searchable_content\030\002 \001(\t\022\024\n\014pu" +
|
||||
"sh_content\030\003 \001(\t\022\017\n\007content\030\004 \001(\t\022\014\n\004dat" +
|
||||
"a\030\005 \001(\014\022\021\n\tmediaType\030\006 \001(\005\022\026\n\016remoteMedi" +
|
||||
"aUrl\030\007 \001(\t\022\024\n\014persist_flag\030\010 \001(\005\022\027\n\017expi" +
|
||||
"re_duration\030\t \001(\005\022\026\n\016mentioned_type\030\n \001(" +
|
||||
"\005\022\030\n\020mentioned_target\030\013 \003(\t\022\r\n\005extra\030\014 \001" +
|
||||
"(\t\022\021\n\tpush_data\030\r \001(\t\"\226\001\n\025AddGroupMember" +
|
||||
"Request\022\020\n\010group_id\030\001 \002(\t\022\"\n\014added_membe" +
|
||||
"r\030\002 \003(\0132\014.GroupMember\022\017\n\007to_line\030\003 \003(\005\022\'",
|
||||
"\n\016notify_content\030\004 \001(\0132\017.MessageContent\022" +
|
||||
"\r\n\005extra\030\005 \001(\t\"{\n\022CreateGroupRequest\022\025\n\005" +
|
||||
"group\030\001 \002(\0132\006.Group\022\017\n\007to_line\030\002 \003(\005\022\'\n\016" +
|
||||
"notify_content\030\003 \001(\0132\017.MessageContent\022\024\n" +
|
||||
"\014member_extra\030\004 \001(\t\"a\n\023DismissGroupReque" +
|
||||
"st\022\020\n\010group_id\030\001 \002(\t\022\017\n\007to_line\030\002 \003(\005\022\'\n" +
|
||||
"\016notify_content\030\003 \001(\0132\017.MessageContent\"\245" +
|
||||
"\001\n\rFriendRequest\022\020\n\010from_uid\030\001 \001(\t\022\016\n\006to" +
|
||||
"_uid\030\002 \002(\t\022\016\n\006reason\030\003 \002(\t\022\016\n\006status\030\004 \001" +
|
||||
"(\005\022\021\n\tupdate_dt\030\005 \001(\003\022\030\n\020from_read_statu",
|
||||
"s\030\006 \001(\010\022\026\n\016to_read_status\030\007 \001(\010\022\r\n\005extra" +
|
||||
"\030\010 \001(\t\"#\n\rGeneralResult\022\022\n\nerror_code\030\001 " +
|
||||
"\002(\005\"?\n\025GetUploadTokenRequest\022\022\n\nmedia_ty" +
|
||||
"pe\030\001 \002(\005\022\022\n\nmedia_path\030\002 \002(\t\"S\n\024GetUploa" +
|
||||
"dTokenResult\022\016\n\006domain\030\001 \002(\t\022\r\n\005token\030\002 " +
|
||||
"\002(\t\022\016\n\006server\030\003 \002(\t\022\014\n\004port\030\004 \001(\005\"H\n\023Han" +
|
||||
"dleFriendRequest\022\022\n\ntarget_uid\030\001 \002(\t\022\016\n\006" +
|
||||
"status\030\002 \002(\005\022\r\n\005extra\030\003 \001(\t\"\023\n\005IDBuf\022\n\n\002" +
|
||||
"id\030\001 \002(\t\"\027\n\tIDListBuf\022\n\n\002id\030\001 \003(\t\"\256\001\n\007Me" +
|
||||
"ssage\022#\n\014conversation\030\001 \002(\0132\r.Conversati",
|
||||
"on\022\021\n\tfrom_user\030\002 \002(\t\022 \n\007content\030\003 \002(\0132\017" +
|
||||
".MessageContent\022\022\n\nmessage_id\030\004 \001(\003\022\030\n\020s" +
|
||||
"erver_timestamp\030\005 \001(\003\022\017\n\007to_user\030\006 \001(\t\022\n" +
|
||||
"\n\002to\030\007 \003(\t\"\353\001\n\004User\022\013\n\003uid\030\001 \002(\t\022\014\n\004name" +
|
||||
"\030\002 \001(\t\022\024\n\014display_name\030\003 \001(\t\022\020\n\010portrait" +
|
||||
"\030\004 \001(\t\022\016\n\006mobile\030\005 \001(\t\022\r\n\005email\030\006 \001(\t\022\017\n" +
|
||||
"\007address\030\007 \001(\t\022\017\n\007company\030\010 \001(\t\022\r\n\005extra" +
|
||||
"\030\t \001(\t\022\021\n\tupdate_dt\030\n \001(\003\022\016\n\006gender\030\013 \001(" +
|
||||
"\005\022\016\n\006social\030\014 \001(\t\022\014\n\004type\030\r \001(\005\022\017\n\007delet" +
|
||||
"ed\030\016 \001(\005\"c\n\005Robot\022\013\n\003uid\030\001 \002(\t\022\r\n\005state\030",
|
||||
"\002 \002(\005\022\r\n\005owner\030\003 \001(\t\022\016\n\006secret\030\004 \001(\t\022\020\n\010" +
|
||||
"callback\030\005 \001(\t\022\r\n\005extra\030\006 \001(\t\"(\n\017GetRobo" +
|
||||
"tsResult\022\025\n\005entry\030\001 \003(\0132\006.Robot\"g\n\030Uploa" +
|
||||
"dDeviceTokenRequest\022\020\n\010platform\030\001 \002(\005\022\020\n" +
|
||||
"\010app_name\030\002 \002(\t\022\024\n\014device_token\030\003 \002(\t\022\021\n" +
|
||||
"\tpush_type\030\004 \002(\005\"\201\001\n\026ModifyGroupInfoRequ" +
|
||||
"est\022\020\n\010group_id\030\001 \002(\t\022\014\n\004type\030\002 \002(\005\022\r\n\005v" +
|
||||
"alue\030\003 \002(\t\022\017\n\007to_line\030\004 \003(\005\022\'\n\016notify_co" +
|
||||
"ntent\030\005 \001(\0132\017.MessageContent\"\203\001\n\026SetGrou" +
|
||||
"pManagerRequest\022\020\n\010group_id\030\001 \002(\t\022\014\n\004typ",
|
||||
"e\030\002 \002(\005\022\017\n\007user_id\030\003 \003(\t\022\017\n\007to_line\030\004 \003(" +
|
||||
"\005\022\'\n\016notify_content\030\005 \001(\0132\017.MessageConte" +
|
||||
"nt\"(\n\tInfoEntry\022\014\n\004type\030\001 \002(\005\022\r\n\005value\030\002" +
|
||||
" \002(\t\"0\n\023ModifyMyInfoRequest\022\031\n\005entry\030\001 \003" +
|
||||
"(\0132\n.InfoEntry\";\n\rNotifyMessage\022\014\n\004type\030" +
|
||||
"\001 \002(\005\022\014\n\004head\030\002 \002(\003\022\016\n\006target\030\003 \001(\t\"=\n\022P" +
|
||||
"ullMessageRequest\022\n\n\002id\030\001 \002(\003\022\014\n\004type\030\002 " +
|
||||
"\002(\005\022\r\n\005delay\030\003 \001(\003\"M\n\021PullMessageResult\022" +
|
||||
"\031\n\007message\030\001 \003(\0132\010.Message\022\017\n\007current\030\002 " +
|
||||
"\002(\003\022\014\n\004head\030\003 \002(\003\"/\n\023PullGroupInfoResult",
|
||||
"\022\030\n\004info\030\001 \003(\0132\n.GroupInfo\"6\n\026PullGroupM" +
|
||||
"emberRequest\022\016\n\006target\030\001 \002(\t\022\014\n\004head\030\002 \002" +
|
||||
"(\003\"5\n\025PullGroupMemberResult\022\034\n\006member\030\001 " +
|
||||
"\003(\0132\014.GroupMember\"-\n\013UserRequest\022\013\n\003uid\030" +
|
||||
"\001 \002(\t\022\021\n\tupdate_dt\030\002 \001(\003\"0\n\017PullUserRequ" +
|
||||
"est\022\035\n\007request\030\001 \003(\0132\014.UserRequest\"/\n\nUs" +
|
||||
"erResult\022\023\n\004user\030\001 \002(\0132\005.User\022\014\n\004code\030\002 " +
|
||||
"\002(\005\"-\n\016PullUserResult\022\033\n\006result\030\001 \003(\0132\013." +
|
||||
"UserResult\"^\n\020QuitGroupRequest\022\020\n\010group_" +
|
||||
"id\030\001 \002(\t\022\017\n\007to_line\030\002 \003(\005\022\'\n\016notify_cont",
|
||||
"ent\030\003 \001(\0132\017.MessageContent\"~\n\030RemoveGrou" +
|
||||
"pMemberRequest\022\020\n\010group_id\030\001 \002(\t\022\026\n\016remo" +
|
||||
"ved_member\030\002 \003(\t\022\017\n\007to_line\030\003 \003(\005\022\'\n\016not" +
|
||||
"ify_content\030\004 \001(\0132\017.MessageContent\"u\n\024Tr" +
|
||||
"ansferGroupRequest\022\020\n\010group_id\030\001 \002(\t\022\021\n\t" +
|
||||
"new_owner\030\002 \002(\t\022\017\n\007to_line\030\003 \003(\005\022\'\n\016noti" +
|
||||
"fy_content\030\004 \001(\0132\017.MessageContent\"\206\001\n\026Mo" +
|
||||
"difyGroupMemberAlias\022\020\n\010group_id\030\001 \002(\t\022\r" +
|
||||
"\n\005alias\030\002 \002(\t\022\017\n\007to_line\030\003 \003(\005\022\'\n\016notify" +
|
||||
"_content\030\004 \001(\0132\017.MessageContent\022\021\n\tmembe",
|
||||
"r_id\030\005 \001(\t\"\206\001\n\026ModifyGroupMemberExtra\022\020\n" +
|
||||
"\010group_id\030\001 \002(\t\022\017\n\007to_line\030\002 \003(\005\022\'\n\016noti" +
|
||||
"fy_content\030\003 \001(\0132\017.MessageContent\022\r\n\005ext" +
|
||||
"ra\030\004 \001(\t\022\021\n\tmember_id\030\005 \001(\t\"P\n\020UserSetti" +
|
||||
"ngEntry\022\r\n\005scope\030\001 \002(\005\022\013\n\003key\030\002 \002(\t\022\r\n\005v" +
|
||||
"alue\030\003 \002(\t\022\021\n\tupdate_dt\030\004 \002(\003\"A\n\024ModifyU" +
|
||||
"serSettingReq\022\r\n\005scope\030\001 \002(\005\022\013\n\003key\030\002 \002(" +
|
||||
"\t\022\r\n\005value\030\003 \002(\t\"\032\n\007Version\022\017\n\007version\030\001" +
|
||||
" \002(\003\"8\n\024GetUserSettingResult\022 \n\005entry\030\001 " +
|
||||
"\003(\0132\021.UserSettingEntry\"f\n\006Friend\022\013\n\003uid\030",
|
||||
"\001 \002(\t\022\r\n\005state\030\002 \002(\005\022\021\n\tupdate_dt\030\003 \002(\003\022" +
|
||||
"\r\n\005alias\030\004 \001(\t\022\017\n\007blacked\030\005 \001(\005\022\r\n\005extra" +
|
||||
"\030\006 \001(\t\"*\n\020GetFriendsResult\022\026\n\005entry\030\001 \003(" +
|
||||
"\0132\007.Friend\"7\n\026GetFriendRequestResult\022\035\n\005" +
|
||||
"entry\030\001 \003(\0132\016.FriendRequest\"\243\001\n\021ConnectA" +
|
||||
"ckPayload\022\020\n\010msg_head\030\001 \001(\003\022\023\n\013friend_he" +
|
||||
"ad\030\002 \001(\003\022\026\n\016friend_rq_head\030\003 \001(\003\022\024\n\014sett" +
|
||||
"ing_head\030\004 \001(\003\022\021\n\tnode_addr\030\005 \001(\t\022\021\n\tnod" +
|
||||
"e_port\030\006 \001(\005\022\023\n\013server_time\030\007 \001(\003\"P\n\rIMH" +
|
||||
"ttpWrapper\022\r\n\005token\030\001 \002(\t\022\021\n\tclient_id\030\002",
|
||||
" \002(\t\022\017\n\007request\030\003 \002(\t\022\014\n\004data\030\004 \001(\014\"A\n\021S" +
|
||||
"earchUserRequest\022\017\n\007keyword\030\001 \002(\t\022\r\n\005fuz" +
|
||||
"zy\030\002 \001(\005\022\014\n\004page\030\003 \001(\005\"(\n\020SearchUserResu" +
|
||||
"lt\022\024\n\005entry\030\001 \003(\0132\005.User\"@\n\026GetChatroomI" +
|
||||
"nfoRequest\022\023\n\013chatroom_id\030\001 \002(\t\022\021\n\tupdat" +
|
||||
"e_dt\030\002 \001(\003\"\227\001\n\014ChatroomInfo\022\r\n\005title\030\001 \002" +
|
||||
"(\t\022\014\n\004desc\030\002 \001(\t\022\020\n\010portrait\030\003 \001(\t\022\024\n\014me" +
|
||||
"mber_count\030\004 \001(\005\022\021\n\tcreate_dt\030\005 \001(\003\022\021\n\tu" +
|
||||
"pdate_dt\030\006 \001(\003\022\r\n\005extra\030\007 \001(\t\022\r\n\005state\030\010" +
|
||||
" \001(\005\"F\n\034GetChatroomMemberInfoRequest\022\023\n\013",
|
||||
"chatroom_id\030\001 \002(\t\022\021\n\tmax_count\030\002 \001(\005\";\n\022" +
|
||||
"ChatroomMemberInfo\022\024\n\014member_count\030\001 \001(\005" +
|
||||
"\022\017\n\007members\030\002 \003(\t\"\026\n\010INT64Buf\022\n\n\002id\030\001 \002(" +
|
||||
"\003\"4\n\023NotifyRecallMessage\022\n\n\002id\030\001 \002(\003\022\021\n\t" +
|
||||
"from_user\030\002 \002(\t\"/\n\020BlackUserRequest\022\013\n\003u" +
|
||||
"id\030\001 \002(\t\022\016\n\006status\030\002 \002(\005\"\323\001\n\014RouteReques" +
|
||||
"t\022\013\n\003app\030\001 \001(\t\022\020\n\010platform\030\002 \001(\005\022\021\n\tpush" +
|
||||
"_type\030\003 \001(\005\022\023\n\013device_name\030\004 \001(\t\022\026\n\016devi" +
|
||||
"ce_version\030\005 \001(\t\022\022\n\nphone_name\030\006 \001(\t\022\020\n\010" +
|
||||
"language\030\007 \001(\t\022\024\n\014carrier_name\030\010 \001(\t\022\023\n\013",
|
||||
"app_version\030\t \001(\t\022\023\n\013sdk_version\030\n \001(\t\"D" +
|
||||
"\n\rRouteResponse\022\014\n\004host\030\001 \002(\t\022\021\n\tlong_po" +
|
||||
"rt\030\002 \002(\005\022\022\n\nshort_port\030\003 \002(\005\"G\n\017GetToken" +
|
||||
"Request\022\017\n\007user_id\030\001 \002(\t\022\021\n\tclient_id\030\002 " +
|
||||
"\002(\t\022\020\n\010platform\030\003 \001(\005\"r\n\022LoadRemoteMessa" +
|
||||
"ges\022#\n\014conversation\030\001 \002(\0132\r.Conversation" +
|
||||
"\022\022\n\nbefore_uid\030\002 \002(\003\022\r\n\005count\030\003 \002(\005\022\024\n\014c" +
|
||||
"ontent_type\030\004 \003(\005\"a\n\020MultiCastMessage\022\021\n" +
|
||||
"\tfrom_user\030\001 \002(\t\022 \n\007content\030\002 \002(\0132\017.Mess" +
|
||||
"ageContent\022\n\n\002to\030\003 \003(\t\022\014\n\004line\030\004 \002(\005\"E\n\035",
|
||||
"RecallMultiCastMessageRequest\022\022\n\nmessage" +
|
||||
"_id\030\001 \002(\003\022\020\n\010receiver\030\002 \003(\t\"@\n\017AuthCodeR" +
|
||||
"equest\022\021\n\ttarget_id\030\001 \002(\t\022\014\n\004type\030\002 \002(\005\022" +
|
||||
"\014\n\004host\030\003 \002(\t\"o\n\030ApplicationConfigReques" +
|
||||
"t\022\r\n\005appId\030\001 \002(\t\022\017\n\007appType\030\002 \002(\005\022\021\n\ttim" +
|
||||
"estamp\030\003 \002(\003\022\r\n\005nonce\030\004 \002(\t\022\021\n\tsignature" +
|
||||
"\030\005 \002(\tB/\n\025cn.wildfirechat.protoB\nWFCMess" +
|
||||
"ageZ\n./go;proto"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
@@ -67420,7 +67502,7 @@ public final class WFCMessage {
|
||||
internal_static_GroupInfo_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_GroupInfo_descriptor,
|
||||
new java.lang.String[] { "TargetId", "Name", "Portrait", "Owner", "Type", "MemberCount", "Extra", "UpdateDt", "MemberUpdateDt", "Mute", "JoinType", "PrivateChat", "Searchable", "MaxMemberCount", "HistoryMessage", });
|
||||
new java.lang.String[] { "TargetId", "Name", "Portrait", "Owner", "Type", "MemberCount", "Extra", "UpdateDt", "MemberUpdateDt", "Mute", "JoinType", "PrivateChat", "Searchable", "MaxMemberCount", "HistoryMessage", "SuperGroup", });
|
||||
internal_static_GroupMember_descriptor =
|
||||
getDescriptor().getMessageTypes().get(3);
|
||||
internal_static_GroupMember_fieldAccessorTable = new
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
@@ -18,38 +19,46 @@ import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class AES {
|
||||
private static byte[] aes_key= {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F};
|
||||
public static void init(byte[] secret) {
|
||||
if (secret != null && secret.length == 16) {
|
||||
aes_key = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
aes_key[i] = secret[i];
|
||||
}
|
||||
} else {
|
||||
System.out.println("Error int key error, secret incorrect");
|
||||
}
|
||||
}
|
||||
public static int keyLen = 16;
|
||||
private final static int ivLen = 16;
|
||||
private static byte[] aes_key= {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x3A,0x1F,0x28,0x39,0x4F,0x52,0x68,0x79,0x71,0x73,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F};
|
||||
|
||||
public static byte[] AESEncrypt(String sSrc, String userKey) {
|
||||
return AESEncrypt(sSrc.getBytes(), userKey);
|
||||
}
|
||||
|
||||
public static void useAes256(boolean aes256) {
|
||||
if(aes256)
|
||||
keyLen = 32;
|
||||
else
|
||||
keyLen = 16;
|
||||
}
|
||||
|
||||
public static byte[] AESEncrypt(byte[] tobeencrypdata, byte[] aesKey) {
|
||||
if (aesKey == null) {
|
||||
System.out.print("Key为空null");
|
||||
return null;
|
||||
}
|
||||
// 判断Key是否为16位
|
||||
if (aesKey.length != 16) {
|
||||
if (aesKey.length < keyLen) {
|
||||
System.out.print("Key长度不是16位");
|
||||
return null;
|
||||
}
|
||||
if(aesKey.length > keyLen) {
|
||||
aesKey = Arrays.copyOfRange(aesKey, 0, keyLen);
|
||||
}
|
||||
|
||||
byte[] ivKeys;
|
||||
if(aesKey.length == ivLen) {
|
||||
ivKeys = aesKey;
|
||||
} else {
|
||||
ivKeys = Arrays.copyOfRange(aesKey, 0, ivLen);
|
||||
}
|
||||
|
||||
try {
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
|
||||
IvParameterSpec iv = new IvParameterSpec(aesKey);//使用CBC模式,需要一个向量iv,可增加加密算法的强度
|
||||
IvParameterSpec iv = new IvParameterSpec(ivKeys);//使用CBC模式,需要一个向量iv,可增加加密算法的强度
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
|
||||
|
||||
//2018.1.1 0:0:0 以来的小时数
|
||||
@@ -101,21 +110,26 @@ public class AES {
|
||||
}
|
||||
|
||||
private static byte[] convertUserKey(String userKey) {
|
||||
byte[] key = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
byte[] key = new byte[keyLen];
|
||||
for (int i = 0; i < keyLen; i++) {
|
||||
key[i] = (byte) (userKey.charAt(i) & 0xFF);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public static byte[] AESDecrypt(byte[] sSrc, String userKey, boolean checkTime) {
|
||||
return AESDecrypt(sSrc, userKey, checkTime, null);
|
||||
}
|
||||
|
||||
public static byte[] AESDecrypt(byte[] sSrc, String userKey, boolean checkTime, boolean[] invalidTime) {
|
||||
byte[] aesKey = aes_key;
|
||||
if (userKey != null && !userKey.isEmpty()) {
|
||||
aesKey = convertUserKey(userKey);
|
||||
}
|
||||
return AESDecrypt(sSrc, aesKey, checkTime);
|
||||
return AESDecrypt(sSrc, aesKey, checkTime, invalidTime);
|
||||
}
|
||||
|
||||
public static byte[] AESDecrypt(byte[] sSrc, byte[] aesKey, boolean checkTime) {
|
||||
public static byte[] AESDecrypt(byte[] sSrc, byte[] aesKey, boolean checkTime, boolean[] invalidTime) {
|
||||
try {
|
||||
|
||||
// 判断Key是否正确
|
||||
@@ -123,14 +137,25 @@ public class AES {
|
||||
aesKey = aes_key;
|
||||
}
|
||||
// 判断Key是否为16位
|
||||
if (aesKey.length != 16) {
|
||||
if (aesKey.length < keyLen) {
|
||||
System.out.print("Key长度不是16位");
|
||||
return null;
|
||||
}
|
||||
|
||||
if(aesKey.length > keyLen) {
|
||||
aesKey = Arrays.copyOfRange(aesKey, 0, keyLen);
|
||||
}
|
||||
|
||||
byte[] ivKeys;
|
||||
if(aesKey.length == ivLen) {
|
||||
ivKeys = aesKey;
|
||||
} else {
|
||||
ivKeys = Arrays.copyOfRange(aesKey, 0, ivLen);
|
||||
}
|
||||
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
IvParameterSpec iv = new IvParameterSpec(aesKey);
|
||||
IvParameterSpec iv = new IvParameterSpec(ivKeys);
|
||||
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
|
||||
try {
|
||||
byte[] original = cipher.doFinal(sSrc);
|
||||
@@ -152,6 +177,9 @@ public class AES {
|
||||
int curhour = (int) ((System.currentTimeMillis()/1000 - 1514736000)/3600);
|
||||
|
||||
if (curhour - hours > 24 && checkTime) {
|
||||
if(invalidTime != null) {
|
||||
invalidTime[0] = true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
byte[] neworiginal = new byte[original.length - 4];
|
||||
|
||||
+104
-2
@@ -6,7 +6,7 @@
|
||||
<!--<relativePath>../pom.xml</relativePath>-->
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.95</version>
|
||||
<version>1.1.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>distribution</artifactId>
|
||||
@@ -93,7 +93,109 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>jdeb</artifactId>
|
||||
<groupId>org.vafer</groupId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jdeb</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<controlDir>${project.basedir}/src/main/deb/control</controlDir>
|
||||
<skipPOMs>false</skipPOMs>
|
||||
<deb>${project.build.directory}/im-server-${project.version}.deb</deb>
|
||||
<dataSet>
|
||||
<data>
|
||||
<src>${project.build.directory}/distribution-${project.version}-bundle-tar.tar.gz</src>
|
||||
<type>archive</type>
|
||||
<mapper>
|
||||
<type>perm</type>
|
||||
<prefix>/opt/im-server</prefix>
|
||||
</mapper>
|
||||
</data>
|
||||
<data>
|
||||
<src>${project.basedir}/../systemd/im-server.service</src>
|
||||
<type>file</type>
|
||||
<mapper>
|
||||
<type>perm</type>
|
||||
<prefix>/usr/lib/systemd/system</prefix>
|
||||
</mapper>
|
||||
</data>
|
||||
</dataSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- 打包RPM 包需要本地有rpm命令才可以,linux和mac都可以安装rpm。如果是windows需要cygwin安装rpm才可以,如果不需要rpm包,可以把这个plugin注释掉-->
|
||||
<!-- 打包RPM插件,如果需要打包RPM格式请打开下面注释 -->
|
||||
<!-- <plugin>-->
|
||||
<!-- <groupId>org.codehaus.mojo</groupId>-->
|
||||
<!-- <artifactId>rpm-maven-plugin</artifactId>-->
|
||||
<!-- <version>2.2.0</version>-->
|
||||
<!-- <executions>-->
|
||||
<!-- <execution>-->
|
||||
<!-- <id>generate-rpm</id>-->
|
||||
<!-- <goals>-->
|
||||
<!-- <goal>rpm</goal>-->
|
||||
<!-- </goals>-->
|
||||
<!-- </execution>-->
|
||||
<!-- </executions>-->
|
||||
<!-- <configuration>-->
|
||||
<!-- <group>Applications/Chat</group>-->
|
||||
<!-- <name>im-server</name>-->
|
||||
<!-- <needarch>noarch</needarch>-->
|
||||
<!-- <targetOS>linux</targetOS>-->
|
||||
<!-- <prefix>/opt/im-server</prefix>-->
|
||||
<!-- <defineStatements>-->
|
||||
<!-- <defineStatement>_unpackaged_files_terminate_build 0</defineStatement>-->
|
||||
<!-- </defineStatements>-->
|
||||
<!-- <copyTo>-->
|
||||
<!-- target/im-server-${project.version}.rpm-->
|
||||
<!-- </copyTo>-->
|
||||
<!-- <requires>-->
|
||||
<!-- <require>java-1.8.0-openjdk-headless</require>-->
|
||||
<!-- </requires>-->
|
||||
<!-- <mappings>-->
|
||||
<!-- <mapping>-->
|
||||
<!-- <directory>/opt/im-server</directory>-->
|
||||
<!-- <filemode>755</filemode>-->
|
||||
<!-- <sources>-->
|
||||
<!-- <source>-->
|
||||
<!-- <location>${project.build.directory}/distribution-${project.version}-bundle-tar.tar.gz</location>-->
|
||||
<!-- </source>-->
|
||||
<!-- </sources>-->
|
||||
<!-- </mapping>-->
|
||||
<!-- <mapping>-->
|
||||
<!-- <directory>/usr/lib/systemd/system</directory>-->
|
||||
<!-- <filemode>644</filemode>-->
|
||||
<!-- <username>root</username>-->
|
||||
<!-- <groupname>root</groupname>-->
|
||||
<!-- <directoryIncluded>false</directoryIncluded>-->
|
||||
<!-- <sources>-->
|
||||
<!-- <source>-->
|
||||
<!-- <location>${project.basedir}/../systemd/im-server.service</location>-->
|
||||
<!-- </source>-->
|
||||
<!-- </sources>-->
|
||||
<!-- </mapping>-->
|
||||
<!-- </mappings>-->
|
||||
<!-- <postinstallScriptlet>-->
|
||||
<!-- <scriptFile>${project.basedir}/src/main/rpm/install.sh</scriptFile>-->
|
||||
<!-- <fileEncoding>utf-8</fileEncoding>-->
|
||||
<!-- <filter>true</filter>-->
|
||||
<!-- </postinstallScriptlet>-->
|
||||
<!-- <postremoveScriptlet>-->
|
||||
<!-- <scriptFile>${project.basedir}/src/main/rpm/uninstall.sh</scriptFile>-->
|
||||
<!-- <fileEncoding>utf-8</fileEncoding>-->
|
||||
<!-- <filter>true</filter>-->
|
||||
<!-- </postremoveScriptlet>-->
|
||||
<!-- </configuration>-->
|
||||
<!-- </plugin>-->
|
||||
<!-- 打包RPM 结束-->
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -21,13 +21,18 @@
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>../broker/config/i18n/</directory>
|
||||
<outputDirectory>/config/i18n</outputDirectory>
|
||||
<directory>src/main/resources/</directory>
|
||||
<outputDirectory>config/</outputDirectory>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>src/main/resources/</directory>
|
||||
<outputDirectory>config/</outputDirectory>
|
||||
<directory>../systemd/</directory>
|
||||
<outputDirectory>/systemd</outputDirectory>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>src/main/checker/</directory>
|
||||
<outputDirectory>checker/</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
@@ -39,6 +44,12 @@
|
||||
<fileMode>0755</fileMode>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>src/main/scripts/stop.sh</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<fileMode>0755</fileMode>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>src/main/scripts/wildfirechat.bat</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
@@ -49,7 +60,7 @@
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>src/main/files/release_note.md</source>
|
||||
<source>../release_note.md</source>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
@@ -75,8 +86,22 @@
|
||||
<outputDirectory>server_sdk/</outputDirectory>
|
||||
<destName>common-${project.version}.jar</destName>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
<file>
|
||||
<source>../sdk/target/checker.jar</source>
|
||||
<outputDirectory>checker/</outputDirectory>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>../docker/Dockerfile</source>
|
||||
<outputDirectory>docker/</outputDirectory>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>../docker/README.md</source>
|
||||
<outputDirectory>docker/</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
部署IM服务后,可以使用Server SDK通过API来检查服务的部署情况,可以执行:
|
||||
```shell
|
||||
java -jar checker.jar http://127.0.0.1:18080 123456 http://127.0.0.1 true false
|
||||
```
|
||||
来检查。检查之后会产生垃圾数据,请在检查之后停掉IM服务后,再删除掉IM服务数据库。此检查仅检查API,检查通过并不代表部署肯定成功,还需要客户端来验证。
|
||||
@@ -0,0 +1,10 @@
|
||||
Package: im-server
|
||||
Version: [[version]]
|
||||
Section: misc
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Maintainer: Wildfirechat <[email protected]>
|
||||
Description: IM Server
|
||||
Distribution: development
|
||||
Depends: openjdk-8-jre-headless
|
||||
Homepage: https://wildfirechat.cn
|
||||
@@ -0,0 +1,23 @@
|
||||
set -e
|
||||
sed -i 's/h2db.path .\/h2db\/wfchat/h2db.path \/var\/lib\/im-server\/h2db\/imdb/' /opt/im-server/config/wildfirechat.conf
|
||||
sed -i 's/local.media.storage.root .\/media/local.media.storage.root \/var\/lib\/im-server\/media/' /opt/im-server/config/wildfirechat.conf
|
||||
sed -i 's/<Property name="MSG_LOG_HOME">.\/logs<\/Property>/<Property name="MSG_LOG_HOME">\/var\/log\/im-server<\/Property>/' /opt/im-server/config/log4j2.xml
|
||||
sed -i 's/WILDFIRECHAT_CONFIG_PATH=$WILDFIRECHAT_HOME/WILDFIRECHAT_CONFIG_PATH=\/etc\/im-server/' /opt/im-server/bin/wildfirechat.sh
|
||||
|
||||
if [ ! -d /etc/im-server ]; then
|
||||
mkdir /etc/im-server
|
||||
fi
|
||||
|
||||
if [ ! -d /var/log/im-server ]; then
|
||||
mkdir /var/log/im-server
|
||||
fi
|
||||
|
||||
mv -f /opt/im-server/config /etc/im-server
|
||||
systemctl daemon-reload
|
||||
|
||||
echo "IM server folders:"
|
||||
echo "/etc/im-server/config config"
|
||||
echo "/opt/im-server binary files"
|
||||
echo "/var/log/im-server logs"
|
||||
echo "/var/lib/im-server/h2db embed db"
|
||||
echo "/var/lib/im-server/media embed media files"
|
||||
@@ -0,0 +1,16 @@
|
||||
set -e
|
||||
rm -rf /opt/im-server
|
||||
rm -rf /etc/im-server
|
||||
rm -rf /var/log/im-server
|
||||
rm -rf /usr/lib/systemd/system/im-server.service
|
||||
|
||||
if [ -d /var/lib/im-server/h2db ]; then
|
||||
echo "IM embed db file not deleted in path /var/lib/im-server/h2db, if you don't need it anymore, please remove it manually"
|
||||
fi
|
||||
|
||||
if [ -d /var/lib/im-server/media ]; then
|
||||
echo "IM embed media files not deleted in path /var/lib/im-server/media, if you don't need it anymore, please remove it manually"
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
<!--monitorInterval="30" :间隔秒数,自动检测配置文件的变更和重新配置本身-->
|
||||
<configuration status="WARN" monitorInterval="60">
|
||||
<Properties>
|
||||
<!--自定义一些常量,之后使用${变量名}引用-->
|
||||
<!-- 日志路径-->
|
||||
<Property name="MSG_LOG_HOME">./logs</Property>
|
||||
<Property name="logFileName">test.log</Property>
|
||||
<!-- <Property name="MSG_LOG_HOME">/var/log/wildfirechat/im/logs</Property>-->
|
||||
<property name="charset">UTF-8</property>
|
||||
<!--自定义的输出格式-->
|
||||
<property name="pattern">%d %-5p [%t] %C{2} (%F:%L) - %m%n</property>
|
||||
</Properties>
|
||||
<!--appenders:定义输出内容,输出格式,输出方式,日志保存策略等,常用其下三种标签[console,File,RollingFile]-->
|
||||
@@ -21,14 +20,14 @@
|
||||
|
||||
<RollingRandomAccessFile name="RollingFileInfo" immediateFlush="false"
|
||||
fileName="${MSG_LOG_HOME}/wildfirechat.log"
|
||||
filePattern="${MSG_LOG_HOME}/backup/wildfirechat.%d{yyyyMMddHH}.zip">
|
||||
filePattern="${MSG_LOG_HOME}/backup/wildfirechat.%d{yyyyMMddHHmm}.zip">
|
||||
<Filters>
|
||||
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</Filters>
|
||||
<PatternLayout pattern="${pattern}" />
|
||||
<Policies>
|
||||
<!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval="6" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate="true" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->
|
||||
<!-- <TimeBasedTriggeringPolicy interval="6" modulate="true"/>-->
|
||||
<TimeBasedTriggeringPolicy interval="6" modulate="true"/>
|
||||
<!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->
|
||||
<SizeBasedTriggeringPolicy size="100 MB"/>
|
||||
</Policies>
|
||||
|
||||
@@ -31,6 +31,8 @@ local_port 80
|
||||
|
||||
## 是否使用内置DB。0使用mysql;1使用h2db。
|
||||
## MySQL需要把事物隔离级别改成"Read committed",使用命令来修改"set global transaction_isolation='read-committed';",其他数据库默认已经是这个级别不用修改
|
||||
## 如果使用MySQL,请在c3p0.xml文件中配置JDBC信息。
|
||||
## 如果是MySQL5.7,需要开启长索引的支持,在数据库中执行命令:"set global innodb_large_prefix=on;"。其他版本默认支持,不用修改。
|
||||
embed.db 1
|
||||
|
||||
## 是否自动清理历史消息记录,当为true时,IM服务会定时扫描t_messages_x和t_user_messages_x表,清除掉3年前的历史消息。
|
||||
@@ -39,6 +41,9 @@ embed.db 1
|
||||
## 使用mongodb时次开关无效(因为mongodb设置了消息过期时间,会自动清理,仅专业版支持mongodb)。
|
||||
db.auto_clean_history_messages true
|
||||
|
||||
## h2db数据库的路径,默认为程序目录下的,可以指定其他目录。如果使用MySQL,可以忽略此配置
|
||||
h2db.path ./h2db/wfchat
|
||||
|
||||
##服务器管理接口密钥。如果修改此端口需要同步修改使用管理API的地方,比如应用服务。
|
||||
http.admin.secret_key 123456
|
||||
|
||||
@@ -52,6 +57,15 @@ token.key testim
|
||||
##token的过期时间,单位为毫秒,默认为无限期。如果需要设置无限期,客户端上一定需要加上token过期的处理。token过期的处理请参考文档的常见问题
|
||||
##token.expire_time 2592000000
|
||||
|
||||
##客户端(目前只有android)的应用签名(一个应用最取第一个签名),如果有多个签名(多个客户端),用英文逗号分开。获取签名方法请参考文档:https://docs.wildfirechat.cn/blogs/签名验证.html
|
||||
#connect.client_signature_list eNkezQ1g9OsnhfLSFUY1vzKDzhs=,xykezQ1g9OsnhfLSFUY1vzKDzhs=
|
||||
|
||||
##是否拒绝空签名的android客户端, 默认为true。当有旧的客户端需要兼容时改成false,当所有都是新客户端时,改成true。
|
||||
#connect.reject_empty_signature true
|
||||
|
||||
##是否使用AES256加密。默认客户端和服务器都是AES128加密,如果需要开启AES256,需要客户端和IM服务同时开通。
|
||||
#encrypt.use_aes256 true
|
||||
|
||||
##首次登录,是否接收之前的历史消息。
|
||||
##0 不接收历史消息,只接收${message.compensate_time_limit}毫秒以内的消息,由于服务器没有保存已经收取记录,所以如果有超过${message.compensate_time_limit}毫秒之前未收取的消息也不会收取下拉;
|
||||
##1接收,会接收 message.max_queue 配置的条数的历史消息
|
||||
@@ -72,6 +86,9 @@ message.chatroom_remote_history_message 1
|
||||
##是否禁止陌生人聊天
|
||||
message.disable_stranger_chat false
|
||||
|
||||
##当禁止陌生人聊天时,允许聊天的用户id,比如管理员或者文件传输助手等。用户id以英文逗号分割。
|
||||
message.allow_stranger_chat_list admin,FireRobot,wfc_file_transfer
|
||||
|
||||
##黑名单策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃
|
||||
message.blacklist.strategy 0
|
||||
|
||||
@@ -135,11 +152,8 @@ friend.reject_request_duration 2592000000
|
||||
##好友请求过期时间,单位是毫秒,默认是7天,0为无限长期限。
|
||||
friend.request_expiration_duration 604800000
|
||||
|
||||
##添加好友后会发送欢迎消息,比如"你们已经是好友了,可以聊天了"。这个开关控制是用旧的方式还是用新的方式。
|
||||
##旧的方式会发送notification消息(contenttype是80),内容会根据好友接收者的语言选择对应的语言,如果双方语言不一致会导致另外一方看到的不是本地语言。
|
||||
##新的方式会发送添加好友消息(contenttype是93)和欢迎消息(contenttype是92),需要客户端实现这两种消息。
|
||||
##如果客户端已经实现这两种消息可以打开这个开关(客户端2020.6.30添加了此消息类型)。
|
||||
friend.new_welcome_message true
|
||||
##请求添加机器人为好友时,机器人是否自动接受,默认为true
|
||||
friend.robot_auto_accept true
|
||||
|
||||
## 聊天室观众空闲退出时间,单位为毫秒,默认为15分钟,0为永远不退出
|
||||
chatroom.participant_idle_time 900000
|
||||
@@ -161,6 +175,10 @@ group.allow_robot_custom_operation_notification true
|
||||
## 如果应用需要退群或者踢人不通知普通成员,请设置此参数为3,然后修改客户端踢人或退群消息的flag为not_presist。
|
||||
group.visible_quit_or_kickoff_notification 0
|
||||
|
||||
## 禁止客户端群操作。第1位是禁止创建群组,第2位是禁止销毁群组,3位禁止加入群,4位禁止退出群,5位禁止邀请群成员,6位禁止移出群成员,7位禁止转移群,8位禁止设置群管理员,9位禁止白名单处理,10位禁止群禁言,11位禁止修改群组信息,12位禁止群成员禁言。
|
||||
## 如果有客户端有被破解的风险,可以禁止客户端群操作,然后通过Server API操作。Server API不受限制。
|
||||
#group.forbidden_client_operation 0xFFF
|
||||
|
||||
## 隐藏用户信息属性类型,2是性别,3是电话号码,4是邮箱,5是地址,6是公司信息,7是社交账号,8是Extra信息。当需要隐藏多个时以英文逗号分开;
|
||||
## 本配置是为了提高安全性,避免把对应信息同步到客户端,这样就能防止程序被破解从而拿到用户关键信息。仅对客户端有效,server api不受影响。
|
||||
## 注意,修改本配置不会对已经同步的信息产生影响。
|
||||
@@ -184,11 +202,6 @@ http.channel.rate_limit 1000
|
||||
##客户端请求频率限制,默认是5秒100次。通常情况下不要修改这个值。
|
||||
client.request_rate_limit 100
|
||||
|
||||
#*********************************************************************
|
||||
# hazelcase configuration
|
||||
#*********************************************************************
|
||||
hazelcast.configuration config/hazelcast.xml
|
||||
|
||||
#*********************************************************************
|
||||
# Media server configuration
|
||||
#*********************************************************************
|
||||
@@ -296,18 +309,25 @@ push.ios.server.address http://localhost:8085/ios/push
|
||||
|
||||
##消息转发地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.forward.url http://localhost:8087/im_event/message
|
||||
##需要转发的消息类型,当有多个时以英文逗号分割。如果转发所有消息,请注释掉配置或者设置为空
|
||||
#message.forward.types 1,2,3
|
||||
#message.forward.url http://localhost:8888/im_event/message
|
||||
##需要转发的消息类型,当有多个时以英文逗号分割,可以用-来指定区间,注意区间不能太大,因为要把区间内的所有数字都放入到Set中。如果转发所有消息,请注释掉配置或者设置为空
|
||||
#message.forward.types 1,2,3,5-10
|
||||
##需要转发的消息类型,当有多个时以英文逗号分割,可以用-来指定区间,注意区间不能太大,因为要把区间内的所有数字都放入到Set中。
|
||||
#message.forward.exclude_types 1,2,3,5-10
|
||||
|
||||
##敏感消息转发地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.sensitive.forward.url http://localhost:8888/im_event/message
|
||||
|
||||
##提醒消息转发地址,@全体用户和@某个用户消息会回调此地址。此转发不受${message.forward.types}限制。
|
||||
##提醒消息转发地址,@全体用户和@某个用户消息会回调此地址。
|
||||
##此转发不受${message.forward.types}和${message.forward.exclude_types}限制。
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.mentionmsg.forward.url http://localhost:8888/im_event/message
|
||||
|
||||
##撤回消息转发地址,当用户撤回消息会回调此地址。
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#message.recallmsg.forward.url http://localhost:8888/im_event/recall_message
|
||||
|
||||
##设备信息转发地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
#things_message.forward.url http://localhost:8087/im_event/things/message
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
set -e
|
||||
|
||||
cd /opt/im-server
|
||||
tar -xzvf distribution*.tar.gz
|
||||
|
||||
sed -i 's/h2db.path .\/h2db\/wfchat/h2db.path \/var\/lib\/im-server\/h2db\/imdb/' /opt/im-server/config/wildfirechat.conf
|
||||
sed -i 's/local.media.storage.root .\/media/local.media.storage.root \/var\/lib\/im-server\/media/' /opt/im-server/config/wildfirechat.conf
|
||||
sed -i 's/<Property name="MSG_LOG_HOME">.\/logs<\/Property>/<Property name="MSG_LOG_HOME">\/var\/log\/im-server<\/Property>/' /opt/im-server/config/log4j2.xml
|
||||
sed -i 's/WILDFIRECHAT_CONFIG_PATH=$WILDFIRECHAT_HOME/WILDFIRECHAT_CONFIG_PATH=\/etc\/im-server/' /opt/im-server/bin/wildfirechat.sh
|
||||
|
||||
if [ ! -d /etc/im-server ]; then
|
||||
mkdir /etc/im-server
|
||||
fi
|
||||
|
||||
if [ ! -d /var/log/im-server ]; then
|
||||
mkdir /var/log/im-server
|
||||
fi
|
||||
|
||||
mv -f /opt/im-server/config /etc/im-server
|
||||
systemctl daemon-reload
|
||||
|
||||
echo "IM server folders:"
|
||||
echo "/etc/im-server/config config"
|
||||
echo "/opt/im-server binary files"
|
||||
echo "/var/log/im-server logs"
|
||||
echo "/var/lib/im-server/h2db embed db"
|
||||
echo "/var/lib/im-server/media embed media files"
|
||||
@@ -0,0 +1,16 @@
|
||||
set -e
|
||||
rm -rf /opt/im-server
|
||||
rm -rf /etc/im-server
|
||||
rm -rf /var/log/im-server
|
||||
rm -rf /usr/lib/systemd/system/im-server.service
|
||||
|
||||
if [ -d /var/lib/im-server/h2db ]; then
|
||||
echo "IM embed db file not deleted in path /var/lib/im-server/h2db, if you don't need it anymore, please remove it manually"
|
||||
fi
|
||||
|
||||
if [ -d /var/lib/im-server/media ]; then
|
||||
echo "IM embed media files not deleted in path /var/lib/im-server/media, if you don't need it anymore, please remove it manually"
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
pid=`ps -ef | grep wildfirechat.server.Server | grep -v grep | awk '{print $2}'`
|
||||
|
||||
if [ -z $pid ]; then
|
||||
echo "野火IM服务不存在"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
kill -15 $pid
|
||||
|
||||
for i in {1..15}
|
||||
do
|
||||
pid=`ps -ef | grep wildfirechat.server.Server | grep -v grep | awk '{print $2}'`
|
||||
if [ -z $pid ]; then
|
||||
echo "野火IM服务已结束"
|
||||
exit 0
|
||||
else
|
||||
echo "正在结束中,请等待..."
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "正常结束失败,强制结束!"
|
||||
kill -9 $pid
|
||||
@@ -1,82 +1,87 @@
|
||||
@ECHO OFF
|
||||
|
||||
set "CURRENT_DIR=%cd%"
|
||||
set "WILDFIRECHAT_HOME=%CURRENT_DIR%"
|
||||
if exist "%WILDFIRECHAT_HOME%\bin\wildfirechat.bat" goto okHome
|
||||
cd ..
|
||||
set "WILDFIRECHAT_HOME=%cd%"
|
||||
set "CURRENT_DIR=%cd%"
|
||||
:gotHome
|
||||
if exist "%WILDFIRECHAT_HOME%\bin\wildfirechat.bat" goto okHome
|
||||
echo The WILDFIRECHAT_HOME environment variable is not defined correctly
|
||||
echo This environment variable is needed to run this program
|
||||
goto end
|
||||
:okHome
|
||||
|
||||
rem Set JavaHome if it exists
|
||||
if exist { "%JAVA_HOME%\bin\java" } (
|
||||
set "JAVA="%JAVA_HOME%\bin\java""
|
||||
) else {
|
||||
set "JAVA="java""
|
||||
}
|
||||
|
||||
echo Using JAVA_HOME: "%JAVA_HOME%"
|
||||
echo Using WILDFIRECHAT_HOME: "%WILDFIRECHAT_HOME%"
|
||||
|
||||
rem set LOG_CONSOLE_LEVEL=info
|
||||
rem set LOG_FILE_LEVEL=fine
|
||||
set JAVA_OPTS=
|
||||
set JAVA_OPTS_SCRIPT=-XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true
|
||||
set WILDFIRECHAT_PATH=%WILDFIRECHAT_HOME%
|
||||
set LOG_FILE=%WILDFIRECHAT_HOME%\config\log4j2.xml
|
||||
set HZ_CONF_FILE=%WILDFIRECHAT_HOME%\config\hazelcast.xml
|
||||
set C3P0_CONF_FILE=%WILDFIRECHAT_HOME%\config\c3p0-config.xml
|
||||
|
||||
rem Use the Hotspot garbage-first collector.
|
||||
set JAVA_OPTS=%JAVA_OPTS% -XX:+UseG1GC
|
||||
|
||||
rem Have the JVM do less remembered set work during STW, instead
|
||||
rem preferring concurrent GC. Reduces p99.9 latency.
|
||||
set JAVA_OPTS=%JAVA_OPTS% -XX:G1RSetUpdatingPauseTimePercent=5
|
||||
|
||||
rem Main G1GC tunable: lowering the pause target will lower throughput and vise versa.
|
||||
rem 200ms is the JVM default and lowest viable setting
|
||||
rem 1000ms increases throughput. Keep it smaller than the timeouts.
|
||||
set JAVA_OPTS=%JAVA_OPTS% -XX:MaxGCPauseMillis=500
|
||||
|
||||
rem Optional G1 Settings
|
||||
|
||||
rem Save CPU time on large (>= 16GB) heaps by delaying region scanning
|
||||
rem until the heap is 70% full. The default in Hotspot 8u40 is 40%.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:InitiatingHeapOccupancyPercent=70
|
||||
|
||||
rem For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores.
|
||||
rem Otherwise equal to the number of cores when 8 or less.
|
||||
rem Machines with > 10 cores should try setting these to <= full cores.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:ParallelGCThreads=16
|
||||
|
||||
rem By default, ConcGCThreads is 1/4 of ParallelGCThreads.
|
||||
rem Setting both to the same value can reduce STW durations.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:ConcGCThreads=16
|
||||
|
||||
rem rem GC logging options -- uncomment to enable
|
||||
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDetails
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDateStamps
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintHeapAtGC
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintTenuringDistribution
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCApplicationStoppedTime
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintPromotionFailure
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:PrintFLSStatistics=1
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+UseGCLogFileRotation
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:NumberOfGCLogFiles=10
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:GCLogFileSize=10M"
|
||||
|
||||
echo
|
||||
echo 请设置JVM参数Xmx和Xms!!!
|
||||
echo
|
||||
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -Xmx2G
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -Xms2G
|
||||
|
||||
%JAVA% -server %JAVA_OPTS% %JAVA_OPTS_SCRIPT% -Dlog4j.configurationFile=%LOG_FILE% -Dcom.mchange.v2.c3p0.cfg.xml=%C3P0_CONF_FILE% -Dhazelcast.configuration=file:%HZ_CONF_FILE% -Dwildfirechat.path=%WILDFIRECHAT_PATH% -cp %WILDFIRECHAT_HOME%\lib\* cn.wildfirechat.server.Server
|
||||
@ECHO OFF
|
||||
|
||||
set "CURRENT_DIR=%cd%"
|
||||
set "WILDFIRECHAT_HOME=%CURRENT_DIR%"
|
||||
if exist "%WILDFIRECHAT_HOME%\bin\wildfirechat.bat" goto okHome
|
||||
cd ..
|
||||
set "WILDFIRECHAT_HOME=%cd%"
|
||||
set "CURRENT_DIR=%cd%"
|
||||
:gotHome
|
||||
if exist "%WILDFIRECHAT_HOME%\bin\wildfirechat.bat" goto okHome
|
||||
echo The WILDFIRECHAT_HOME environment variable is not defined correctly
|
||||
echo This environment variable is needed to run this program
|
||||
goto end
|
||||
:okHome
|
||||
|
||||
rem Set JavaHome if it exists
|
||||
if exist [ "%JAVA_HOME%\bin\java" ] (
|
||||
set "JAVA="%JAVA_HOME%\bin\java""
|
||||
) else (
|
||||
set "JAVA="java""
|
||||
)
|
||||
|
||||
echo Using JAVA_HOME: "%JAVA_HOME%"
|
||||
echo Using WILDFIRECHAT_HOME: "%WILDFIRECHAT_HOME%"
|
||||
|
||||
rem set LOG_CONSOLE_LEVEL=info
|
||||
rem set LOG_FILE_LEVEL=fine
|
||||
set JAVA_OPTS=
|
||||
set JAVA_OPTS_SCRIPT=-XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true
|
||||
set WILDFIRECHAT_PATH=%WILDFIRECHAT_HOME%
|
||||
set LOG_FILE=%WILDFIRECHAT_HOME%\config\log4j2.xml
|
||||
set HZ_CONF_FILE=%WILDFIRECHAT_HOME%\config\hazelcast.xml
|
||||
set C3P0_CONF_FILE=%WILDFIRECHAT_HOME%\config\c3p0-config.xml
|
||||
|
||||
rem Use the Hotspot garbage-first collector.
|
||||
set JAVA_OPTS=%JAVA_OPTS% -XX:+UseG1GC
|
||||
|
||||
rem Have the JVM do less remembered set work during STW, instead
|
||||
rem preferring concurrent GC. Reduces p99.9 latency.
|
||||
set JAVA_OPTS=%JAVA_OPTS% -XX:G1RSetUpdatingPauseTimePercent=5
|
||||
|
||||
rem Main G1GC tunable: lowering the pause target will lower throughput and vise versa.
|
||||
rem 200ms is the JVM default and lowest viable setting
|
||||
rem 1000ms increases throughput. Keep it smaller than the timeouts.
|
||||
set JAVA_OPTS=%JAVA_OPTS% -XX:MaxGCPauseMillis=500
|
||||
|
||||
rem Optional G1 Settings
|
||||
|
||||
rem Save CPU time on large (>= 16GB) heaps by delaying region scanning
|
||||
rem until the heap is 70% full. The default in Hotspot 8u40 is 40%.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:InitiatingHeapOccupancyPercent=70
|
||||
|
||||
rem For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores.
|
||||
rem Otherwise equal to the number of cores when 8 or less.
|
||||
rem Machines with > 10 cores should try setting these to <= full cores.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:ParallelGCThreads=16
|
||||
|
||||
rem By default, ConcGCThreads is 1/4 of ParallelGCThreads.
|
||||
rem Setting both to the same value can reduce STW durations.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:ConcGCThreads=16
|
||||
|
||||
rem rem GC logging options -- uncomment to enable
|
||||
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDetails
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDateStamps
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintHeapAtGC
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintTenuringDistribution
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCApplicationStoppedTime
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintPromotionFailure
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:PrintFLSStatistics=1
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:+UseGCLogFileRotation
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:NumberOfGCLogFiles=10
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -XX:GCLogFileSize=10M"
|
||||
|
||||
rem If the JDK version is 9 or above, please open this configuration.
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% --add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
|
||||
|
||||
echo
|
||||
echo "Please set Xmx and Xms parameters!"
|
||||
echo "Please set Xmx and Xms parameters!"
|
||||
echo "Please set Xmx and Xms parameters!"
|
||||
echo
|
||||
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -Xmx2G
|
||||
rem set JAVA_OPTS=%JAVA_OPTS% -Xms2G
|
||||
|
||||
%JAVA% -server %JAVA_OPTS% %JAVA_OPTS_SCRIPT% -Dlog4j.configurationFile=%LOG_FILE% -Dcom.mchange.v2.c3p0.cfg.xml=%C3P0_CONF_FILE% -Dhazelcast.configuration=%HZ_CONF_FILE% -Dwildfirechat.path=%WILDFIRECHAT_PATH% -cp %WILDFIRECHAT_HOME%\lib\* cn.wildfirechat.server.Server
|
||||
|
||||
@@ -18,7 +18,6 @@ while [ -h "$PRG" ]; do
|
||||
done
|
||||
|
||||
PRGDIR=`dirname "$PRG"`
|
||||
cd $PRGDIR
|
||||
cd ..
|
||||
WILDFIRECHAT_HOME=`pwd`
|
||||
|
||||
@@ -34,11 +33,15 @@ else
|
||||
fi
|
||||
export JAVA
|
||||
|
||||
LOG_FILE=$WILDFIRECHAT_HOME/config/log4j2.xml
|
||||
HZ_CONF_FILE=$WILDFIRECHAT_HOME/config/hazelcast.xml
|
||||
C3P0_CONF_FILE=$WILDFIRECHAT_HOME/config/c3p0-config.xml
|
||||
$JAVA -version
|
||||
|
||||
WILDFIRECHAT_CONFIG_PATH=$WILDFIRECHAT_HOME
|
||||
|
||||
LOG_FILE=$WILDFIRECHAT_CONFIG_PATH/config/log4j2.xml
|
||||
HZ_CONF_FILE=$WILDFIRECHAT_CONFIG_PATH/config/hazelcast.xml
|
||||
C3P0_CONF_FILE=$WILDFIRECHAT_CONFIG_PATH/config/c3p0-config.xml
|
||||
|
||||
|
||||
WILDFIRECHAT_PATH=$WILDFIRECHAT_HOME/
|
||||
#LOG_CONSOLE_LEVEL=info
|
||||
#LOG_FILE_LEVEL=fine
|
||||
JAVA_OPTS_SCRIPT="-XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true"
|
||||
@@ -83,6 +86,8 @@ JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=500"
|
||||
#JAVA_OPTS="$JAVA_OPTS -XX:NumberOfGCLogFiles=10"
|
||||
#JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M"
|
||||
|
||||
#如果JDK版本是9及以上,请打开这个配置
|
||||
#JAVA_OPTS="$JAVA_OPTS --add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED"
|
||||
|
||||
echo "警告:没有设置JVM内存参数!"
|
||||
echo "请设置JVM参数Xmx和Xms,设置为您为IM服务预留的内存大小,注意需要刨除操作系统占用,如果有其它系统也需要相应去除占用。"
|
||||
@@ -91,4 +96,4 @@ echo ""
|
||||
#JAVA_OPTS="$JAVA_OPTS -Xms2G"
|
||||
|
||||
|
||||
$JAVA -server $JAVA_OPTS $JAVA_OPTS_SCRIPT -Dlog4j.configurationFile="file:$LOG_FILE" -Dlog4j2.formatMsgNoLookups=true -Dcom.mchange.v2.c3p0.cfg.xml="$C3P0_CONF_FILE" -Dhazelcast.configuration="file:$HZ_CONF_FILE" -Dwildfirechat.path="$WILDFIRECHAT_PATH" -cp "$WILDFIRECHAT_HOME/lib/*" cn.wildfirechat.server.Server
|
||||
$JAVA -server $JAVA_OPTS $JAVA_OPTS_SCRIPT -Dlog4j.configurationFile="file:$LOG_FILE" -Dlog4j2.formatMsgNoLookups=true -Dcom.mchange.v2.c3p0.cfg.xml="$C3P0_CONF_FILE" -Dhazelcast.configuration=$HZ_CONF_FILE -Dwildfirechat.path="$WILDFIRECHAT_CONFIG_PATH" -cp "$WILDFIRECHAT_HOME/lib/*" cn.wildfirechat.server.Server
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
FROM openjdk:8-jre-alpine
|
||||
|
||||
ADD ../distribution/target/distribution-*-bundle-tar.tar.gz /opt/im-server/
|
||||
ADD distribution-*-bundle-tar.tar.gz /opt/im-server/
|
||||
|
||||
RUN sed -i 's/#JAVA_OPTS="$JAVA_OPTS -Xmx128M"/JAVA_OPTS="$JAVA_OPTS -Xmx$JVM_XMX"/g' /opt/im-server/bin/wildfirechat.sh
|
||||
RUN sed -i 's/#JAVA_OPTS="$JAVA_OPTS -Xms128M"/JAVA_OPTS="$JAVA_OPTS -Xms$JVM_XMS"/g' /opt/im-server/bin/wildfirechat.sh
|
||||
@@ -9,6 +9,8 @@ WORKDIR /opt/im-server
|
||||
|
||||
VOLUME /opt/im-server/config
|
||||
VOLUME /opt/im-server/logs
|
||||
VOLUME /opt/im-server/h2db
|
||||
VOLUME /opt/im-server/media
|
||||
|
||||
EXPOSE 80/tcp 1883/tcp 8083/tcp 8084/tcp 18080/tcp
|
||||
|
||||
|
||||
+14
-3
@@ -5,15 +5,26 @@
|
||||
```
|
||||
mvn clean package
|
||||
```
|
||||
生成的软件包在```distribution/target/distribution-XX-bundle-tar.tar.gz```,把此软件包拷贝到docker目录下。
|
||||
|
||||
然后进入到docker目录下,编译镜像
|
||||
```
|
||||
sudo docker build -t wildfire_im .
|
||||
sudo docker build -t im-server .
|
||||
```
|
||||
|
||||
## 运行
|
||||
配置:
|
||||
运行需要手动指定配置目录,这样不用重新打包镜像。手动指定配置目录的方法如下,其中$PATH_TO_CONFIG为im配置目录,模版为```distribution/src/main/resources```目录:
|
||||
运行需要手动指定配置目录,手动指定配置目录的方法如下,其中$PATH_TO_CONFIG为im配置目录,需要为绝对路径,模版为```distribution/src/main/resources```目录。另外需要创建h2数据库目录(如果用mysql就不需要了)、日志目录、内置存储服务目录(如果使用其它对象存储服务就不需要了)。
|
||||
```
|
||||
sudo docker run -it -v $PATH_TO_CONFIG:/opt/im-server/config -v $PATH_TO_LOGS:/opt/im-server/logs -e JVM_XMX=256M -e JVM_XMS=256M -p 80:80 -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 18080:18080 wildfire_im
|
||||
sudo docker run -it --name im-server -v $PATH_TO_CONFIG:/opt/im-server/config -v $PATH_TO_LOGS:/opt/im-server/logs -v $PATH_TO_H2DB:/opt/im-server/h2db -v $PATH_TO_MEDIA:/opt/im-server/media -e JVM_XMX=256M -e JVM_XMS=256M -p 80:80 -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 18080:18080 im-server
|
||||
```
|
||||
|
||||
## 导出镜像
|
||||
```
|
||||
sudo docker save -o im-server.tar im-server
|
||||
```
|
||||
|
||||
## 导入镜像
|
||||
```
|
||||
sudo docker load -i im-server.tar
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<version>0.95</version>
|
||||
<version>1.1.4</version>
|
||||
<name>Wildfire Chat</name>
|
||||
<description>Wildfire Chat Server</description>
|
||||
<inceptionYear>2019</inceptionYear>
|
||||
|
||||
@@ -7,10 +7,87 @@
|
||||
6. *** 0.62/0.63 版本有严重的问题,请使用0.64及以后版本,或者0.61版。 ***
|
||||
7. *** 从0.68 版本起添加了pc在线是否默认手机接收推送的开关,默认为开,与以前版本作用相反,请注意兼容(可以关掉与之前保持一致或者升级客户端) ***
|
||||
8. *** 从0.78 版本起把MySQL数据库中关键字都改为大小写敏感,另外生成id的方法也做了改变,只生成小写的id,避免出现id重复的问题,建议所有客户都升级 ***
|
||||
9 *** 从0.79 版本起把log4j升级到log4j2,因为log4j已经不再维护而且还有已知的漏洞,建议所有客户都升级,升级时注意更新log4j2的配置文件 ***
|
||||
9. *** 从0.79 版本起把log4j升级到log4j2,因为log4j已经不再维护而且还有已知的漏洞,建议所有客户都升级,升级时注意更新log4j2的配置文件 ***
|
||||
10. *** 5. 0.97版本更改了启动脚本```wildfirechat.sh```,如果是升级服务,请注意更新启动脚本。***
|
||||
|
||||
# 更新记录
|
||||
|
||||
--------------
|
||||
Release note 1.1.4:
|
||||
1. 添加PC客户端多端登录互踢时没有更新pc在线状态问题。
|
||||
2. 添加支持使用AES256加密。
|
||||
3. Server API添加获取单个群成员的接口。
|
||||
4. 添加配置,添加机器人为好友时是否自动接受。
|
||||
|
||||
--------------
|
||||
Release note 1.1.3:
|
||||
1. 添加服务器和客户端时间检查功能。
|
||||
2. 解决用户被block后session失效的问题。
|
||||
3. 添加消息撤回回调。
|
||||
4. 优化群组撤回逻辑。
|
||||
5. 解决用户离开群组后还能修改群昵称的问题。
|
||||
6. 修改server api修改好友关系回调数据错误问题。
|
||||
7. 同步超级群组数据库和数据。
|
||||
|
||||
--------------
|
||||
Release note 1.1.2:
|
||||
1. 会议SDK添加查询会议是否存在的接口
|
||||
2. 单聊会话定向消息分发包含发送者
|
||||
|
||||
--------------
|
||||
Release note 1.1.1:
|
||||
1. 当用户获取群组信息,可以根据返回信息判断是否在群中。
|
||||
2. 搜索用户时,过滤掉已删除用户
|
||||
3. 支持单聊消息的定向消息
|
||||
4. 解决关闭roaming,且message.compensate_time_limit配置为-1时,首次消息无法同步的问题
|
||||
5. 解决禁止客户端群操作flag 解析错误
|
||||
|
||||
--------------
|
||||
Release note 1.1:
|
||||
1. Channel API添加检查用户是否订阅接口
|
||||
2. Server API发送消息时添加检查对象是否存在
|
||||
3. Channel API添加修改频道菜单接口
|
||||
4. 内置对象存储的优化
|
||||
|
||||
--------------
|
||||
Release note 1.0:
|
||||
1. SDK检查工具添加help命令
|
||||
2. 去掉短连接端口被网络爬虫扫描输出的异常日志
|
||||
3. API支持创建组织群
|
||||
4. 添加配置禁止客户端进行某些群操作
|
||||
5. 解决route请求时可能不能正确携带推送类型的问题
|
||||
6. 会议成员离开加上离开原因
|
||||
7. 添加停止程序的命令
|
||||
8. 添加RTP Forward的API
|
||||
|
||||
--------------
|
||||
Release note 0.99:
|
||||
1. API获取用户信息时,过滤掉已经删除用户。
|
||||
2. 消息转发功能支持设置include/exclude功能,支持按区间过滤。
|
||||
3. 添加新的群组类型:组织群。组织群适用于公司部门群场景。
|
||||
4. 内置对象存储支持绝对路径和相对路径配置
|
||||
5. 当开启禁止陌生人聊天时,可以添加例外人员
|
||||
6. 解决user setting并发问题
|
||||
7. 添加可选的android平台签名验证功能。
|
||||
|
||||
--------------
|
||||
Release note 0.98:
|
||||
1. 解决linux多端登录错误问题
|
||||
2. 添加获取用户群组和共同群组功能
|
||||
3. 解决windows下脚本编码错误问题
|
||||
|
||||
--------------
|
||||
Release note 0.97:
|
||||
1. 升级部分依赖库到最新版本
|
||||
2. 添加名片消息默认推送信息
|
||||
3. 添加deb和rpm格式软件包
|
||||
|
||||
--------------
|
||||
Release note 0.96:
|
||||
1. 文章消息添加摘要字段
|
||||
2. 单聊消息支持server api只发送给其中一方
|
||||
3. Server api添加会议录制/停止录制接口
|
||||
|
||||
--------------
|
||||
Release note 0.95:
|
||||
1. 添加按照用户删除会话接口
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 998 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 279 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 535 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 340 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user