Compare commits

..
69 Commits
Author SHA1 Message Date
heavyrian2012 a5f64df2de update version and release note 2025-11-09 11:42:48 +08:00
heavyrian2012 c7f1ea57dc 解决某些平台SDK内置消息没有注册的问题 2025-11-06 18:31:12 +08:00
heavyrian2012 c9b2de076d 默认用户ID搜索用户功能开启 2025-10-31 07:31:57 +08:00
heavyrian2012 552fadaa87 记录客户端来源IP地址 2025-10-26 16:57:33 +08:00
heavyrian2012 765572db36 移除掉无用的编译plugin,解决java8编译错误问题 2025-10-13 09:57:32 +08:00
heavyrian2012 a5f194b385 server api测试代码默认为社区版 2025-10-13 09:56:56 +08:00
heavyrian2012 c74cd7e290 解决server sdk解析图片消息不带缩略图解析错误问题 2025-09-29 20:39:12 +08:00
heavyrian2012 70cf65f0c0 解决Server SDK发送引用消息客户端无法正确解析的问题 2025-09-20 09:41:29 +08:00
heavyrian2012 3bb23f92c4 update version and release note 2025-09-07 09:44:42 +08:00
heavyrian2012 804c12845e fix error 2025-09-06 23:33:35 +08:00
heavyrian2012 fe15a32499 添加开关是否开启允许@不在会话中的机器人 2025-09-06 23:29:09 +08:00
heavyrian2012 06d168935d 支持@不在群组中的机器人和单人会话支持@机器人,支持机器人回复。 2025-09-06 21:36:29 +08:00
heavyrian2012 c1984d27b3 同步专业版SDK 2025-09-05 20:53:32 +08:00
heavyrian2012 29ef46b7a0 解决机器人和频道sdk检查端口错误提示的问题 2025-09-05 20:53:12 +08:00
heavyrian2012 0bdff3fd89 同步专业版server sdk 2025-08-30 10:18:34 +08:00
heavyrian2012 cd03583dab 解决server sdk反复初始化时内存泄漏问题 2025-08-25 11:11:12 +08:00
heavyrian2012 3f8fd7e5e0 update version and release note 2025-08-17 14:46:20 +08:00
heavyrian2012 fdfe71f700 server api添加群备注和收藏群组接口 2025-08-17 14:45:38 +08:00
heavyrian2012 35ecf7ccc6 发送消息的server api添加参数,可以以用户权限发送消息 2025-08-17 10:51:39 +08:00
heavyrian2012 8f798742c3 同步专业版sdk 2025-08-17 10:51:08 +08:00
heavyrian2012 f4ea8b184c 如果server sdk没有初始化,打印出初始化的代码和提示 2025-08-12 12:19:52 +08:00
heavyrian2012 2d7f344b1a 可以系统设置里设置那么名字不能被使用 2025-08-05 17:11:00 +08:00
heavyrian2012 bee03cd2f8 添加配置敏感词检查用户昵称/群组名/群备注等信息 2025-08-05 15:32:20 +08:00
heavyrian2012 59b1c3180f 现在发送消息大小不能超过64KB 2025-08-03 18:04:12 +08:00
heavyrian2012 88d764fb6d update version and release note 2025-08-02 10:45:59 +08:00
heavyrian2012 08b3886238 解决机器人回调配置带上发送人信息功能无效问题 2025-08-02 10:38:09 +08:00
heavyrian2012 7e73c2880b 支持客户端上传本地角标,当需要推送时会把角标数字带上 2025-07-29 11:51:11 +08:00
heavyrian2012 1359ce5250 解决上传文件可能内存泄漏的问题 2025-07-18 21:17:13 +08:00
heavyrian2012 56eaf938a8 添加注释 2025-07-16 17:50:18 +08:00
heavyrian2012 6ef6ed2906 添加群组成员时支持部分成员失败 2025-07-05 16:47:15 +08:00
heavyrian2012 63f37e8984 更新sdk接口测试的说明 2025-07-04 14:03:06 +08:00
heavyrian2012 337302c551 update readme 2025-06-29 11:32:04 +08:00
heavyrian2012 721f27a58a 搜索用户可以指定搜索用户或者机器人 2025-06-22 14:59:34 +08:00
heavyrian2012 ced74280d8 version and release note 2025-06-19 19:19:21 +08:00
heavyrian2012 18617c67f4 api/version和gettoken都添加节点信息 2025-06-19 19:15:35 +08:00
heavyrian2012 883866ce39 配置文件添加注释 2025-06-17 16:02:40 +08:00
heavyrian2012 2e135d4794 群组成员表添加一条索引 2025-06-14 12:38:16 +08:00
heavyrian2012 1d6faa5796 server api支持修改群组类型 2025-05-29 14:18:29 +08:00
heavyrian2012 731fa00cc9 创建/更新频道接口添加频道菜单属性 2025-05-12 14:27:07 +08:00
heavyrian2012 4da9173c5f 修改撤回时间配置,可以配置为不允许撤回 2025-05-10 08:12:20 +08:00
heavyrian2012 94e430cc83 解决外置消息审核回调没有回调成功的问题 2025-05-05 16:52:19 +08:00
heavyrian2012 7e92d1e0c5 Server API创建频道时,需要同时返回频道ID和频道密钥 2025-04-25 23:10:43 +08:00
heavyrian2012 4fa79bfeac 频道和机器人API添加对端口的检查提示 2025-04-22 12:21:45 +08:00
heavyrian2012 98388a5129 update version and release note 2025-04-18 20:03:38 +08:00
heavyrian2012 1a89714df9 配置文件中群组标记删除默认开启 2025-04-18 19:59:37 +08:00
heavyrian2012 a855652c26 音视频通话挂断时推送数据包含开始通话的消息UID 2025-04-18 11:12:15 +08:00
heavyrian2012 21aadd9c0b 去掉空的echo 2025-04-14 10:42:26 +08:00
heavyrian2012 5522a8689d server api添加日志 2025-04-13 18:26:07 +08:00
heavyrian2012 bf52a00304 添加配置是否允许发送消息给被封禁用户 2025-04-12 14:00:55 +08:00
heavyrian2012 3349e2a4e5 添加server api发送朋友圈的api 2025-04-12 12:54:34 +08:00
heavyrian2012 70f3f96f7a server sdk添加撤回和删除消息 2025-04-12 09:57:10 +08:00
heavyrian2012 5e9d411f1b 内置存储支持在线播放 2025-04-09 16:40:37 +08:00
heavyrian2012 e74fd0c660 添加配置,转发消息时是否代码发送者信息和目标信息 2025-03-27 20:52:12 +08:00
heavyrian2012 d1232abe39 version and release note 2025-03-05 19:20:54 +08:00
heavyrian2012 1df192f730 解决分段拉取消息时可能丢消息的问题 2025-03-05 19:13:29 +08:00
heavyrian2012 f897e640fc SDK添加超时配置 2025-03-03 12:11:19 +08:00
heavyrian2012 ee6e4f96fb 配置允许撤回消息时间小于等于0时可以允许用户任意时间撤回消息 2025-02-21 19:28:57 +08:00
heavyrian2012 d14dc74566 sdk添加注册消息的接口,可以允许sdk注册自定义消息 2025-02-19 19:27:42 +08:00
heavyrian2012 ff75379779 优化server sdk 2025-02-18 09:53:34 +08:00
heavyrian2012 b95a6b7785 更新版本号和Release note 2025-02-13 19:00:39 +08:00
heavyrian2012 5acb3044ac Revert "serveri api获取用户信息时返回deleted字段"
This reverts commit ae084063f4.
2025-01-24 10:34:53 +08:00
heavyrian2012 ae084063f4 serveri api获取用户信息时返回deleted字段 2025-01-23 16:27:36 +08:00
heavyrian2012 cb3a82559d 机器人API添加定向消息参数 2025-01-17 20:17:18 +08:00
heavyrian2012 9191204bb0 nginx配置注释 2025-01-15 10:07:37 +08:00
heavyrian2012 6587a88ca9 修改注释 2025-01-14 11:07:39 +08:00
heavyrian2012 86c1a2e140 转移群主时检查目标用户是否在群组中 2025-01-03 21:33:46 +08:00
heavyrian2012 83e9679339 SDK的地址和密钥添加trim,避免空格换行等问题 2025-01-02 14:23:23 +08:00
heavyrian2012 dafb0cd4d9 修改nginx配置示例中上传文件的大小为200MB 2024-12-26 08:42:24 +08:00
heavyrian2012 cbcc8310c4 敏感词过滤类型默认改成2 2024-12-15 10:47:45 +08:00
108 changed files with 2551 additions and 438 deletions
+2 -1
View File
@@ -44,7 +44,8 @@
| [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)。 |
| [pc-chat(electron)](https://github.com/wildfirechat/vue-pc-chat) | [pc-chat(electron)](https://gitee.com/wfchat/vue-pc-chat) | 基于[Electron](https://electronjs.org/)开发的PC 端 | |
| [pc-chat(Qt)](https://github.com/wildfirechat/qt-pc-chat) | [pc-chat(Qt)](https://gitee.com/wfchat/qt-pc-chat) | 基于Qt开发的PC 端 | |
| [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平台移动端应用(使用原生插件)。 |
+40 -4
View File
@@ -111,7 +111,7 @@ message.disable_remote_search false
##如果要避免数据库中明文存储消息内容,请打开这个开关和message.disable_remote_search开关
message.encrypt_message_content false
##允许客户端撤回用户自己发送的消息时限,单位是秒。
##允许客户端撤回用户自己发送的消息时限,单位是秒。0是不允许撤回;-1是无限制撤回。
##Server API不受此限制,可以撤回任意时限内的消息
##群组管理员或群主撤回群成员消息不受此限制,可以撤回任意时限内的消息。但管理员或群主撤回自己的消息还是需要准守此时间限制。
##修改此参数需要同步修改客户端UI,客户端UI代码有判断撤回是否显示的逻辑。
@@ -152,12 +152,37 @@ message.no_forward_admin_message false
## 消息转发功能开启时,转发信息是否带上用户clientId和平台类型。
message.forward_with_client_info false
## 消息转发功能开启时,转发信息是否带上发送者的用户信息
message.forward_with_sender_info false
## 消息转发功能开启时,转发信息是否带上目标的信息,单聊时是对方用户信息,群聊时是群组信息,频道时是频道信息
message.forward_with_target_info false
## 允许发送单聊消息给被封禁用户
message.allow_send_to_forbidden_user false
## 机器人回调信息是否带上用户clientId和平台类型。
robot.callback_with_client_info false
## 机器人回调信息是否带上发送者的用户信息
robot.callback_with_sender_info false
## 机器人回调信息是否带上目标的信息,单聊时是对方用户信息,群聊时是群组信息,频道时是频道信息
robot.callback_with_target_info false
## 是否允许@会话外的机器人。如果为true,单聊或者群聊时,可以@不在会话中的机器人。当机器人收到消息后,可以回复消息。
## 如果为false,不能@不在会话中的机器人。机器人不在会话中时,也不能回复消息。
robot.mention_external_robot true
## 频道回调信息是否带上用户clientId和平台类型。
channel.callback_with_client_info false
## 频道回调信息是否带上发送者的用户信息。
channel.callback_with_sender_info false
## 频道回调信息是否带上频道信息
channel.callback_with_target_info false
## 频道回调新方式,在新方式下,如果有callback地址就会总是回调客户端发送的消息(包括owner和订阅者)。automatic属性控制订阅者发送的消息是否发给owner, 0发,1不发。
## 旧的方式是,automatic为0时,订阅者的消息发给owner,不转发消息到callback地址。为1时,把订阅者的消息转发给callback地址,不发给owner。
channel.new_callback_feature true
@@ -168,8 +193,8 @@ friend.disable_search false
##禁止按照昵称搜索用户。
friend.disable_nick_name_search false
##禁止按照用户id搜索用户,默认为true。
friend.disable_user_id_search true
##禁止按照用户id搜索用户,默认为false。
friend.disable_user_id_search false
##禁止发送好友邀请,通过server api添加好友不受此限制(force参数需要为true)
friend.disable_friend_request false
@@ -227,6 +252,10 @@ group.visible_quit_or_kickoff_notification 0
## 是否禁止陌生人拉人入群,默认为false
group.disable_stranger_invite false
## 创建群组或者加人时。可能会有成员加入失败(黑名单,或者不允许陌生人拉入群)。当出现有成员失败时,如果此开关为关,操作会失败。
## 如果此开关打开,操作会返回成功,另外在群里发送一条通知消息 XXX 拒绝加入群组。默认为开。
group.add_member_allow_part_success true
## 群组信息是否标记删除
group.enable_mark_deletion true
@@ -421,7 +450,14 @@ push.harmony.server.address http://localhost:8085/harmony/push
## 内置文本敏感词过滤处理方法,当命中敏感词后,消息会被记录到t_sensitive_messages表中,然后根据type类型做不同的处理,处理方式如下:
## 0 发送失败;1 发送成功但消息被服务器直接丢弃;2 命中的敏感词被替换成***然后正常发送;3 正常发送。
## 如果开启 message.sensitive.forward.url 配置,命中敏感词的消息还会被回调到这个地址
sensitive.filter.type 0
sensitive.filter.type 2
## 敏感词是否只处理消息。如果为true,只过滤消息;如果为false,会同时过滤用户昵称、群组名和群昵称。
## 除了消息之外的信息只支持内部敏感词处理,不支持外置审核。
sensitive.only_message false
## 敏感词添加或者删除有2种方式,一种是通过Server API进行,这种方式会立即生效。另外一种方法是修改数据库,直接中数据库的t_sensitive_word表中处理
## 修改数据库的方法不会立即生效,IM服务会2个小时重新加载一次敏感词。所以如果直接修改敏感词表,需要等2个小时,或者重启才能生效。
## 如果内置敏感词库无法满足您的需求,可以开发部署独立敏感词审核服务。配置如下地址和消息类型,IM服务会把指定消息类型的消息回调到指定地址,内置的敏感词审核和敏感词转发功能就不再起作用了。
## 审核服务返回状态码200表示继续发送,如果需要替换内容,返回状态码200并且内容为替换后的内容。返回403表示不允许发送。其它错误继续发送。
+1
View File
@@ -0,0 +1 @@
CREATE INDEX `user_gid_dt_index` ON `t_group_member` (`_gid`, `_dt`);
+1
View File
@@ -0,0 +1 @@
insert into t_settings(`id`, `_value`,`_desc`) values (2, '文件传输助手,客服,官方', '禁止使用名称,如果有多个,以英文逗号隔开。直接修改数据库,不用重启IM服务');
+1
View File
@@ -0,0 +1 @@
alter table `t_messages` modify column `_target` varchar(129) NOT NULL;
+1
View File
@@ -0,0 +1 @@
ALTER TABLE `t_user_session` ADD COLUMN `_ip` varchar(40) DEFAULT '';
+1
View File
@@ -0,0 +1 @@
CREATE INDEX `user_gid_mid_dt_index` ON `t_group_member` (`_gid`, `_mid`, `_dt`);
@@ -0,0 +1,2 @@
DROP INDEX `user_gid_mid_dt_index` ON `t_group_member`;
CREATE INDEX `user_gid_dt_index` ON `t_group_member` (`_gid`, `_dt`);
+1
View File
@@ -0,0 +1 @@
insert into t_settings(`id`, `_value`,`_desc`) values (2, '文件传输助手,客服,官方', '禁止使用名称,如果有多个,以英文逗号隔开。直接修改数据库,不用重启IM服务');
+37
View File
@@ -0,0 +1,37 @@
alter table `t_messages` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_0` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_1` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_2` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_3` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_4` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_5` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_6` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_7` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_8` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_9` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_10` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_11` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_12` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_13` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_14` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_15` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_16` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_17` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_18` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_19` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_20` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_21` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_22` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_23` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_24` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_25` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_26` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_27` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_28` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_29` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_30` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_31` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_32` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_33` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_34` modify column `_target` varchar(129) NOT NULL;
alter table `t_messages_35` modify column `_target` varchar(129) NOT NULL;
+1
View File
@@ -0,0 +1 @@
ALTER TABLE `t_user_session` ADD COLUMN `_ip` varchar(40) DEFAULT '';
+10 -1
View File
@@ -9,6 +9,7 @@ server {
root html;
index index.html index.htm index.php;
#同步服务设置
location /route {
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
@@ -16,7 +17,7 @@ server {
proxy_pass http://imserver;
}
#社区版需要启用下面一段,专业版不能用
#客户端短连接业务
location /im {
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
@@ -24,14 +25,21 @@ server {
proxy_pass http://imserver;
}
#版本检查/api/version,可以删掉
location /api {
proxy_pass http://imserver;
}
#内置文件上传和下载
location /fs {
client_max_body_size 200M;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://imserver;
}
#机器人API
location /robot {
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
@@ -39,6 +47,7 @@ server {
proxy_pass http://imserver;
}
#频道API
location /channel {
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
+1 -55
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.2</version>
<version>1.4.0</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -211,60 +211,6 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<!-- Generate the test-jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Includes to generate OSGi headers -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
@@ -36,6 +36,8 @@ public class PushMessage {
public String language;
public boolean republish;
public long messageId;
public long callStartUid;
public int existBadgeNumber;
public PushMessage(String sender, int conversationType, String target, int line, int messageContentType, long serverTime, String senderName, String senderPortrait, String targetName, String targetPortrait, int unReceivedMsg, int mentionedType, boolean isHiddenDetail, String language) {
this.sender = sender;
@@ -81,10 +81,6 @@ public class PushServer {
}
MemorySessionStore.Session session = sessionsStore.getSession(deviceId);
int badge = session.getUnReceivedMsgs();
if (badge <= 0) {
badge = 1;
}
if (StringUtil.isNullOrEmpty(session.getDeviceToken())) {
LOG.warn("Device token is empty for device {}", deviceId);
return;
@@ -94,7 +90,6 @@ public class PushServer {
pushMessage.pushType = session.getPushType();
pushMessage.pushContent = pushContent;
pushMessage.deviceToken = session.getDeviceToken();
pushMessage.unReceivedMsg = badge;
pushMessage.userId = session.getUsername();
if (session.getPlatform() == ProtoConstants.Platform.Platform_iOS ||
session.getPlatform() == ProtoConstants.Platform.Platform_iPad ||
@@ -8,9 +8,13 @@
package com.xiaoleilu.loServer.action;
import cn.wildfirechat.common.IMExceptionEvent;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.xiaoleilu.loServer.RestResult;
import com.xiaoleilu.loServer.action.channel.ChannelAction;
import com.xiaoleilu.loServer.action.robot.RobotAction;
import com.xiaoleilu.loServer.annotation.RequireAuthentication;
import com.xiaoleilu.loServer.handler.Request;
import com.xiaoleilu.loServer.handler.Response;
@@ -23,7 +27,10 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import cn.wildfirechat.common.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import win.liyufan.im.RateLimiter;
import win.liyufan.im.Utility;
import java.nio.charset.StandardCharsets;
@@ -38,6 +45,7 @@ import static io.moquette.BrokerConstants.*;
*/
abstract public class Action {
private static final Logger LOG = LoggerFactory.getLogger(Action.class);
public static IMessagesStore messagesStore = null;
public static ISessionsStore sessionsStore = null;
protected static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
@@ -153,9 +161,22 @@ abstract public class Action {
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
String content = new String(bytes, StandardCharsets.UTF_8);//contribute by JiaRG from github
T t = gson.fromJson(content, cls);
return t;
try {
T t = gson.fromJson(content, cls);
return t;
} catch (JsonSyntaxException e) {
e.printStackTrace();
LOG.error("Object {} from json {} failure", cls.getName(), content);
int exception = IMExceptionEvent.EventType.ADMIN_API_Exception;
if (this instanceof RobotAction) {
exception = IMExceptionEvent.EventType.ROBOT_API_Exception;
} else if (this instanceof ChannelAction) {
exception = IMExceptionEvent.EventType.CHANNEL_API_Exception;
}
Utility.printExecption(LOG, e, exception);
throw new RuntimeException(e);
}
}
return null;
}
@@ -1,8 +1,11 @@
package com.xiaoleilu.loServer.action;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@@ -13,6 +16,7 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.util.StringUtil;
import com.xiaoleilu.loServer.ServerSetting;
import com.xiaoleilu.loServer.handler.Request;
import com.xiaoleilu.loServer.handler.Response;
@@ -90,11 +94,26 @@ public class FileAction extends Action {
}
response.setContent(file);
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
if (isAudioOrVideoFile(file.getName())) {
response.setHeader("Accept-Ranges", "bytes");
} else {
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
}
return true;
}
private static boolean isAudioOrVideoFile(String name) {
try {
if (StringUtil.isNullOrEmpty(name)) return false;
String mimeType = Files.probeContentType(new File(name).toPath());
return mimeType != null && (mimeType.startsWith("audio/") || mimeType.startsWith("video/"));
} catch (IOException e) {
return false;
}
}
private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");
private static final SimpleDateFormat HTTP_DATE_FORMATER = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);
@@ -11,6 +11,7 @@ package com.xiaoleilu.loServer.action;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.hazelcast.util.StringUtil;
import com.xiaoleilu.loServer.annotation.HttpMethod;
import com.xiaoleilu.loServer.annotation.Route;
import com.xiaoleilu.loServer.handler.Request;
@@ -28,7 +29,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.wildfirechat.common.ErrorCode;
import java.net.InetSocketAddress;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.Executor;
@Route("/route")
@@ -111,6 +114,12 @@ public class RouteAction extends Action {
WFCMessage.IMHttpWrapper wrapper = WFCMessage.IMHttpWrapper.parseFrom(bytes);
String token = wrapper.getToken();
String userId = Tokenor.getUserId(token.getBytes());
String remote = ((InetSocketAddress) ctx.channel().remoteAddress())
.getAddress().getHostAddress();
String ip = computeRealIp(request.getHeaders(), remote);
LOG.info("RouteAction token={}, userId={}", token, userId);
if (userId == null) {
sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null);
@@ -119,6 +128,8 @@ public class RouteAction extends Action {
@Override
public void onSuccess(byte[] result) {
sendResponse(response, null, result);
//save ip after success response.
sessionsStore.updateSessionIp(userId, wrapper.getClientId(), ip);
}
@Override
@@ -147,6 +158,20 @@ public class RouteAction extends Action {
return true;
}
private String computeRealIp(Map<String, String> h, String remote) {
String xff = h.get("X-Forwarded-For");
if (xff != null && !xff.isEmpty() && !"unknown".equalsIgnoreCase(xff)) {
int idx = xff.indexOf(',');
String first = (idx > 0 ? xff.substring(0, idx) : xff).trim();
return first;
}
String xri = h.get("X-Real-IP");
if (xri != null && !xri.isEmpty() && !"unknown".equalsIgnoreCase(xri)) {
return xri;
}
return remote;
}
private void sendResponse(Response response, ErrorCode errorCode, byte[] contents) {
response.setStatus(HttpResponseStatus.OK);
if (contents == null) {
@@ -284,9 +284,10 @@ public class UploadFileAction extends Action {
savedThunkSize += readableBytesSize;
offset += readableBytesSize;
byteBuf.release();
byteBuf = null;
if (savedThunkSize >= remoteFileSize) {
byteBuf.release();
fileUpload.release();
response.setStatus(HttpResponseStatus.OK);
@@ -51,14 +51,7 @@ public class AliasPutAction extends AdminAction {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(result);
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
byte[] data = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(data);
String channelId = new String(data);
return new Result(ErrorCode.ERROR_CODE_SUCCESS, new OutputCreateChannel(channelId));
} else {
return new Result(errorCode);
}
return new Result(errorCode);
});
return false;
} else {
@@ -53,8 +53,11 @@ public class CreateChannelAction extends AdminAction {
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
byte[] data = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(data);
String channelId = new String(data);
return new Result(ErrorCode.ERROR_CODE_SUCCESS, new OutputCreateChannel(channelId));
String str = new String(data);
String[] ss = str.split("\\|");
String channelId = ss[0];
String secret = ss[1];
return new Result(ErrorCode.ERROR_CODE_SUCCESS, new OutputCreateChannel(channelId, secret));
} else {
return new Result(errorCode);
}
@@ -20,6 +20,7 @@ import io.netty.handler.codec.http.FullHttpRequest;
import cn.wildfirechat.common.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import win.liyufan.im.GitRepositoryState;
import win.liyufan.im.IMTopic;
import java.util.Base64;
@@ -53,7 +54,7 @@ public class GetIMTokenAction extends AdminAction {
LOG.info("get im token success {},{},{}", userId, input.getClientId(), token.substring(0, Math.min(10, token.length())));
return new Result(errorCode1, new OutputGetIMTokenData(userId, token));
return new Result(errorCode1, new OutputGetIMTokenData(userId, token, GitRepositoryState.globalLabel));
} else {
return new Result(errorCode1);
}
@@ -51,7 +51,7 @@ public class SendMessageAction extends AdminAction {
} else {
return new Result(errorCode);
}
});
}, sendMessageData.isUserMessage());
return false;
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
@@ -105,18 +105,6 @@ abstract public class ChannelAction extends Action {
response.send();
}
protected <T> T getRequestBody(HttpRequest request, Class<T> cls) {
if (request instanceof FullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
String content = new String(bytes, StandardCharsets.UTF_8);
T t = gson.fromJson(content, cls);
return t;
}
return null;
}
protected void sendApiMessage(Response response, String topic, byte[] message, Callback callback) {
sendApiMessage(response, channelInfo.getOwner(), topic, message, callback);
}
@@ -0,0 +1,112 @@
/*
* 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.Conversation;
import cn.wildfirechat.pojos.ReplyMessageData;
import cn.wildfirechat.pojos.SendMessageData;
import cn.wildfirechat.pojos.SendMessageResult;
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.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.jetbrains.annotations.NotNull;
import win.liyufan.im.IMTopic;
import java.util.Arrays;
@Route(APIPath.Robot_Message_Reply)
@HttpMethod("POST")
public class ReplyMessageAction extends RobotAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
ReplyMessageData replyMessageData = getRequestBody(request.getNettyRequest(), ReplyMessageData.class);
if (ReplyMessageData.isValide(replyMessageData)) {
WFCMessage.Message message = messagesStore.getMessage(replyMessageData.getMessageUid());
ErrorCode errorCode = null;
if(message == null) {
errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;
} else if(!message.getContent().getMentionedTargetList().contains(robot.getUid())) {
errorCode = ErrorCode.ERROR_CODE_INVALID_MESSAGE;
} else if(message.getConversation().getType() != ProtoConstants.ConversationType.ConversationType_Private && message.getConversation().getType() != ProtoConstants.ConversationType.ConversationType_Group) {
errorCode = ErrorCode.ERROR_CODE_NOT_IMPLEMENT;
} else if(System.currentTimeMillis() - message.getServerTimestamp() > 15*60*1000) {
errorCode = ErrorCode.ERROR_CODE_RECALL_TIME_EXPIRED;
} else if(!messagesStore.isRobotMentionExternalRobot()) {
if(message.getConversation().getType() != ProtoConstants.ConversationType.ConversationType_Group) {
errorCode = ErrorCode.ERROR_CODE_NOT_IMPLEMENT;
} else {
WFCMessage.GroupMember member = messagesStore.getGroupMember(message.getConversation().getTarget(), robot.getUid());
if(member == null || member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {
errorCode = ErrorCode.ERROR_CODE_NOT_IMPLEMENT;
}
}
}
if(errorCode != null) {
response.setStatus(HttpResponseStatus.OK);
RestResult result = RestResult.resultOf(errorCode);
response.setContent(gson.toJson(result));
return true;
}
SendMessageData sendMessageData = getSendMessageData(message, replyMessageData);
WFCMessage.Message newMsg = sendMessageData.toProtoMessage().toBuilder().setMessageId(message.getMessageId()).build();
sendApiRequest(response, IMTopic.RobotReplyMessageTopic, newMsg.toByteArray(), result -> {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(result);
ErrorCode ec = ErrorCode.fromCode(byteBuf.readByte());
if (ec == ErrorCode.ERROR_CODE_SUCCESS) {
long messageId = byteBuf.readLong();
long timestamp = byteBuf.readLong();
sendResponse(response, null, new SendMessageResult(messageId, timestamp));
} else {
sendResponse(response, ec, null);
}
});
return false;
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
}
}
return true;
}
private @NotNull SendMessageData getSendMessageData(WFCMessage.Message message, ReplyMessageData replyMessageData) {
SendMessageData sendMessageData = new SendMessageData();
sendMessageData.setSender(robot.getUid());
Conversation conversation = new Conversation();
conversation.setType(message.getConversation().getType());
conversation.setLine(message.getConversation().getLine());
conversation.setTarget(message.getConversation().getTarget());
sendMessageData.setConv(conversation);
sendMessageData.setPayload(replyMessageData.getPayload());
if(replyMessageData.isOnly2Sender()) {
sendMessageData.setToUsers(Arrays.asList(message.getFromUser()));
}
return sendMessageData;
}
}
@@ -106,24 +106,6 @@ abstract public class RobotAction extends Action {
response.send();
}
protected <T> T getRequestBody(HttpRequest request, Class<T> cls) {
if (request instanceof FullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
String content = null;
try {
content = new String(bytes, "UTF-8");
T t = gson.fromJson(content, cls);
return t;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
Utility.printExecption(LOG, e, IMExceptionEvent.EventType.ROBOT_API_Exception);
}
}
return null;
}
protected void sendApiRequest(Response response, String topic, byte[] message, Callback callback) {
ServerAPIHelper.sendRequest(robot.getUid(), null, topic, message, new ServerAPIHelper.Callback() {
@Override
@@ -124,7 +124,7 @@ public final class BrokerConstants {
public static final String SENSITIVE_Filter_Type = "sensitive.filter.type";
public static final String SENSITIVE_Only_Message = "sensitive.only_message";
public static final String SENSITIVE_Remote_Server_URL = "sensitive.remote_server_url";
public static final String SENSITIVE_Remote_Message_Type = "sensitive.remote_sensitive_message_type";
public static final String SENSITIVE_Remote_Fail_When_Matched = "sensitive.remote_fail_when_matched";
@@ -163,11 +163,22 @@ public final class BrokerConstants {
public static final String MESSAGE_Force_Push_Types = "message.force_push_types";
public static final String MESSAGE_Forward_With_Client_Info = "message.forward_with_client_info";
public static final String MESSAGE_Forward_With_Sender_Info = "message.forward_with_sender_info";
public static final String MESSAGE_Forward_With_Target_Info = "message.forward_with_target_info";
public static final String BROADCAST_Target_From_User_Table = "message.broadcast.target_from_user_table";
public static final String MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER = "message.allow_send_to_forbidden_user";
public static final String ROBOT_Callback_With_Client_Info = "robot.callback_with_client_info";
public static final String ROBOT_Callback_With_Sender_Info = "robot.callback_with_sender_info";
public static final String ROBOT_Callback_With_Target_Info = "robot.callback_with_target_info";
public static final String ROBOT_Mention_External_Robot = "robot.mention_external_robot";
public static final String CHANNEL_Callback_With_Client_Info = "channel.callback_with_client_info";
public static final String CHANNEL_Callback_With_Sender_Info = "channel.callback_with_sender_info";
public static final String CHANNEL_Callback_With_Target_Info = "channel.callback_with_target_info";
public static final String CHANNEL_New_Callback_Feature = "channel.new_callback_feature";
@@ -196,6 +207,7 @@ public final class BrokerConstants {
public static final String GROUP_Forbidden_Client_Operation = "group.forbidden_client_operation";
public static final String GROUP_Disable_Stranger_Invite = "group.disable_stranger_invite";
public static final String GROUP_ADD_MEMBER_ALLOW_PART_SUCCESS = "group.add_member_allow_part_success";
public static final String GROUP_INFO_MARK_DELETION = "group.enable_mark_deletion";
@@ -16,6 +16,10 @@ import io.netty.buffer.ByteBuf;
import cn.wildfirechat.common.ErrorCode;
import win.liyufan.im.IMTopic;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
@Handler(value = IMTopic.AddGroupMemberTopic)
@@ -38,16 +42,34 @@ public class AddGroupMember extends GroupHandler<WFCMessage.AddGroupMemberReques
}
}
ErrorCode errorCode = m_messagesStore.addGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getAddedMemberList(), request.getExtra());
Map<String, Integer> failedMembers = new HashMap<>();
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
ErrorCode errorCode = m_messagesStore.canAddGroupMembers(fromUser, request.getAddedMemberList(), failedMembers);
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
return errorCode;
}
}
ErrorCode errorCode = m_messagesStore.addGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getAddedMemberList(), request.getExtra(), failedMembers);
if (errorCode == ERROR_CODE_SUCCESS) {
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());
} else {
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, getMemberIdList(request.getAddedMemberList())).setExtra(request.getExtra()).getAddGroupNotifyContent();
List<String> added = getMemberIdList(request.getAddedMemberList());
added.removeAll(failedMembers.keySet());
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, added).setExtra(request.getExtra()).getAddGroupNotifyContent();
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
}
}
if (errorCode == ERROR_CODE_SUCCESS && !failedMembers.isEmpty()) {
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, "").setMi(failedMembers).getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_REJECT_JOIN_GROUP);
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
}
if(errorCode == ERROR_CODE_SUCCESS && !failedMembers.isEmpty()) {
return ErrorCode.ERROR_CODE_PARTLY_SUCCESS;
}
return errorCode;
}
}
@@ -16,6 +16,7 @@ import io.netty.buffer.ByteBuf;
import cn.wildfirechat.common.ErrorCode;
import win.liyufan.im.IMTopic;
import static cn.wildfirechat.proto.ProtoConstants.RequestSourceType.Request_From_Admin;
import static win.liyufan.im.IMTopic.PutUserSettingTopic;
import static win.liyufan.im.UserSettingScope.kUserSettingMyChannels;
@@ -42,7 +43,13 @@ public class CreateChannelHandler extends GroupHandler<WFCMessage.ChannelInfo> {
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
WFCMessage.ModifyUserSettingReq modifyUserSettingReq = WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingMyChannels).setKey(request.getTargetId()).setValue("1").build();
mServer.onApiMessage(fromUser, null, modifyUserSettingReq.toByteArray(), 0, fromUser, PutUserSettingTopic, requestSourceType);
byte[] data = request.getTargetId().getBytes();
byte[] data;
if (requestSourceType == Request_From_Admin) {
//When server api create channel, need return channelId and secret together.
data = (request.getTargetId() + "|" + request.getSecret()).getBytes();
} else {
data = request.getTargetId().getBytes();
}
ackPayload.ensureWritable(data.length).writeBytes(data);
return ErrorCode.ERROR_CODE_SUCCESS;
} else {
@@ -17,6 +17,10 @@ import io.netty.buffer.ByteBuf;
import cn.wildfirechat.common.ErrorCode;
import win.liyufan.im.IMTopic;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Handler(value = IMTopic.CreateGroupTopic)
public class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupRequest> {
@Override
@@ -51,14 +55,34 @@ public class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupReque
}
}
Map<String, Integer> failedMembers = new HashMap<>();
if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {
ErrorCode errorCode = m_messagesStore.canAddGroupMembers(fromUser, request.getGroup().getMembersList());
ErrorCode errorCode = m_messagesStore.canAddGroupMembers(fromUser, request.getGroup().getMembersList(), failedMembers);
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
return errorCode;
}
}
WFCMessage.GroupInfo groupInfo = m_messagesStore.createGroup(fromUser, request.getGroup().getGroupInfo(), request.getGroup().getMembersList(), request.getMemberExtra(), isAdmin);
if (request.getGroup().getGroupInfo().getTargetId().length() > 64
|| request.getGroup().getGroupInfo().getName().length() > 64
|| request.getGroup().getGroupInfo().getPortrait().length() > 1024) {
return ErrorCode.INVALID_PARAMETER;
}
if(!isAdmin && !StringUtil.isNullOrEmpty(request.getGroup().getGroupInfo().getName())) {
if(!m_messagesStore.isSensitiveOnlyMessage()) {
Set<String> matched = m_messagesStore.handleSensitiveWord(request.getGroup().getGroupInfo().getName());
if (matched != null && !matched.isEmpty()) {
return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
}
}
if(!m_messagesStore.isAllowName(request.getGroup().getGroupInfo().getName())) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
}
WFCMessage.GroupInfo groupInfo = m_messagesStore.createGroup(fromUser, request.getGroup().getGroupInfo(), request.getGroup().getMembersList(), request.getMemberExtra(), isAdmin, failedMembers);
if (groupInfo != null && groupInfo.getDeleted() == 0) {
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
@@ -66,9 +90,19 @@ public class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupReque
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, groupInfo.getName(), "").setExtra(request.getMemberExtra()).getCreateGroupNotifyContent();
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), content);
}
if(!failedMembers.isEmpty()) {
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, null, "").setMi(failedMembers).getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_REJECT_JOIN_GROUP);
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), content);
}
}
byte[] data = groupInfo.getTargetId().getBytes();
ackPayload.ensureWritable(data.length).writeBytes(data);
return ErrorCode.ERROR_CODE_SUCCESS;
if(failedMembers.isEmpty()) {
return ErrorCode.ERROR_CODE_SUCCESS;
} else {
return ErrorCode.ERROR_CODE_PARTLY_SUCCESS;
}
}
}
@@ -11,11 +11,14 @@ package io.moquette.imhandler;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import cn.wildfirechat.pojos.GroupNotificationBinaryContent;
import com.hazelcast.util.StringUtil;
import io.moquette.spi.impl.Qos1PublishHandler;
import io.netty.buffer.ByteBuf;
import cn.wildfirechat.common.ErrorCode;
import win.liyufan.im.IMTopic;
import java.util.Set;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
@Handler(IMTopic.ModifyGroupAliasTopic)
@@ -26,10 +29,24 @@ public class ModifyGroupAliasHandler extends GroupHandler<WFCMessage.ModifyGroup
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
if (!isAdmin && !StringUtil.isNullOrEmpty(request.getAlias())) {
if(!m_messagesStore.isSensitiveOnlyMessage()) {
Set<String> matched = m_messagesStore.handleSensitiveWord(request.getAlias());
if (matched != null && !matched.isEmpty()) {
return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
}
}
if(!m_messagesStore.isAllowName(request.getAlias())) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
}
ErrorCode errorCode = m_messagesStore.modifyGroupMemberAlias(fromUser, request.getGroupId(), request.getAlias(), null, isAdmin);
if (errorCode == ERROR_CODE_SUCCESS) {
if (request.hasNotifyContent()&& request.getNotifyContent().getType() > 0) {
@@ -12,10 +12,13 @@ import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.GroupNotificationBinaryContent;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import com.hazelcast.util.StringUtil;
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.ModifyGroupMemberAliasTopic)
@@ -29,6 +32,18 @@ public class ModifyGroupMemberAliasHandler extends GroupHandler<WFCMessage.Modif
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
if (!isAdmin && !StringUtil.isNullOrEmpty(request.getAlias())) {
if(!m_messagesStore.isSensitiveOnlyMessage()) {
Set<String> matched = m_messagesStore.handleSensitiveWord(request.getAlias());
if (matched != null && !matched.isEmpty()) {
return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
}
}
if(!m_messagesStore.isAllowName(request.getAlias())) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
}
ErrorCode errorCode = m_messagesStore.modifyGroupMemberAlias(fromUser, request.getGroupId(), request.getAlias(), request.getMemberId(), isAdmin);
if (errorCode == ERROR_CODE_SUCCESS) {
@@ -0,0 +1,348 @@
/*
* 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.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import com.hazelcast.util.StringUtil;
import io.moquette.BrokerConstants;
import io.moquette.spi.impl.Qos1PublishHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import win.liyufan.im.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_NOT_IN_GROUP;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
@Handler(value = IMTopic.RobotReplyMessageTopic)
public class ReplyMessageHandler extends IMHandler<WFCMessage.Message> {
private int mSensitiveType = 0; //命中敏感词时,0 失败,1 吞掉, 2 敏感词替换成*。
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 mBlacklistAllowSend2Black = true;
private boolean mNoForwardAdminMessage = false;
private boolean mAllowSend2ForbiddenUser = false;
private String mRemoteSensitiveServerUrl = null;
private Set<Integer> mRemoteSensitiveMessageTypes;
private boolean mWaitRemoteSensitiveServerResponse = false;
public ReplyMessageHandler() {
super();
mForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Url);
if (!StringUtil.isNullOrEmpty(mForwardUrl)) {
String forwardTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Types);
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);
try {
mSensitiveType = Integer.parseInt(mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Filter_Type));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
}
try {
mBlacklistStrategy = Integer.parseInt(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Blacklist_Strategy));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
}
try {
mBlacklistAllowSend2Black = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Blacklist_Allow_Send, "true"));
} catch (Exception e) {
}
try {
mRemoteSensitiveServerUrl = mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Server_URL);
if(!StringUtil.isNullOrEmpty(mRemoteSensitiveServerUrl)) {
mWaitRemoteSensitiveServerResponse = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Fail_When_Matched, "false"));
String types = mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Message_Type, "");
mRemoteSensitiveMessageTypes = new HashSet<>();
if(!StringUtil.isNullOrEmpty(types)) {
String[] ts = types.split(",");
for (String t:ts) {
mRemoteSensitiveMessageTypes.add(Integer.parseInt(t.trim()));
}
}
}
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
}
try {
mNoForwardAdminMessage = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_NO_Forward_Admin_Message, "false"));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
}
try {
mAllowSend2ForbiddenUser = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER, "false"));
} catch (Exception e) {}
}
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) {
if(requestSourceType != ProtoConstants.RequestSourceType.Request_From_Robot) {
return ErrorCode.ERROR_CODE_NOT_IMPLEMENT;
}
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
if (message != null) {
if(message.getContent().getContent().length() +
message.getContent().getSearchableContent().length() +
message.getContent().getData().size() +
message.getContent().getExtra().length() +
message.getContent().getPushContent().length() +
message.getContent().getPushData().length() > 64 * 1024) {
return ErrorCode.ERROR_CODE_MESSAGE_TOO_LARGE;
}
boolean ignoreMsg = false;
// 不能在端上直接发送撤回和群通知
if (message.getContent().getType() == 80 || message.getContent().getType() == 81 || (message.getContent().getType() >= 100 && message.getContent().getType() < 200)) {
return ErrorCode.INVALID_PARAMETER;
}
if(m_messagesStore.getClientForbiddenSendTypes().contains(message.getContent().getType())) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
int userStatus = m_messagesStore.getUserStatus(fromUser);
if (userStatus == ProtoConstants.UserStatus.Muted || userStatus == ProtoConstants.UserStatus.Forbidden) {
if(!m_messagesStore.getGlobalMuteExceptionTypes().contains(message.getContent().getType())) {
return ErrorCode.ERROR_CODE_FORBIDDEN_SEND_MSG;
}
}
if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private) {
if(!m_messagesStore.getBlackListExceptionTypes().contains(message.getContent().getType())) {
errorCode = m_messagesStore.isAllowUserMessage(message.getConversation().getTarget(), fromUser, message.getConversation().getLine());
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
if (errorCode == ErrorCode.ERROR_CODE_IN_BLACK_LIST && mBlacklistStrategy != ProtoConstants.BlacklistStrategy.Message_Reject) {
ignoreMsg = true;
errorCode = ErrorCode.ERROR_CODE_SUCCESS;
} else {
return errorCode;
}
}
if(!mBlacklistAllowSend2Black) {
errorCode = m_messagesStore.isBlacked(fromUser, message.getConversation().getTarget());
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
return errorCode;
}
}
}
if (!mAllowSend2ForbiddenUser) {
userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());
if (userStatus == ProtoConstants.UserStatus.Forbidden) {
return ErrorCode.ERROR_CODE_USER_FORBIDDEN;
}
}
}
if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group ) {
if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {
errorCode = m_messagesStore.canSendMessageInGroup(fromUser, message.getConversation().getTarget());
if(errorCode == ERROR_CODE_NOT_IN_GROUP) {
errorCode = ERROR_CODE_SUCCESS;
}
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
return errorCode;
}
}
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom) {
if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {
if (!m_messagesStore.checkUserClientInChatroom(fromUser, clientID, message.getConversation().getTarget())) {
return ErrorCode.ERROR_CODE_NOT_IN_CHATROOM;
}
}
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {
if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {
if (!m_messagesStore.canSendMessageInChannel(fromUser, message.getConversation().getTarget())) {
return ErrorCode.ERROR_CODE_NOT_IN_CHANNEL;
}
}
}
if(message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private) {
long beforeMessageId = message.getMessageId();
WFCMessage.Message replyMsg = m_messagesStore.getMessage(beforeMessageId);
message = message.toBuilder().setConversation(message.getConversation().toBuilder().setTarget(replyMsg.getFromUser() + "|" + replyMsg.getConversation().getTarget())).build();
}
long timestamp = System.currentTimeMillis();
final long messageId;
try {
messageId = MessageShardingUtil.generateId();
} catch (Exception e) {
e.printStackTrace();
return ErrorCode.ERROR_CODE_SERVER_ERROR;
}
message = message.toBuilder().setFromUser(fromUser).setMessageId(messageId).setServerTimestamp(timestamp).build();
if (!StringUtil.isNullOrEmpty(mForwardUrl) && (mForwardMessageTypes.isEmpty() || mForwardMessageTypes.contains(message.getContent().getType())) && !mForwardExcludeMessageTypes.contains(message.getContent().getType())) {
publisher.forwardMessage(message, mForwardUrl, clientID);
}
if(!StringUtil.isNullOrEmpty(mMentionForwardUrl) && message.hasContent() && message.getContent().getMentionedType() != 0) {
publisher.forwardMessage(message, mMentionForwardUrl, clientID);
}
if(StringUtil.isNullOrEmpty(mRemoteSensitiveServerUrl)) {
Set<String> matched = m_messagesStore.handleSensitiveWord(message.getContent().getSearchableContent());
if (matched != null && !matched.isEmpty()) {
m_messagesStore.storeSensitiveMessage(message);
if (!StringUtil.isNullOrEmpty(mSensitiveMessageForwardUrl)) {
publisher.forwardMessage(message, mSensitiveMessageForwardUrl, clientID);
}
if (mSensitiveType == 0) {
errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
} else if (mSensitiveType == 1) {
ignoreMsg = true;
} else if (mSensitiveType == 2) {
String text = message.getContent().getSearchableContent();
for (String word : matched) {
text = text.replace(word, "***");
}
message = message.toBuilder().setContent(message.getContent().toBuilder().setSearchableContent(text).build()).build();
}
}
} else {
if(mRemoteSensitiveMessageTypes.contains(message.getContent().getType())) {
final WFCMessage.Message finalMsg = message;
publisher.forwardMessageWithCallback(message, clientID, mRemoteSensitiveServerUrl, new HttpUtils.HttpCallback() {
@Override
public void onSuccess(String content) {
if(StringUtil.isNullOrEmpty(content)) {
saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);
} else {
MessagePayload payload = GsonUtil.gson.fromJson(content, MessagePayload.class);
if (payload != null && payload.getType() > 0) {
WFCMessage.Message newMsg = finalMsg.toBuilder().setContent(payload.toProtoMessageContent()).build();
saveAndPublish(fromUser, clientID, newMsg, requestSourceType);
} else {
LOG.error("Response content {} from censor is invalid payload, ignore response and send original message", content);
saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);
}
}
if(mWaitRemoteSensitiveServerResponse) {
ByteBuf ackPayload = Unpooled.buffer(21);
ErrorCode errorCode = ERROR_CODE_SUCCESS;
ackPayload.writeByte(errorCode.getCode());
ackPayload.writeLong(messageId);
ackPayload.writeLong(timestamp);
callback.onIMHandled(ErrorCode.ERROR_CODE_SUCCESS, ackPayload);
}
}
@Override
public void onFailure(int statusCode, String errorMessage) {
ByteBuf ackPayload = null;
ErrorCode errorCode = ERROR_CODE_SUCCESS;
if(statusCode == 403) {
if(mWaitRemoteSensitiveServerResponse) {
errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
ackPayload = Unpooled.buffer(1);
ackPayload.writeByte(errorCode.getCode());
}
} else {
LOG.warn("Failed to censor message with status {}, errorMessage {}. Send the original message", statusCode, errorMessage);
saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);
if(mWaitRemoteSensitiveServerResponse) {
errorCode = ERROR_CODE_SUCCESS;
ackPayload = Unpooled.buffer(21);
ackPayload.writeByte(errorCode.getCode());
ackPayload.writeLong(messageId);
ackPayload.writeLong(timestamp);
}
}
if(mWaitRemoteSensitiveServerResponse) {
callback.onIMHandled(errorCode, ackPayload);
}
}
});
if(mWaitRemoteSensitiveServerResponse) {
ackPayload.clear();
return ErrorCode.INVALID_ASYNC_HANDLING;
} else {
ackPayload = ackPayload.capacity(20);
ackPayload.writeLong(messageId);
ackPayload.writeLong(timestamp);
return ErrorCode.ERROR_CODE_SUCCESS;
}
}
}
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
if(!ignoreMsg) {
saveAndPublish(fromUser, clientID, message, requestSourceType);
}
ackPayload = ackPayload.capacity(20);
ackPayload.writeLong(messageId);
ackPayload.writeLong(timestamp);
}
} else {
errorCode = ErrorCode.ERROR_CODE_INVALID_MESSAGE;
}
return errorCode;
}
}
@@ -39,6 +39,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
private int mBlacklistStrategy = 0; //黑名单中时,0失败,1吞掉。
private boolean mBlacklistAllowSend2Black = true;
private boolean mNoForwardAdminMessage = false;
private boolean mAllowSend2ForbiddenUser = false;
private String mRemoteSensitiveServerUrl = null;
private Set<Integer> mRemoteSensitiveMessageTypes;
@@ -101,6 +102,9 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
Utility.printExecption(LOG, e);
}
try {
mAllowSend2ForbiddenUser = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER, "false"));
} catch (Exception e) {}
}
private void parseTypes(Collection<Integer> collection, String types) {
@@ -132,6 +136,15 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;
if (message != null) {
if(message.getContent().getContent().length() +
message.getContent().getSearchableContent().length() +
message.getContent().getData().size() +
message.getContent().getExtra().length() +
message.getContent().getPushContent().length() +
message.getContent().getPushData().length() > 64 * 1024) {
return ErrorCode.ERROR_CODE_MESSAGE_TOO_LARGE;
}
boolean ignoreMsg = false;
if (!isAdmin) { //admin do not check the right
// 不能在端上直接发送撤回和群通知
@@ -170,9 +183,11 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
}
}
userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());
if (userStatus == ProtoConstants.UserStatus.Forbidden) {
return ErrorCode.ERROR_CODE_USER_FORBIDDEN;
if (!mAllowSend2ForbiddenUser) {
userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());
if (userStatus == ProtoConstants.UserStatus.Forbidden) {
return ErrorCode.ERROR_CODE_USER_FORBIDDEN;
}
}
}
@@ -217,20 +232,13 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
}
message = message.toBuilder().setFromUser(fromUser).setMessageId(messageId).setServerTimestamp(timestamp).build();
OutputClient outputClient = null;
if(m_messagesStore.isForwardMessageWithClientInfo() && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !StringUtil.isNullOrEmpty(clientID)) {
MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);
if(session != null && session.getUsername().equals(fromUser)) {
outputClient = new OutputClient(session.getPlatform(), clientID);
}
}
if (!StringUtil.isNullOrEmpty(mForwardUrl) && (mForwardMessageTypes.isEmpty() || mForwardMessageTypes.contains(message.getContent().getType())) && !(isAdmin && mNoForwardAdminMessage) && !mForwardExcludeMessageTypes.contains(message.getContent().getType())) {
publisher.forwardMessage(message, mForwardUrl, outputClient);
publisher.forwardMessage(message, mForwardUrl, clientID);
}
if(!StringUtil.isNullOrEmpty(mMentionForwardUrl) && message.hasContent() && message.getContent().getMentionedType() != 0 && !(isAdmin && mNoForwardAdminMessage)) {
publisher.forwardMessage(message, mMentionForwardUrl, outputClient);
publisher.forwardMessage(message, mMentionForwardUrl, clientID);
}
if (!isAdmin) {
@@ -239,7 +247,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
if (matched != null && !matched.isEmpty()) {
m_messagesStore.storeSensitiveMessage(message);
if (!StringUtil.isNullOrEmpty(mSensitiveMessageForwardUrl)) {
publisher.forwardMessage(message, mSensitiveMessageForwardUrl, outputClient);
publisher.forwardMessage(message, mSensitiveMessageForwardUrl, clientID);
}
if (mSensitiveType == 0) {
errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
@@ -256,7 +264,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
} else {
if(mRemoteSensitiveMessageTypes.contains(message.getContent().getType())) {
final WFCMessage.Message finalMsg = message;
publisher.forwardMessageWithCallback(message, mRemoteSensitiveServerUrl, new HttpUtils.HttpCallback() {
publisher.forwardMessageWithCallback(message, clientID, mRemoteSensitiveServerUrl, new HttpUtils.HttpCallback() {
@Override
public void onSuccess(String content) {
if(StringUtil.isNullOrEmpty(content)) {
@@ -21,7 +21,7 @@ import java.util.List;
public class UserSearchHandler extends IMHandler<WFCMessage.SearchUserRequest> {
@Override
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.SearchUserRequest request, Qos1PublishHandler.IMCallback callback) {
List<WFCMessage.User> users = m_messagesStore.searchUser(request.getKeyword(), request.getFuzzy(), request.getPage());
List<WFCMessage.User> users = m_messagesStore.searchUser(request.getKeyword(), request.getFuzzy(), request.getType(), request.getPage());
WFCMessage.SearchUserResult.Builder builder = WFCMessage.SearchUserResult.newBuilder();
builder.addAllEntry(users);
byte[] data = builder.build().toByteArray();
@@ -36,6 +36,8 @@ import java.util.function.Function;
import static cn.wildfirechat.common.IMExceptionEvent.EventType.RDBS_Exception;
import static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;
import static cn.wildfirechat.proto.ProtoConstants.UserSearchUserType.UserSearchUserType_ONLY_ROBOT;
import static cn.wildfirechat.proto.ProtoConstants.UserSearchUserType.UserSearchUserType_ONLY_USER;
import static io.moquette.BrokerConstants.GROUP_INFO_MARK_DELETION;
import static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;
import static cn.wildfirechat.proto.ProtoConstants.SearchUserType.*;
@@ -169,7 +171,7 @@ public class DatabaseStore {
return null;
}
List<WFCMessage.User> searchUserByNameMobileUserId(String keyword, int searchType) {
List<WFCMessage.User> searchUserByNameMobileUserId(String keyword, int searchType, int userType) {
ArrayList<WFCMessage.User> out = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
@@ -203,7 +205,15 @@ public class DatabaseStore {
sql += " where (`_name` = ? or `_mobile` = ? or `_uid` = ?) ";
}
sql += " and `_type` <> 2 and `_deleted` = 0"; //can search normal user(0) and robot(1) and admin(100), can not search things
if(userType == UserSearchUserType_ONLY_USER) {
sql += " and _type <> 2 "; //can not search device
sql += " and _type <> 1 ";
} else if(userType == UserSearchUserType_ONLY_ROBOT) {
sql += " and _type = 1 ";
} else {
sql += " and _type <> 2 "; //can not search device
}
sql += " and _deleted = 0 ";
if(searchType == SearchUserType_Name || searchType == SearchUserType_Mobile || searchType == SearchUserType_UserId) {
sql += " limit 1";
@@ -408,7 +418,7 @@ public class DatabaseStore {
return out;
}
List<WFCMessage.User> searchUserByDisplayName(String keyword, int page, List<WFCMessage.User> nameOrIdMatched) {
List<WFCMessage.User> searchUserByDisplayName(String keyword, int userType, int page, List<WFCMessage.User> nameOrIdMatched) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
@@ -419,7 +429,18 @@ public class DatabaseStore {
connection = DBUtil.getConnection();
String sql = "select u._uid, u._name, u._display_name, u._portrait, u._mobile, u._gender, u._email, u._address, u._company, u._social, u._extra, u._dt, u._type " +
" from t_user u left join (select _uid, _value from t_user_setting where _scope = 27) s on u._uid = s._uid " +
" where u._display_name like ? ESCAPE '!' and u._type <> 2 and u._deleted = 0 ";
" where u._display_name like ? ESCAPE '!' ";
if(userType == UserSearchUserType_ONLY_USER) {
sql += " and u._type <> 2 ";
sql += " and u._type <> 1 ";
} else if(userType == UserSearchUserType_ONLY_ROBOT) {
sql += " and u._type = 1 ";
} else {
sql += " and u._type <> 2 ";
}
sql += " and u._deleted = 0 ";
if(nameOrIdMatched.size() == 1) {
sql += " and u._uid <> ? and u._name <> ?";
} else if(nameOrIdMatched.size() == 2) {
@@ -523,15 +544,15 @@ public class DatabaseStore {
return out;
}
List<WFCMessage.User> searchUserFromDB(String keyword, int searchType, int page) {
List<WFCMessage.User> nameOrIdMatched = searchUserByNameMobileUserId(keyword, searchType);
List<WFCMessage.User> searchUserFromDB(String keyword, int searchType, int userType, int page) {
List<WFCMessage.User> nameOrIdMatched = searchUserByNameMobileUserId(keyword, searchType, userType);
List<WFCMessage.User> out = new ArrayList<>();
if(page == 0) {
out.addAll(nameOrIdMatched);
}
if(searchType == SearchUserType_General || searchType == SearchUserType_Name_Mobile_DisplayName) {
List<WFCMessage.User> general = searchUserByDisplayName(keyword, page, nameOrIdMatched);
List<WFCMessage.User> general = searchUserByDisplayName(keyword, userType, page, nameOrIdMatched);
general.removeAll(nameOrIdMatched);
out.addAll(general);
}
@@ -1811,6 +1832,31 @@ public class DatabaseStore {
});
}
void updateSessionIp(String uid, String cid, String ip) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "update t_user_session set _ip = ? where `_uid` = ? and `_cid` = ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setString(index++, ip);
statement.setString(index++, uid);
statement.setString(index++, cid);
int c = statement.executeUpdate();
LOG.info("Update rows {}", c);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e, RDBS_Exception);
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
void clearMultiEndpoint(String uid, String clientId, int platform) {
LOG.info("clearMultiEndpoint {}, {}", uid, clientId);
Connection connection = null;
@@ -56,6 +56,7 @@ 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.BiFunction;
import java.util.function.Consumer;
import static cn.wildfirechat.common.IMExceptionEvent.EventType.EVENT_CALLBACK_Exception;
@@ -167,9 +168,10 @@ public class MemoryMessagesStore implements IMessagesStore {
private Set<String> mAllowStrangerChatSet = new HashSet<>();
private Set<Integer> mAllowStrangerLineSet = new HashSet<>();
private boolean mDisableStrangerAddGroup = false;
private boolean mGroupAllowPartSuccess = false;
private boolean mIDUseUUID = true;
private boolean mSensitiveOnlyMessage = true;
private Set<String> mClientSignatureSet = new HashSet<>();
private boolean mRejectEmptySignature = true;
@@ -205,8 +207,17 @@ public class MemoryMessagesStore implements IMessagesStore {
private boolean mBroadcastTargetFromUserTable = false;
private boolean mForwardMessageWithClientInfo = false;
private boolean mForwardMessageWithSenderInfo = false;
private boolean mForwardMessageWithTargetInfo = false;
private boolean mRobotCallbackWithClientInfo = false;
private boolean mRobotCallbackWithSenderInfo = false;
private boolean mRobotCallbackWithTargetInfo = false;
private boolean mRobotMentionExternalRobot = false;
private boolean mChannelCallbackWithClientInfo = false;
private boolean mChannelCallbackWithSenderInfo = false;
private boolean mChannelCallbackWithTargetInfo = false;
private boolean mChannelNewCallbackFeature = true;
private Set<Integer> mUserHideProperties = new HashSet<>();
@@ -321,7 +332,7 @@ public class MemoryMessagesStore implements IMessagesStore {
printMissConfigLog(FRIEND_Disable_NickName_Search, mDisableNicknameSearch + "");
}
try {
mDisableUserIdSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_UserId_Search, "true"));
mDisableUserIdSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_UserId_Search, "false"));
} catch (Exception e) {
}
@@ -608,9 +619,13 @@ public class MemoryMessagesStore implements IMessagesStore {
try {
mForwardMessageWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_With_Client_Info, "false"));
} catch (Exception e) {
}
} catch (Exception e) {}
try {
mForwardMessageWithSenderInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_With_Sender_Info, "false"));
} catch (Exception e) {}
try {
mForwardMessageWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_With_Target_Info, "false"));
} catch (Exception e) {}
try {
mBroadcastTargetFromUserTable = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.BROADCAST_Target_From_User_Table, "false"));
@@ -619,18 +634,36 @@ public class MemoryMessagesStore implements IMessagesStore {
}
try {
mRobotCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Client_Info, "false"));
mGroupAllowPartSuccess = "true".equals(server.getConfig().getProperty(BrokerConstants.GROUP_ADD_MEMBER_ALLOW_PART_SUCCESS, "false"));
} catch (Exception e) {
}
try {
mRobotCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Client_Info, "false"));
} catch (Exception e) {}
try {
mRobotCallbackWithSenderInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Sender_Info, "false"));
} catch (Exception e) {}
try {
mRobotCallbackWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Target_Info, "false"));
} catch (Exception e) {}
try {
mRobotMentionExternalRobot = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Mention_External_Robot, "false"));
} catch (Exception e) {}
try {
mChannelCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Client_Info, "false"));
} catch (Exception e) {
}
} catch (Exception e) {}
try {
mChannelCallbackWithSenderInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Sender_Info, "false"));
} catch (Exception e) {}
try {
mChannelCallbackWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Target_Info, "false"));
} catch (Exception e) {}
try {
mChannelNewCallbackFeature = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_New_Callback_Feature, "true"));
} catch (Exception e) {
}
} catch (Exception e) {}
try {
mRecallForwardUrl = server.getConfig().getProperty(BrokerConstants.MESSAGE_RecallMsg_Forward_Url);
@@ -642,6 +675,11 @@ public class MemoryMessagesStore implements IMessagesStore {
mIDUseUUID = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ID_USE_UUID, "false"));
} catch (Exception e) {
}
try {
mSensitiveOnlyMessage = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SENSITIVE_Only_Message, "true"));
} catch (Exception e) {
}
}
private void printMissConfigLog(String config, String defaultValue) {
@@ -708,13 +746,34 @@ public class MemoryMessagesStore implements IMessagesStore {
int pullType = ProtoConstants.PullType.Pull_Normal;
if (type == ProtoConstants.ConversationType.ConversationType_Private) {
notifyReceivers.add(fromUser);
if(message.getToCount() > 0) {
if(message.getToList().contains(message.getConversation().getTarget())) {
notifyReceivers.add(message.getConversation().getTarget());
if(mRobotMentionExternalRobot && message.getConversation().getTarget().contains("|")) {
String[] ss = message.getConversation().getTarget().split("\\|");
notifyReceivers.add(ss[0]);
notifyReceivers.add(ss[1]);
if(!message.getToList().isEmpty()) {
notifyReceivers.addAll(message.getToList());
} else if(!StringUtil.isNullOrEmpty(message.getToUser())) {
notifyReceivers.add(message.getToUser());
}
} else {
notifyReceivers.add(message.getConversation().getTarget());
notifyReceivers.add(fromUser);
if (message.getToCount() > 0) {
if (message.getToList().contains(message.getConversation().getTarget())) {
notifyReceivers.add(message.getConversation().getTarget());
}
} else {
notifyReceivers.add(message.getConversation().getTarget());
}
}
if (mRobotMentionExternalRobot && message.getContent().getMentionedTargetCount() > 0) {
for (String mentioned : message.getContent().getMentionedTargetList()) {
if (!notifyReceivers.contains(mentioned)) {
WFCMessage.User user = getUserInfo(mentioned);
if(user != null && user.getType() == ProtoConstants.UserType.UserType_Robot) {
notifyReceivers.add(mentioned);
}
}
}
}
pullType = ProtoConstants.PullType.Pull_Normal;
} else if (type == ProtoConstants.ConversationType.ConversationType_Group) {
@@ -744,6 +803,16 @@ public class MemoryMessagesStore implements IMessagesStore {
}
}
}
if (mRobotMentionExternalRobot && message.getContent().getMentionedTargetCount() > 0) {
for (String mentioned : message.getContent().getMentionedTargetList()) {
if (!notifyReceivers.contains(mentioned)) {
WFCMessage.User user = getUserInfo(mentioned);
if(user != null && user.getType() == ProtoConstants.UserType.UserType_Robot) {
notifyReceivers.add(mentioned);
}
}
}
}
pullType = ProtoConstants.PullType.Pull_Normal;
} else if (type == ProtoConstants.ConversationType.ConversationType_ChatRoom) {
boolean isDirect = !StringUtil.isNullOrEmpty(message.getToUser()) || !message.getToList().isEmpty();
@@ -816,6 +885,18 @@ public class MemoryMessagesStore implements IMessagesStore {
return pullType;
}
private final Map<String, Integer> unreceivedMsgCount = new ConcurrentHashMap<>();
@Override
public void increaseUnreceivedMsgCount(String user) {
unreceivedMsgCount.compute(user, (s, integer) -> integer == null ? 1 : integer+1);
}
@Override
public int getUnreceivedMsgCount(String user) {
return unreceivedMsgCount.getOrDefault(user, 0);
}
@Override
public Set<String> getAllEnds() {
return databaseStore.getAllEnds(mBroadcastTargetFromUserTable);
@@ -830,7 +911,7 @@ public class MemoryMessagesStore implements IMessagesStore {
MemorySessionStore.Session session = m_Server.getStore().sessionsStore().getSession(exceptClientId);
session.refreshLastActiveTime();
if (pullType != ProtoConstants.PullType.Pull_ChatRoom) {
session.setUnReceivedMsgs(0);
unreceivedMsgCount.put(user, 0);
} else {
session.refreshLastChatroomActiveTime();
}
@@ -900,11 +981,13 @@ public class MemoryMessagesStore implements IMessagesStore {
session.setPullHistoryMsg(true);
}
long previousCurrent;
while (true) {
Map.Entry<Long, Long> entry = maps.higherEntry(current);
if (entry == null) {
break;
}
previousCurrent = current;
current = entry.getKey();
long targetMessageId = entry.getValue();
@@ -933,6 +1016,8 @@ public class MemoryMessagesStore implements IMessagesStore {
if (size >= 512 * 1024) { //3M
if(builder.getMessageCount() == 0){
builder.addMessage(bundle.getMessage());
} else {
current = previousCurrent;
}
break;
}
@@ -1256,7 +1341,7 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public ErrorCode canAddGroupMembers(String fromUser, List<WFCMessage.GroupMember> memberList) {
public ErrorCode canAddGroupMembers(String fromUser, List<WFCMessage.GroupMember> memberList, Map<String, Integer> failedMembers) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);
IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);
@@ -1282,7 +1367,12 @@ public class MemoryMessagesStore implements IMessagesStore {
for (FriendData friendData : friendDatas) {
if (friendData.getFriendUid().equals(fromUser)) {
if (friendData.getBlacked() == 1) {
return ErrorCode.ERROR_CODE_IN_BLACK_LIST;
LOG.error("Add group member failure, because inviter {} is blocked by invitee {}", fromUser, targetUser);
if(isGroupAllowPartSuccess()) {
failedMembers.put(targetUser, 1); //black
} else {
return ErrorCode.ERROR_CODE_IN_BLACK_LIST;
}
} else {
if (friendData.getState() == 0) {
allow = true;
@@ -1306,7 +1396,11 @@ public class MemoryMessagesStore implements IMessagesStore {
continue;
}
return ErrorCode.ERROR_CODE_NOT_RIGHT;
if(isGroupAllowPartSuccess()) {
failedMembers.put(targetUser, 2);//stranger
} else {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
}
} else {
for (WFCMessage.GroupMember groupMember : memberList) {
@@ -1323,7 +1417,12 @@ public class MemoryMessagesStore implements IMessagesStore {
for (FriendData friendData : friendDatas) {
if (friendData.getFriendUid().equals(fromUser)) {
if (friendData.getBlacked() == 1) {
return ErrorCode.ERROR_CODE_IN_BLACK_LIST;
LOG.error("Add group member failure, because inviter {} is blocked by invitee {}", fromUser, targetUser);
if(isGroupAllowPartSuccess()) {
failedMembers.put(targetUser, 1); //black
} else {
return ErrorCode.ERROR_CODE_IN_BLACK_LIST;
}
} else {
break;
}
@@ -1335,7 +1434,7 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public WFCMessage.GroupInfo createGroup(String fromUser, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList, String memberExtra, boolean isAdmin) {
public WFCMessage.GroupInfo createGroup(String fromUser, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList, String memberExtra, boolean isAdmin, Map<String, Integer> failedMembers) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);
@@ -1357,6 +1456,9 @@ public class MemoryMessagesStore implements IMessagesStore {
List<WFCMessage.GroupMember> updatedMemberList = new ArrayList<>();
boolean hasOwnerMember = false;
for (WFCMessage.GroupMember member : memberList) {
if(failedMembers.containsKey(member.getMemberId())) {
continue;
}
WFCMessage.GroupMember.Builder builder = member.toBuilder();
builder.setUpdateDt(dt).setCreateDt(dt);
if (member.getMemberId().equals(owner)) {
@@ -1551,7 +1653,7 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList, String extra) {
public ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList, String extra, Map<String, Integer> failedMembers) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);
@@ -1624,6 +1726,10 @@ public class MemoryMessagesStore implements IMessagesStore {
List<WFCMessage.GroupMember> tmp = new ArrayList<>();
int newMemberCount = 0;
for (WFCMessage.GroupMember member : memberList) {
if(failedMembers.containsKey(member.getMemberId())) {
continue;
}
if (existMemberIds.contains(member.getMemberId()) && member.getType() != GroupMemberType_Removed) {
if(!isAdmin)
continue;
@@ -1656,7 +1762,11 @@ public class MemoryMessagesStore implements IMessagesStore {
if (memberList.size() == 0) {
if (!isAdmin) {
return ErrorCode.ERROR_CODE_ALREADY_IN_GROUP;
if(failedMembers.isEmpty()) {
return ErrorCode.ERROR_CODE_ALREADY_IN_GROUP;
} else {
return ErrorCode.ERROR_CODE_SUCCESS;
}
} else {
return ErrorCode.ERROR_CODE_SUCCESS;
}
@@ -1675,6 +1785,10 @@ public class MemoryMessagesStore implements IMessagesStore {
List<String> memberIds = new ArrayList<>();
for (WFCMessage.GroupMember member : memberList) {
if(failedMembers.containsKey(member.getMemberId())) {
continue;
}
if (member.getType() != GroupMemberType_Removed) {
memberIds.add(member.getMemberId());
}
@@ -1900,6 +2014,19 @@ public class MemoryMessagesStore implements IMessagesStore {
if (!isAllow) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
if (modifyType == Modify_Group_Name && !StringUtil.isNullOrEmpty(value)) {
if(!mSensitiveOnlyMessage) {
Set<String> matched = handleSensitiveWord(value);
if (matched != null && !matched.isEmpty()) {
return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
}
}
if(!isAllowName(value)) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
}
}
if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Normal) {
@@ -1937,6 +2064,14 @@ public class MemoryMessagesStore implements IMessagesStore {
newInfoBuilder.setPrivateChat(Integer.parseInt(value));
else if(modifyType == Modify_Group_Searchable)
newInfoBuilder.setSearchable(Integer.parseInt(value));
else if(modifyType == Modify_Group_Type) {
int newType = Integer.parseInt(value);
if(newType < 0 || newType > ProtoConstants.GroupType.GroupType_Organization) {
LOG.error("modify group type failure, invalid group type {}", newType);
return ErrorCode.INVALID_PARAMETER;
}
newInfoBuilder.setType(newType);
}
else
return ErrorCode.INVALID_PARAMETER;
@@ -2266,15 +2401,29 @@ public class MemoryMessagesStore implements IMessagesStore {
}
//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();
mIMap.set(groupId, groupInfo);
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);
Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);
if (members == null || members.size() == 0) {
members = loadGroupMemberFromDB(hzInstance, groupId);
}
boolean isNewOwnerInGroup = false;
for (WFCMessage.GroupMember member : members) {
if (member.getMemberId().equals(newOwner)) {
if(member.getType() != GroupMemberType_Removed) {
isNewOwnerInGroup = true;
}
break;
}
}
if(!isNewOwnerInGroup) {
return ErrorCode.ERROR_CODE_NOT_IN_GROUP;
}
long updateDt = System.currentTimeMillis();
groupInfo = groupInfo.toBuilder().setOwner(newOwner).setUpdateDt(updateDt).setMemberUpdateDt(updateDt).build();
mIMap.set(groupId, groupInfo);
int modifyMemeberCount = 0;
for (WFCMessage.GroupMember member : members) {
if (modifyMemeberCount == 2) {
@@ -2440,7 +2589,7 @@ public class MemoryMessagesStore implements IMessagesStore {
}
boolean isExpired = false;
if (!canRecall && message.getFromUser().equals(operatorId)) {
if (now - message.getServerTimestamp() > mRecallTimeLimit * 1000) {
if (mRecallTimeLimit >= 0 && now - message.getServerTimestamp() > mRecallTimeLimit * 1000) {
isExpired = true;
} else {
canRecall = true;
@@ -2714,6 +2863,19 @@ public class MemoryMessagesStore implements IMessagesStore {
) {
switch (entry.getType()) {
case Modify_DisplayName:
if(!StringUtil.isNullOrEmpty(entry.getValue())) {
if (!mSensitiveOnlyMessage) {
Set<String> matched = handleSensitiveWord(entry.getValue());
if (matched != null && !matched.isEmpty()) {
return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
}
}
if(!isAllowName(entry.getValue())) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
}
builder.setDisplayName(entry.getValue());
modified = true;
break;
@@ -3061,7 +3223,7 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public List<WFCMessage.User> searchUser(String keyword, int searchType, int page) {
public List<WFCMessage.User> searchUser(String keyword, int searchType, int userType, int page) {
if (mDisableSearch) {
return new ArrayList<>();
}
@@ -3082,7 +3244,7 @@ public class MemoryMessagesStore implements IMessagesStore {
return new ArrayList<>();
}
return databaseStore.searchUserFromDB(keyword, searchType, page);
return databaseStore.searchUserFromDB(keyword, searchType, userType, page);
}
@Override
@@ -3805,6 +3967,25 @@ public class MemoryMessagesStore implements IMessagesStore {
return ErrorCode.ERROR_CODE_SUCCESS;
}
@Override
public boolean isAllowName(String name) {
if(StringUtil.isNullOrEmpty(name)) {
return true;
}
name = name.trim();
SystemSettingPojo notAllowNameSetting = getSystemSetting(ProtoConstants.SystemSettingType.NOT_ALLOW_USER_NAMES);
if (notAllowNameSetting != null && !StringUtil.isNullOrEmpty(notAllowNameSetting.value)) {
String[] ss = notAllowNameSetting.value.split(",");
for (String s : ss) {
if(name.contains(s.trim())) {
return false;
}
}
}
return true;
}
@Override
public ErrorCode handleJoinChatroom(String userId, String clientId, String chatroomId) {
IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = m_Server.getHazelcastInstance().getMap(CHATROOMS);
@@ -4444,7 +4625,7 @@ public class MemoryMessagesStore implements IMessagesStore {
} else if(modifyType == Modify_Channel_Menu) {
OutputGetChannelInfo.OutputMenuList outputMenuButtons = GsonUtil.gson.fromJson(value, OutputGetChannelInfo.OutputMenuList.class);
if (!outputMenuButtons.isEmpty()) {
for (OutputGetChannelInfo.OutputMenu outputMenuButton : outputMenuButtons) {
for (PojoChannelMenu outputMenuButton : outputMenuButtons) {
newInfoBuilder.addMenu(outputMenuButton.toPbInfo());
}
}
@@ -4674,6 +4855,11 @@ public class MemoryMessagesStore implements IMessagesStore {
return new ArrayList<>(databaseStore.getSensitiveWord());
}
@Override
public boolean isSensitiveOnlyMessage() {
return mSensitiveOnlyMessage;
}
@Override
public WFCMessage.Message getMessage(long messageId) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
@@ -4700,6 +4886,11 @@ public class MemoryMessagesStore implements IMessagesStore {
return mGroupVisibleQuitKickoffNotification;
}
@Override
public boolean isGroupAllowPartSuccess() {
return mGroupAllowPartSuccess;
}
@Override
public int getGroupForbiddenClientOperation() {
return mGroupForbiddenClientOperation;
@@ -4710,16 +4901,51 @@ public class MemoryMessagesStore implements IMessagesStore {
return mForwardMessageWithClientInfo;
}
@Override
public boolean isForwardMessageWithSenderInfo() {
return mForwardMessageWithSenderInfo;
}
@Override
public boolean isForwardMessageWithTargetInfo() {
return mForwardMessageWithTargetInfo;
}
@Override
public boolean isRobotCallbackWithClientInfo() {
return mRobotCallbackWithClientInfo;
}
@Override
public boolean isRobotCallbackWithSenderInfo() {
return mRobotCallbackWithSenderInfo;
}
@Override
public boolean isRobotCallbackWithTargetInfo() {
return mRobotCallbackWithTargetInfo;
}
@Override
public boolean isRobotMentionExternalRobot() {
return mRobotMentionExternalRobot;
}
@Override
public boolean isChannelCallbackWithClientInfo() {
return mChannelCallbackWithClientInfo;
}
@Override
public boolean isChannelCallbackWithSenderInfo() {
return mChannelCallbackWithSenderInfo;
}
@Override
public boolean isChannelCallbackWithTargetInfo() {
return mChannelCallbackWithTargetInfo;
}
@Override
public boolean isChannelNewCallbackFeature() {
return mChannelNewCallbackFeature;
@@ -61,6 +61,7 @@ public class MemorySessionStore implements ISessionsStore {
private int deleted;
private boolean pullHistoryMsg;
private String ip;
public int getDeleted() {
return deleted;
@@ -92,10 +93,6 @@ public class MemorySessionStore implements ISessionsStore {
return unReceivedMsgs;
}
public void setUnReceivedMsgs(int unReceivedMsgs) {
this.unReceivedMsgs = unReceivedMsgs;
}
public int getPushType() {
return pushType;
}
@@ -163,6 +160,14 @@ public class MemorySessionStore implements ISessionsStore {
}
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
private int pushType;
private int platform;
@@ -548,6 +553,15 @@ public class MemorySessionStore implements ISessionsStore {
return session.clientSession;
}
@Override
public void updateSessionIp(String username, String clientID, String ip) {
Session session = getSession(clientID);
if(session != null && session.getDeleted() == 0) {
session.setIp(ip);
databaseStore.updateSessionIp(username, clientID, ip);
}
}
@Override
public Session sessionForClientAndUser(String username, String clientID) {
Session session = sessions.get(clientID);
@@ -102,9 +102,9 @@ public interface IMessagesStore {
WFCMessage.PullMessageResult fetchMessage(String user, String exceptClientId, long fromMessageId, int pullType);
WFCMessage.PullMessageResult loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count, Collection<Integer> contentTypes);
long insertUserMessages(String sender, int conversationType, String target, int line, int messageContentType, String userId, long messageId, boolean directing);
ErrorCode canAddGroupMembers(String operator, List<WFCMessage.GroupMember> memberList);
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 canAddGroupMembers(String operator, List<WFCMessage.GroupMember> memberList, Map<String, Integer> failedMembers);
WFCMessage.GroupInfo createGroup(String operator, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList, String memberExtra, boolean isAdmin, Map<String, Integer> failedMembers);
ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList, String extra, Map<String, Integer> failedMembers);
ErrorCode kickoffGroupMembers(String operator, boolean isAdmin, String groupId, List<String> memberList);
ErrorCode quitGroup(String operator, String groupId, boolean admin);
void clearUserGroups(String userId);
@@ -154,7 +154,7 @@ public interface IMessagesStore {
WFCMessage.User getUserInfoByName(String name);
WFCMessage.User getUserInfoByMobile(String mobile);
List<WFCMessage.User> getUserInfosByEmail(String email);
List<WFCMessage.User> searchUser(String keyword, int searchType, int page);
List<WFCMessage.User> searchUser(String keyword, int searchType, int userType, int page);
List<WFCMessage.User> getUserInfoList(int count, int offset);
@@ -190,6 +190,8 @@ public interface IMessagesStore {
ErrorCode setFriendAliasRequest(String fromUser, String targetUserId, String alias, long[] head);
ErrorCode setFriendExtraRequest(String fromUser, String targetUserId, String extra, long[] head);
boolean isAllowName(String name);
ErrorCode handleJoinChatroom(String userId, String clientId, String chatroomId);
ErrorCode handleQuitChatroom(String userId, String clientId, String chatroomId);
@@ -232,9 +234,13 @@ public interface IMessagesStore {
boolean addSensitiveWords(List<String> words);
boolean removeSensitiveWords(List<String> words);
List<String> getAllSensitiveWords();
boolean isSensitiveOnlyMessage();
WFCMessage.Message getMessage(long messageId);
void increaseUnreceivedMsgCount(String user);
int getUnreceivedMsgCount(String user);
boolean isAllowClientCustomGroupNotification();
boolean isAllowRobotCustomGroupNotification();
int getVisibleQuitKickoffNotification();
@@ -242,10 +248,19 @@ public interface IMessagesStore {
int getGroupForbiddenClientOperation();
boolean isForwardMessageWithClientInfo();
boolean isRobotCallbackWithClientInfo();
boolean isChannelCallbackWithClientInfo();
boolean isChannelNewCallbackFeature();
boolean isForwardMessageWithSenderInfo();
boolean isForwardMessageWithTargetInfo();
boolean isRobotCallbackWithClientInfo();
boolean isRobotCallbackWithSenderInfo();
boolean isRobotCallbackWithTargetInfo();
boolean isRobotMentionExternalRobot();
boolean isChannelCallbackWithClientInfo();
boolean isChannelCallbackWithSenderInfo();
boolean isChannelCallbackWithTargetInfo();
boolean isChannelNewCallbackFeature();
boolean isGroupAllowPartSuccess();
boolean isRobotAutoAcceptFriendRequest();
long getPushExpiredTimes();
@@ -43,7 +43,7 @@ public interface ISessionsStore {
ErrorCode loadActiveSession(String username, String clientID);
ClientSession updateExistSession(String username, String clientID, WFCMessage.RouteRequest endpoint, boolean cleanSession);
void updateSessionIp(String username, String clientID, String ip);
Session getSession(String clientID);
void cleanDuplatedToken(String cid, int pushType, String token, boolean isVoip, String packageName);
@@ -16,14 +16,13 @@
package io.moquette.spi.impl;
import cn.wildfirechat.pojos.OutputClient;
import cn.wildfirechat.pojos.OutputMessageData;
import org.json.simple.JSONObject;
import cn.wildfirechat.pojos.*;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import cn.wildfirechat.push.PushServer;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.util.StringUtil;
import cn.wildfirechat.pojos.OutputNotifyChannelSubscribeStatus;
import com.xiaoleilu.loServer.model.FriendData;
import io.moquette.persistence.*;
import io.moquette.persistence.MemorySessionStore.Session;
@@ -34,12 +33,14 @@ import io.moquette.spi.ISessionsStore;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.mqtt.*;
import org.json.simple.parser.JSONParser;
import win.liyufan.im.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
@@ -47,6 +48,7 @@ import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import static cn.wildfirechat.common.IMExceptionEvent.EventType.EVENT_CALLBACK_Exception;
import static cn.wildfirechat.proto.ProtoConstants.ConversationType.*;
import static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;
public class MessagesPublisher {
@@ -157,7 +159,7 @@ public class MessagesPublisher {
}
}
private void publish2Receivers(String sender, int conversationType, String target, int line, long messageId, Collection<String> receivers, String pushContent, String pushData, String exceptClientId, int pullType, int messageContentType, long serverTime, int mentionType, List<String> mentionTargets, int persistFlag, boolean directing) {
private void publish2Receivers(String sender, int conversationType, String target, int line, long messageId, Collection<String> receivers, String pushContent, String pushData, long callStartUid, String exceptClientId, int pullType, int messageContentType, long serverTime, int mentionType, List<String> mentionTargets, int persistFlag, boolean directing) {
if (persistFlag == Transparent) {
publishTransparentMessage2Receivers(messageId, receivers, pullType, exceptClientId);
return;
@@ -176,19 +178,10 @@ public class MessagesPublisher {
if (message == null) {
message = m_messagesStore.getMessage(messageId);
}
OutputClient outputClient = null;
if(m_messagesStore.isRobotCallbackWithClientInfo() && !StringUtil.isNullOrEmpty(exceptClientId)) {
Session session = m_sessionsStore.getSession(exceptClientId);
if(session != null && session.getUsername().equals(sender)) {
outputClient = new OutputClient(session.getPlatform(), exceptClientId);
}
}
final WFCMessage.Message finalMsg = message;
OutputClient finalOutputClient = outputClient;
OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, exceptClientId, m_messagesStore.isRobotCallbackWithClientInfo() , m_messagesStore.isRobotCallbackWithSenderInfo(), m_messagesStore.isRobotCallbackWithTargetInfo());
Server.getServer().getCallbackScheduler().execute(() -> {
try {
HttpUtils.httpJsonPost(robot.getCallback(), GsonUtil.gson.toJson(OutputMessageData.fromProtoMessage(finalMsg, finalOutputClient), OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Robot_Message_Callback);
HttpUtils.httpJsonPost(robot.getCallback(), GsonUtil.gson.toJson(outputMessageData, OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Robot_Message_Callback);
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);
@@ -283,7 +276,7 @@ public class MessagesPublisher {
if (!user.equals(sender)) {
WFCMessage.Conversation conversation;
if (conversationType == ProtoConstants.ConversationType.ConversationType_Private) {
if (conversationType == ConversationType_Private) {
conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(sender).build();
} else {
conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(target).build();
@@ -322,7 +315,7 @@ public class MessagesPublisher {
if (!StringUtil.isNullOrEmpty(pushContent) || messageContentType == 400) {
if (!isConvSilent && (persistFlag & 0x02) > 0) {
targetSession.setUnReceivedMsgs(targetSession.getUnReceivedMsgs() + 1);
m_messagesStore.increaseUnreceivedMsgCount(user);
}
}
}
@@ -398,7 +391,7 @@ public class MessagesPublisher {
if(!sendNameLoaded) {
List<String> list = new ArrayList<>();
senderName = getUserDisplayName(sender, conversationType == ProtoConstants.ConversationType.ConversationType_Group ? target : null, list);
senderName = getUserDisplayName(sender, conversationType == ConversationType_Group ? target : null, list);
if(!list.isEmpty()) {
senderPortrait = list.get(0);
}
@@ -421,13 +414,25 @@ public class MessagesPublisher {
name = fd.getAlias();
}
}
this.messageSender.sendPush(sender, conversationType, target, line, messageId, targetSession.getClientID(), pushContent, pushData, messageContentType, serverTime, name, senderPortrait, targetName, targetPortrait, targetSession.getUnReceivedMsgs(), curMentionType, isHiddenDetail, targetSession.getLanguage());
this.messageSender.sendPush(sender, conversationType, target, line, messageId, targetSession.getClientID(), pushContent, pushData, callStartUid, messageContentType, serverTime, name, senderPortrait, targetName, targetPortrait, m_messagesStore.getUnreceivedMsgCount(user), curMentionType, isHiddenDetail, targetSession.getLanguage(), getExistBadgeNumber(user));
}
}
}
}
private int getExistBadgeNumber(String user) {
int existBadgeNumber = 0;
WFCMessage.UserSettingEntry userSettingData = m_messagesStore.getUserSetting(user, UserSettingScope.kUserSettingScopeSyncBadge, "");
if(userSettingData != null && !StringUtil.isNullOrEmpty(userSettingData.getValue())) {
try {
existBadgeNumber = Integer.parseInt(userSettingData.getValue());
} catch (NumberFormatException e) {}
}
return existBadgeNumber;
}
public boolean sendOfflineNotify(String clientId) {
boolean targetIsActive = this.connectionDescriptors.isConnected(clientId);
if (targetIsActive) {
@@ -486,19 +491,10 @@ public class MessagesPublisher {
if (userInfo != null && userInfo.getType() == ProtoConstants.UserType.UserType_Robot) {
WFCMessage.Robot robot = m_messagesStore.getRobot(user);
if (robot != null && !StringUtil.isNullOrEmpty(robot.getCallback())) {
OutputClient outputClient = null;
if(m_messagesStore.isRobotCallbackWithClientInfo() && !StringUtil.isNullOrEmpty(exceptClientId)) {
Session session = m_sessionsStore.getSession(exceptClientId);
if(session != null && session.getUsername().equals(message.getFromUser())) {
outputClient = new OutputClient(session.getPlatform(), exceptClientId);
}
}
final WFCMessage.Message finalMsg = message;
OutputClient finalOutputClient = outputClient;
OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, exceptClientId, m_messagesStore.isRobotCallbackWithClientInfo() , m_messagesStore.isRobotCallbackWithSenderInfo(), m_messagesStore.isRobotCallbackWithTargetInfo());
Server.getServer().getCallbackScheduler().execute(() -> {
try {
HttpUtils.httpJsonPost(robot.getCallback(), GsonUtil.gson.toJson(OutputMessageData.fromProtoMessage(finalMsg, finalOutputClient), OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Robot_Message_Callback);
HttpUtils.httpJsonPost(robot.getCallback(), GsonUtil.gson.toJson(outputMessageData, OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Robot_Message_Callback);
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);
@@ -530,9 +526,9 @@ public class MessagesPublisher {
}
String getTargetName(String targetId, int cnvType, String fromUser, List<String> portraitList) {
if (cnvType == ProtoConstants.ConversationType.ConversationType_Private) {
if (cnvType == ConversationType_Private) {
return getUserDisplayName(targetId, null, portraitList);
} else if(cnvType == ProtoConstants.ConversationType.ConversationType_Group) {
} else if(cnvType == ConversationType_Group) {
WFCMessage.GroupInfo group = m_messagesStore.getGroupInfo(targetId);
if(group != null) {
if(!StringUtil.isNullOrEmpty(group.getPortrait())) {
@@ -545,7 +541,7 @@ public class MessagesPublisher {
}
return group.getName();
}
} else if(cnvType == ProtoConstants.ConversationType.ConversationType_Channel) {
} else if(cnvType == ConversationType_Channel) {
WFCMessage.ChannelInfo channelInfo = m_messagesStore.getChannelInfo(targetId);
if (channelInfo != null) {
if(!StringUtil.isNullOrEmpty(channelInfo.getPortrait())) {
@@ -602,7 +598,7 @@ public class MessagesPublisher {
}
if (IMTopic.NotifyFriendRequestTopic.equals(topic)) {
messageSender.sendPush(fromUser, receiver, targetSession.getClientID(), pushContent, PushServer.PushMessageType.PUSH_MESSAGE_TYPE_FRIEND_REQUEST, System.currentTimeMillis(), fromUserName, targetSession.getUnReceivedMsgs() + 1, targetSession.getLanguage());
messageSender.sendPush(fromUser, receiver, targetSession.getClientID(), pushContent, PushServer.PushMessageType.PUSH_MESSAGE_TYPE_FRIEND_REQUEST, System.currentTimeMillis(), fromUserName, m_messagesStore.getUnreceivedMsgCount(receiver) + 1, targetSession.getLanguage(), getExistBadgeNumber(receiver));
}
}
}
@@ -667,7 +663,7 @@ public class MessagesPublisher {
}
public void publish2Receivers(WFCMessage.Message message, Set<String> receivers, String exceptClientId, int pullType) {
if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {
if (message.getConversation().getType() == ConversationType_Channel) {
WFCMessage.ChannelInfo channelInfo = m_messagesStore.getChannelInfo(message.getConversation().getTarget());
boolean forwardMsg;
@@ -678,18 +674,10 @@ public class MessagesPublisher {
}
if (forwardMsg) {
OutputClient outputClient = null;
if(m_messagesStore.isChannelCallbackWithClientInfo() && !StringUtil.isNullOrEmpty(exceptClientId)) {
Session session = m_sessionsStore.getSession(exceptClientId);
if(session != null && session.getUsername().equals(message.getFromUser())) {
outputClient = new OutputClient(session.getPlatform(), exceptClientId);
}
}
OutputClient finalOutputClient = outputClient;
OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, exceptClientId, m_messagesStore.isChannelCallbackWithClientInfo() , m_messagesStore.isChannelCallbackWithSenderInfo(), m_messagesStore.isChannelCallbackWithTargetInfo());
Server.getServer().getCallbackScheduler().execute(() -> {
try {
HttpUtils.httpJsonPost(channelInfo.getCallback() + "/message", GsonUtil.gson.toJson(OutputMessageData.fromProtoMessage(message, finalOutputClient), OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Channel_Message_Callback);
HttpUtils.httpJsonPost(channelInfo.getCallback() + "/message", GsonUtil.gson.toJson(outputMessageData, OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Channel_Message_Callback);
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);
@@ -733,18 +721,92 @@ public class MessagesPublisher {
pushContent = null;
}
long callStartUid = 0;
if (message.getContent().getType() == 402) {
try {
String str = new String(message.getContent().getData().toByteArray(), StandardCharsets.UTF_8);
JSONObject jsonObject = (JSONObject)(new JSONParser().parse(str));
if (jsonObject.containsKey("u")) {
callStartUid = (Long)jsonObject.get("u");
}
} catch (Exception e) {}
}
publish2Receivers(message.getFromUser(),
message.getConversation().getType(), message.getConversation().getTarget(), message.getConversation().getLine(),
messageId,
receivers,
pushContent, message.getContent().getPushData(), exceptClientId, pullType, message.getContent().getType(), message.getServerTimestamp(), message.getContent().getMentionedType(), message.getContent().getMentionedTargetList(), message.getContent().getPersistFlag(), message.hasToUser() || !message.getToList().isEmpty());
pushContent, message.getContent().getPushData(), callStartUid, exceptClientId, pullType, message.getContent().getType(), message.getServerTimestamp(), message.getContent().getMentionedType(), message.getContent().getMentionedTargetList(), message.getContent().getPersistFlag(), message.hasToUser() || !message.getToList().isEmpty());
}
public void forwardMessage(final WFCMessage.Message message, String forwardUrl, OutputClient outputClient) {
private OutputMessageData getOutputMessageWithExtraInfo(WFCMessage.Message message, String clientId, boolean withClient, boolean withSender, boolean withTarget) {
if (message == null) {
return null;
}
OutputClient outputClient = null;
if (withClient && !StringUtil.isNullOrEmpty(clientId)) {
Session session = m_sessionsStore.getSession(clientId);
if(session != null && session.getUsername().equals(message.getFromUser())) {
outputClient = new OutputClient(session.getPlatform(), clientId);
}
}
OutputMessageData outputMessageData = OutputMessageData.fromProtoMessage(message, outputClient);
if (withSender) {
WFCMessage.User senderInfo = m_messagesStore.getUserInfo(message.getFromUser());
outputMessageData.setSenderUserInfo(InputOutputUserInfo.fromPbUser(senderInfo));
}
if (withTarget) {
if (message.getConversation().getType() == ConversationType_Private) {
WFCMessage.User targetInfo = m_messagesStore.getUserInfo(message.getConversation().getTarget());
if (targetInfo != null) {
outputMessageData.setTargetUserInfo(InputOutputUserInfo.fromPbUser(targetInfo));
}
} else if(message.getConversation().getType() == ConversationType_Group) {
WFCMessage.GroupInfo groupInfo = m_messagesStore.getGroupInfo(message.getConversation().getTarget());
if (groupInfo != null) {
PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();
pojoGroupInfo.setExtra(groupInfo.getExtra());
pojoGroupInfo.setName(groupInfo.getName());
pojoGroupInfo.setOwner(groupInfo.getOwner());
pojoGroupInfo.setPortrait(groupInfo.getPortrait());
pojoGroupInfo.setTarget_id(groupInfo.getTargetId());
pojoGroupInfo.setType(groupInfo.getType());
pojoGroupInfo.setMember_count(groupInfo.getMemberCount());
pojoGroupInfo.setMute(groupInfo.getMute());
pojoGroupInfo.setJoin_type(groupInfo.getJoinType());
pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());
pojoGroupInfo.setSearchable(groupInfo.getSearchable());
pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());
pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());
pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);
pojoGroupInfo.setDeleted(groupInfo.getDeleted()>0);
pojoGroupInfo.setUpdate_dt(groupInfo.getUpdateDt());
pojoGroupInfo.setMember_update_dt(groupInfo.getMemberUpdateDt());
outputMessageData.setTargetGroupInfo(pojoGroupInfo);
}
} else if(message.getConversation().getType() == ConversationType_Channel) {
WFCMessage.ChannelInfo targetInfo = m_messagesStore.getChannelInfo(message.getConversation().getTarget());
if (targetInfo != null) {
outputMessageData.setTargetChannelInfo(OutputGetChannelInfo.fromPbInfo(targetInfo));
}
}
}
return outputMessageData;
}
public void forwardMessage(final WFCMessage.Message message, String forwardUrl, String fromClientId) {
OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, fromClientId, m_messagesStore.isForwardMessageWithClientInfo() , m_messagesStore.isForwardMessageWithSenderInfo(), m_messagesStore.isForwardMessageWithTargetInfo());
Server.getServer().getCallbackScheduler().execute(() -> {
try {
HttpUtils.httpJsonPost(forwardUrl, GsonUtil.gson.toJson(OutputMessageData.fromProtoMessage(message, outputClient), OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Forward_Message_Callback);
HttpUtils.httpJsonPost(forwardUrl, GsonUtil.gson.toJson(outputMessageData), HttpUtils.HttpPostType.POST_TYPE_Forward_Message_Callback);
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);
@@ -752,9 +814,10 @@ public class MessagesPublisher {
});
}
public void forwardMessageWithCallback(final WFCMessage.Message message, String forwardUrl, HttpUtils.HttpCallback callback) {
public void forwardMessageWithCallback(final WFCMessage.Message message, String fromClientId, String forwardUrl, HttpUtils.HttpCallback callback) {
OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, fromClientId, m_messagesStore.isForwardMessageWithClientInfo() , m_messagesStore.isForwardMessageWithSenderInfo(), m_messagesStore.isForwardMessageWithTargetInfo());
try {
HttpUtils.httpJsonPost(forwardUrl, GsonUtil.gson.toJson(OutputMessageData.fromProtoMessage(message), OutputMessageData.class), new HttpUtils.HttpCallback() {
HttpUtils.httpJsonPost(forwardUrl, GsonUtil.gson.toJson(outputMessageData), new HttpUtils.HttpCallback() {
@Override
public void onSuccess(String content) {
Server.getServer().getImBusinessScheduler().execute(()->{
@@ -37,16 +37,18 @@ class PersistentQueueMessageSender {
this.connectionDescriptorStore = connectionDescriptorStore;
}
void sendPush(String sender, int conversationType, String target, int line, long messageId, String deviceId, String pushContent, String pushData, int messageContentType, long serverTime, String senderName, String senderPortrait, String targetName, String targetPortrait, int unReceivedMsg, int mentionType, boolean isHiddenDetail, String language) {
void sendPush(String sender, int conversationType, String target, int line, long messageId, String deviceId, String pushContent, String pushData, long callStartUid, int messageContentType, long serverTime, String senderName, String senderPortrait, String targetName, String targetPortrait, int unReceivedMsg, int mentionType, boolean isHiddenDetail, String language, int existBadgeNumber) {
LOG.info("Send push to {}, message from {}", deviceId, sender);
PushMessage pushMessage = new PushMessage(sender, conversationType, target, line, messageContentType, serverTime, senderName, senderPortrait, targetName, targetPortrait, unReceivedMsg, mentionType, isHiddenDetail, language);
pushMessage.pushContent = pushContent;
pushMessage.pushData = pushData;
pushMessage.messageId = messageId;
pushMessage.callStartUid = callStartUid;
pushMessage.existBadgeNumber = existBadgeNumber;
PushServer.getServer().pushMessage(pushMessage, deviceId, pushContent);
}
void sendPush(String sender, String target, String deviceId, String pushContent, int pushContentType, long serverTime, String senderName, int unReceivedMsg, String language) {
void sendPush(String sender, String target, String deviceId, String pushContent, int pushContentType, long serverTime, String senderName, int unReceivedMsg, String language, int existBadgeNumber) {
LOG.info("Send push to {}, message from {}", deviceId, sender);
PushMessage pushMessage = new PushMessage(sender, target, serverTime, senderName, unReceivedMsg, language, pushContentType);
pushMessage.pushContent = pushContent;
@@ -284,7 +284,7 @@ public class ProtocolProcessor {
sessionstatus = 0;
}
userOnlineStatus.sessions.add(new OutputCheckUserOnline.Session(userId, session.getClientID(), session.getPlatform(), sessionstatus, session.getLastActiveTime(), session.getAppName()));
userOnlineStatus.sessions.add(new OutputCheckUserOnline.Session(userId, session.getClientID(), session.getPlatform(), sessionstatus, session.getLastActiveTime(), session.getAppName(), session.getIp()));
}
HttpUtils.httpJsonPost(mUserOnlineStatusCallback, GsonUtil.gson.toJson(userOnlineStatus), HttpUtils.HttpPostType.POST_TYPE_User_Online_Event_Callback);
@@ -141,7 +141,7 @@ public class Qos1PublishHandler extends QosPublishHandler {
status = 0;
}
out.addSession(userId, session.getClientID(), session.getPlatform(), status, session.getLastActiveTime(), session.getAppName());
out.addSession(userId, session.getClientID(), session.getPlatform(), status, session.getLastActiveTime(), session.getAppName(), session.getIp());
}
callback.onRouteHandled(GsonUtil.gson.toJson(out).getBytes());
@@ -12,6 +12,7 @@ import io.moquette.server.Server;
import java.io.*;
import java.util.Properties;
import java.util.UUID;
public class GitRepositoryState {
public final String tags;
@@ -28,6 +29,8 @@ public class GitRepositoryState {
public final String commitMessageFull;
public final String commitMessageShort;
public final String commitTime;
public static final String globalLabel = UUID.randomUUID().toString();
public String label;
public final String closestTagName;
public final String closestTagCommitCount;
@@ -63,6 +66,7 @@ public class GitRepositoryState {
this.buildHost = String.valueOf(properties.get("git.build.host"));
this.buildVersion = String.valueOf(properties.get("git.build.version"));
this.runTime = Server.getServer().getRunTime();
this.label = globalLabel;
}
public static GitRepositoryState getGitRepositoryState() throws IOException {
@@ -10,6 +10,7 @@ package win.liyufan.im;
public interface IMTopic {
String SendMessageTopic = "MS";
String RobotReplyMessageTopic = "RRM";
String MultiCastMessageTopic = "MMC";
String RecallMessageTopic = "MR";
String RecallMultiCastMessageTopic = "MRMC";
@@ -21,4 +21,5 @@ public interface UserSettingScope {
int kUserSettingGroupRemark = 26;
int kUserSettingPrivacySearchable = 27;
int kUserSettingAddFriendStrategy = 28;
int kUserSettingScopeSyncBadge = 29;
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.2</version>
<version>1.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,6 +21,7 @@ public interface APIPath {
String Get_Domain = "/admin/domain/get";
String Destroy_Domain = "/admin/domain/destroy";
String List_Domain = "/admin/domain/list";
String Ping_Domain = "/admin/domain/ping";
String Create_User = "/admin/user/create";
String Update_User = "/admin/user/update";
@@ -61,6 +62,8 @@ public interface APIPath {
String Handle_Friend_Send_Request = "/admin/friend/handle_send_request";
String Admin_Moments_Post_Feed = "/admin/moments/feed/post";
String Msg_Send = "/admin/message/send";
String Msg_Publish = "/admin/message/publish";
String Msg_Recall = "/admin/message/recall";
@@ -126,6 +129,8 @@ public interface APIPath {
String Channel_Update_Profile = "/channel/update_profile";
String Channel_Get_Profile = "/channel/get_profile";
String Channel_Message_Send = "/channel/message/send";
String Channel_Msg_Recall = "/channel/message/recall";
String Channel_Msg_Republish = "/channel/message/republish";
String Channel_Subscribe = "/channel/subscribe";
String Channel_Subscriber_List = "/channel/subscriber_list";
String Channel_Is_Subscriber = "/channel/is_subscriber";
@@ -134,6 +139,7 @@ public interface APIPath {
String Robot_User_Info = "/robot/user_info";
String Robot_Get_Profile = "/robot/profile";
String Robot_Message_Send = "/robot/message/send";
String Robot_Message_Reply = "/robot/message/reply";
String Robot_Message_Recall = "/robot/message/recall";
String Robot_Message_Update = "/robot/message/update";
String Robot_Set_Callback = "/robot/set_callback";
@@ -49,6 +49,7 @@ public enum ErrorCode {
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_MESSAGE_TOO_LARGE(35, "message too large"),
ERROR_CODE_CONFERENCE_ROOM_NOT_EXIST(60, "conference room not exist"),
ERROR_CODE_CONFERENCE_SERVICE_NOT_AVAILABLE(61, "conference service not available"),
@@ -65,6 +66,8 @@ public enum ErrorCode {
ERROR_CODE_CONFERENCE_ERROR(90, "Conference server response error"),
ERROR_CODE_FUNCTION_DISABLED(220, "function disabled"),
ERROR_CODE_SERVER_BUSY(221, "Server busy"),
ERROR_CODE_PARTLY_SUCCESS(222, "Partly success"),
ERROR_CODE_OTHER_CLIENT_ALREADY_IN_CHATROOM(225, "other client already in chatroom"),
@@ -16,6 +16,7 @@ import com.google.protobuf.ByteString;
import io.netty.util.internal.StringUtil;
import java.util.List;
import java.util.Map;
public class GroupNotificationBinaryContent {
//groupId
@@ -33,6 +34,8 @@ public class GroupNotificationBinaryContent {
//value2(member or something)
private String m;
private Map<String, Integer> mi;
private String extra;
public GroupNotificationBinaryContent() {
@@ -92,6 +95,11 @@ public class GroupNotificationBinaryContent {
this.ms = ms;
}
public GroupNotificationBinaryContent setMi(Map<String, Integer> mi) {
this.mi = mi;
return this;
}
public GroupNotificationBinaryContent setExtra(String extra) {
this.extra = extra;
return this;
@@ -12,6 +12,9 @@ package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
import io.netty.util.internal.StringUtil;
import java.util.ArrayList;
import java.util.List;
public class InputCreateChannel {
private String owner;
private String name;
@@ -24,6 +27,7 @@ public class InputCreateChannel {
private int state;
private String extra;
private long updateDt;
public List<PojoChannelMenu> menus;
public WFCMessage.ChannelInfo toProtoChannelInfo() {
WFCMessage.ChannelInfo.Builder builder = WFCMessage.ChannelInfo.newBuilder().setOwner(owner);
@@ -48,6 +52,12 @@ public class InputCreateChannel {
else
builder = builder.setUpdateDt(System.currentTimeMillis());
if (menus != null && !menus.isEmpty()) {
for (PojoChannelMenu menu : menus) {
builder.addMenu(menu.toPbInfo());
}
}
return builder.build();
}
@@ -20,22 +20,24 @@ public class OutputCheckUserOnline {
public int status; //0 online, 1 have session offline
public long lastSeen;
public String packageName;
public String ip;
public Session() {
}
public Session(String clientId, String userId, int platform, int status, long lastSeen, String packageName) {
public Session(String clientId, String userId, int platform, int status, long lastSeen, String packageName, String ip) {
this.clientId = clientId;
this.userId = userId;
this.platform = platform;
this.status = status;
this.lastSeen = lastSeen;
this.packageName = packageName;
this.ip = ip;
}
}
public void addSession(String userId, String clientId, int platform, int status, long lastSeen, String packageName) {
Session session = new Session(clientId, userId, platform, status, lastSeen, packageName);
public void addSession(String userId, String clientId, int platform, int status, long lastSeen, String packageName, String ip) {
Session session = new Session(clientId, userId, platform, status, lastSeen, packageName, ip);
sessions.add(session);
}
@@ -13,9 +13,11 @@ import cn.wildfirechat.proto.WFCMessage;
public class OutputCreateChannel {
private String targetId;
private String secret;
public OutputCreateChannel(String targetId) {
public OutputCreateChannel(String targetId, String secret) {
this.targetId = targetId;
this.secret = secret;
}
public String getTargetId() {
@@ -25,4 +27,12 @@ public class OutputCreateChannel {
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}
@@ -16,61 +16,7 @@ import java.util.ArrayList;
import java.util.List;
public class OutputGetChannelInfo {
public static class OutputMenu {
public String menuId;
public String type;
public String name;
public String key;
public String url;
public String mediaId;
public String articleId;
public String appId;
public String appPage;
public String extra;
public List<OutputMenu> subMenus;
public static OutputMenu fromPbInfo(WFCMessage.ChannelMenu channelMenuMenu) {
OutputMenu out = new OutputMenu();
out.menuId = channelMenuMenu.getMenuId();
out.type = channelMenuMenu.getType();
out.name = channelMenuMenu.getName();
out.key = channelMenuMenu.getKey();
out.url = channelMenuMenu.getUrl();
out.mediaId = channelMenuMenu.getMediaId();
out.articleId = channelMenuMenu.getArticleId();
out.appId = channelMenuMenu.getAppId();
out.appPage = channelMenuMenu.getAppPage();
out.extra = channelMenuMenu.getExtra();
if (channelMenuMenu.getSubMenuCount() > 0) {
out.subMenus = new ArrayList<>();
for (WFCMessage.ChannelMenu menuMenu : channelMenuMenu.getSubMenuList()) {
out.subMenus.add(fromPbInfo(menuMenu));
}
}
return out;
}
public WFCMessage.ChannelMenu.Builder toPbInfo() {
WFCMessage.ChannelMenu.Builder builder = WFCMessage.ChannelMenu.newBuilder();
builder.setType(type);
builder.setName(name);
if (!StringUtil.isNullOrEmpty(menuId)) builder.setMenuId(menuId);
if (!StringUtil.isNullOrEmpty(key)) builder.setKey(key);
if (!StringUtil.isNullOrEmpty(url)) builder.setUrl(url);
if (!StringUtil.isNullOrEmpty(mediaId)) builder.setMediaId(mediaId);
if (!StringUtil.isNullOrEmpty(articleId)) builder.setArticleId(articleId);
if (!StringUtil.isNullOrEmpty(appId)) builder.setAppId(appId);
if (!StringUtil.isNullOrEmpty(appPage)) builder.setAppPage(appPage);
if (!StringUtil.isNullOrEmpty(extra)) builder.setExtra(extra);
if (subMenus != null && !subMenus.isEmpty()) {
subMenus.forEach(menuMenu -> builder.addSubMenu(menuMenu.toPbInfo()));
}
return builder;
}
}
public static class OutputMenuList extends ArrayList<OutputMenu> {
public static class OutputMenuList extends ArrayList<PojoChannelMenu> {
}
private String channelId;
@@ -85,7 +31,7 @@ public class OutputGetChannelInfo {
private String callback;
private int automatic;
private String secret;
public List<OutputMenu> menus;
public List<PojoChannelMenu> menus;
public String getChannelId() {
return channelId;
@@ -200,7 +146,7 @@ public class OutputGetChannelInfo {
if (channelInfo.getMenuCount() > 0) {
out.menus = new ArrayList<>();
for (WFCMessage.ChannelMenu channelMenuMenu : channelInfo.getMenuList()) {
out.menus.add(OutputMenu.fromPbInfo(channelMenuMenu));
out.menus.add(PojoChannelMenu.fromPbInfo(channelMenuMenu));
}
}
return out;
@@ -3,13 +3,15 @@ package cn.wildfirechat.pojos;
public class OutputGetIMTokenData {
private String userId;
private String token;
private String serverLabel;
public OutputGetIMTokenData() {
}
public OutputGetIMTokenData(String userId, String imToken) {
public OutputGetIMTokenData(String userId, String imToken, String label) {
this.userId = userId;
this.token = imToken;
this.serverLabel = label;
}
public String getUserId() {
@@ -27,4 +29,12 @@ public class OutputGetIMTokenData {
public void setToken(String token) {
this.token = token;
}
public String getServerLabel() {
return serverLabel;
}
public void setServerLabel(String serverLabel) {
this.serverLabel = serverLabel;
}
}
@@ -22,6 +22,11 @@ public class OutputMessageData {
private long timestamp;
private OutputClient client;
private InputOutputUserInfo senderUserInfo;
private InputOutputUserInfo targetUserInfo;
private PojoGroupInfo targetGroupInfo;
private OutputGetChannelInfo targetChannelInfo;
public String getSender() {
return sender;
}
@@ -78,6 +83,38 @@ public class OutputMessageData {
this.client = client;
}
public InputOutputUserInfo getSenderUserInfo() {
return senderUserInfo;
}
public void setSenderUserInfo(InputOutputUserInfo senderUserInfo) {
this.senderUserInfo = senderUserInfo;
}
public InputOutputUserInfo getTargetUserInfo() {
return targetUserInfo;
}
public void setTargetUserInfo(InputOutputUserInfo targetUserInfo) {
this.targetUserInfo = targetUserInfo;
}
public PojoGroupInfo getTargetGroupInfo() {
return targetGroupInfo;
}
public void setTargetGroupInfo(PojoGroupInfo targetGroupInfo) {
this.targetGroupInfo = targetGroupInfo;
}
public OutputGetChannelInfo getTargetChannelInfo() {
return targetChannelInfo;
}
public void setTargetChannelInfo(OutputGetChannelInfo targetChannelInfo) {
this.targetChannelInfo = targetChannelInfo;
}
public static OutputMessageData fromProtoMessage(WFCMessage.Message protoMessage) {
return fromProtoMessage(protoMessage, null);
}
@@ -0,0 +1,60 @@
package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
import io.netty.util.internal.StringUtil;
import java.util.ArrayList;
import java.util.List;
public class PojoChannelMenu {
public String menuId;
public String type;
public String name;
public String key;
public String url;
public String mediaId;
public String articleId;
public String appId;
public String appPage;
public String extra;
public List<PojoChannelMenu> subMenus;
public static PojoChannelMenu fromPbInfo(WFCMessage.ChannelMenu channelMenuMenu) {
PojoChannelMenu out = new PojoChannelMenu();
out.menuId = channelMenuMenu.getMenuId();
out.type = channelMenuMenu.getType();
out.name = channelMenuMenu.getName();
out.key = channelMenuMenu.getKey();
out.url = channelMenuMenu.getUrl();
out.mediaId = channelMenuMenu.getMediaId();
out.articleId = channelMenuMenu.getArticleId();
out.appId = channelMenuMenu.getAppId();
out.appPage = channelMenuMenu.getAppPage();
out.extra = channelMenuMenu.getExtra();
if (channelMenuMenu.getSubMenuCount() > 0) {
out.subMenus = new ArrayList<>();
for (WFCMessage.ChannelMenu menuMenu : channelMenuMenu.getSubMenuList()) {
out.subMenus.add(fromPbInfo(menuMenu));
}
}
return out;
}
public WFCMessage.ChannelMenu.Builder toPbInfo() {
WFCMessage.ChannelMenu.Builder builder = WFCMessage.ChannelMenu.newBuilder();
builder.setType(type);
builder.setName(name);
if (!StringUtil.isNullOrEmpty(menuId)) builder.setMenuId(menuId);
if (!StringUtil.isNullOrEmpty(key)) builder.setKey(key);
if (!StringUtil.isNullOrEmpty(url)) builder.setUrl(url);
if (!StringUtil.isNullOrEmpty(mediaId)) builder.setMediaId(mediaId);
if (!StringUtil.isNullOrEmpty(articleId)) builder.setArticleId(articleId);
if (!StringUtil.isNullOrEmpty(appId)) builder.setAppId(appId);
if (!StringUtil.isNullOrEmpty(appPage)) builder.setAppPage(appPage);
if (!StringUtil.isNullOrEmpty(extra)) builder.setExtra(extra);
if (subMenus != null && !subMenus.isEmpty()) {
subMenus.forEach(menuMenu -> builder.addSubMenu(menuMenu.toPbInfo()));
}
return builder;
}
}
@@ -0,0 +1,52 @@
/*
* 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;
import cn.wildfirechat.proto.WFCMessage;
import io.netty.util.internal.StringUtil;
import java.util.List;
public class ReplyMessageData {
private long messageUid;
private MessagePayload payload;
private boolean only2Sender;
public long getMessageUid() {
return messageUid;
}
public void setMessageUid(long messageUid) {
this.messageUid = messageUid;
}
public MessagePayload getPayload() {
return payload;
}
public void setPayload(MessagePayload payload) {
this.payload = payload;
}
public boolean isOnly2Sender() {
return only2Sender;
}
public void setOnly2Sender(boolean only2Sender) {
this.only2Sender = only2Sender;
}
public static boolean isValide(ReplyMessageData sendMessageData) {
if(sendMessageData.messageUid <=0 ||
sendMessageData.getPayload() == null) {
return false;
}
return true;
}
}
@@ -0,0 +1,32 @@
/*
* 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;
import java.util.List;
public class RepublishChannelMessageData {
private List<String> targets;
private long messageId;
public List<String> getTargets() {
return targets;
}
public void setTargets(List<String> targets) {
this.targets = targets;
}
public long getMessageId() {
return messageId;
}
public void setMessageId(long messageId) {
this.messageId = messageId;
}
}
@@ -20,6 +20,7 @@ public class SendMessageData {
private MessagePayload payload;
private List<String> toUsers;
private boolean isMeshMessage;
private boolean isUserMessage;
public String getSender() {
return sender;
@@ -61,6 +62,14 @@ public class SendMessageData {
isMeshMessage = meshMessage;
}
public boolean isUserMessage() {
return isUserMessage;
}
public void setUserMessage(boolean userMessage) {
isUserMessage = userMessage;
}
public static boolean isValide(SendMessageData sendMessageData) {
if(sendMessageData == null ||
sendMessageData.getConv() == null ||
@@ -0,0 +1,14 @@
/*
* 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.mesh;
public class PojoDomainPingRequest {
public String domainId;
}
@@ -0,0 +1,16 @@
/*
* 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.mesh;
public class PojoDomainPingResponse {
public boolean success;
public String errorMessage;
public String myDomainName;
}
@@ -3,6 +3,7 @@ package cn.wildfirechat.pojos.mesh;
public class PojoSearchUserReq {
public String keyword;
public int searchType;
public int userType;
public int page;
public String domainId;
@@ -22,6 +23,14 @@ public class PojoSearchUserReq {
this.searchType = searchType;
}
public int getUserType() {
return userType;
}
public void setUserType(int userType) {
this.userType = userType;
}
public int getPage() {
return page;
}
@@ -172,6 +172,7 @@ public class ProtoConstants {
int Modify_Group_Max_Member_Count = 8;
//仅专业版的server api支持
int Modify_Group_Super_Group = 9;
int Modify_Group_Type = 10;
}
//ModifyGroupInfoRequest -> type
@@ -225,6 +226,7 @@ public class ProtoConstants {
public interface SystemSettingType {
int Group_Max_Member_Count = 1;
int NOT_ALLOW_USER_NAMES = 2;
}
public interface SearchUserType {
@@ -237,6 +239,12 @@ public class ProtoConstants {
int SearchUserType_Name_Mobile_DisplayName = 100;
}
public interface UserSearchUserType {
int UserSearchUserType_ALL = 0;
int UserSearchUserType_ONLY_USER = 1;
int UserSearchUserType_ONLY_ROBOT = 2;
}
public interface DisableSearchMask {
int DisableSearchDisplayNameMask = 1;
int DisableSearchNameMask = 2;
@@ -389,5 +397,7 @@ public class ProtoConstants {
public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_EXTRA = 122;
public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_MEMBER_EXTRA = 123;
public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_SETTINGS = 124;
public static final int MESSAGE_CONTENT_TYPE_REJECT_JOIN_GROUP = 125;
}
@@ -54041,6 +54041,31 @@ public final class WFCMessage {
* <code>optional int32 page = 3;</code>
*/
int getPage();
// optional string domain_id = 4;
/**
* <code>optional string domain_id = 4;</code>
*/
boolean hasDomainId();
/**
* <code>optional string domain_id = 4;</code>
*/
java.lang.String getDomainId();
/**
* <code>optional string domain_id = 4;</code>
*/
com.google.protobuf.ByteString
getDomainIdBytes();
// optional int32 type = 5;
/**
* <code>optional int32 type = 5;</code>
*/
boolean hasType();
/**
* <code>optional int32 type = 5;</code>
*/
int getType();
}
/**
* Protobuf type {@code SearchUserRequest}
@@ -54108,6 +54133,16 @@ public final class WFCMessage {
page_ = input.readInt32();
break;
}
case 34: {
bitField0_ |= 0x00000008;
domainId_ = input.readBytes();
break;
}
case 40: {
bitField0_ |= 0x00000010;
type_ = input.readInt32();
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -54223,10 +54258,71 @@ public final class WFCMessage {
return page_;
}
// optional string domain_id = 4;
public static final int DOMAIN_ID_FIELD_NUMBER = 4;
private java.lang.Object domainId_;
/**
* <code>optional string domain_id = 4;</code>
*/
public boolean hasDomainId() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional string domain_id = 4;</code>
*/
public java.lang.String getDomainId() {
java.lang.Object ref = domainId_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
if (bs.isValidUtf8()) {
domainId_ = s;
}
return s;
}
}
/**
* <code>optional string domain_id = 4;</code>
*/
public com.google.protobuf.ByteString
getDomainIdBytes() {
java.lang.Object ref = domainId_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
domainId_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
// optional int32 type = 5;
public static final int TYPE_FIELD_NUMBER = 5;
private int type_;
/**
* <code>optional int32 type = 5;</code>
*/
public boolean hasType() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional int32 type = 5;</code>
*/
public int getType() {
return type_;
}
private void initFields() {
keyword_ = "";
fuzzy_ = 0;
page_ = 0;
domainId_ = "";
type_ = 0;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -54253,6 +54349,12 @@ public final class WFCMessage {
if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeInt32(3, page_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBytes(4, getDomainIdBytes());
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeInt32(5, type_);
}
getUnknownFields().writeTo(output);
}
@@ -54274,6 +54376,14 @@ public final class WFCMessage {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(3, page_);
}
if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(4, getDomainIdBytes());
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(5, type_);
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -54396,6 +54506,10 @@ public final class WFCMessage {
bitField0_ = (bitField0_ & ~0x00000002);
page_ = 0;
bitField0_ = (bitField0_ & ~0x00000004);
domainId_ = "";
bitField0_ = (bitField0_ & ~0x00000008);
type_ = 0;
bitField0_ = (bitField0_ & ~0x00000010);
return this;
}
@@ -54436,6 +54550,14 @@ public final class WFCMessage {
to_bitField0_ |= 0x00000004;
}
result.page_ = page_;
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008;
}
result.domainId_ = domainId_;
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
to_bitField0_ |= 0x00000010;
}
result.type_ = type_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -54463,6 +54585,14 @@ public final class WFCMessage {
if (other.hasPage()) {
setPage(other.getPage());
}
if (other.hasDomainId()) {
bitField0_ |= 0x00000008;
domainId_ = other.domainId_;
onChanged();
}
if (other.hasType()) {
setType(other.getType());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -54634,6 +54764,113 @@ public final class WFCMessage {
return this;
}
// optional string domain_id = 4;
private java.lang.Object domainId_ = "";
/**
* <code>optional string domain_id = 4;</code>
*/
public boolean hasDomainId() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional string domain_id = 4;</code>
*/
public java.lang.String getDomainId() {
java.lang.Object ref = domainId_;
if (!(ref instanceof java.lang.String)) {
java.lang.String s = ((com.google.protobuf.ByteString) ref)
.toStringUtf8();
domainId_ = s;
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>optional string domain_id = 4;</code>
*/
public com.google.protobuf.ByteString
getDomainIdBytes() {
java.lang.Object ref = domainId_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
domainId_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>optional string domain_id = 4;</code>
*/
public Builder setDomainId(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000008;
domainId_ = value;
onChanged();
return this;
}
/**
* <code>optional string domain_id = 4;</code>
*/
public Builder clearDomainId() {
bitField0_ = (bitField0_ & ~0x00000008);
domainId_ = getDefaultInstance().getDomainId();
onChanged();
return this;
}
/**
* <code>optional string domain_id = 4;</code>
*/
public Builder setDomainIdBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000008;
domainId_ = value;
onChanged();
return this;
}
// optional int32 type = 5;
private int type_ ;
/**
* <code>optional int32 type = 5;</code>
*/
public boolean hasType() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional int32 type = 5;</code>
*/
public int getType() {
return type_;
}
/**
* <code>optional int32 type = 5;</code>
*/
public Builder setType(int value) {
bitField0_ |= 0x00000010;
type_ = value;
onChanged();
return this;
}
/**
* <code>optional int32 type = 5;</code>
*/
public Builder clearType() {
bitField0_ = (bitField0_ & ~0x00000010);
type_ = 0;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:SearchUserRequest)
}
@@ -67604,44 +67841,45 @@ public final class WFCMessage {
"ead\030\004 \001(\003\022\021\n\tnode_addr\030\005 \001(\t\022\021\n\tnode_por" +
"t\030\006 \001(\005\022\023\n\013server_time\030\007 \001(\003\"P\n\rIMHttpWr",
"apper\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\021Search" +
"\017\n\007request\030\003 \002(\t\022\014\n\004data\030\004 \001(\014\"b\n\021Search" +
"UserRequest\022\017\n\007keyword\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.User\"@\n\026GetChatroomInfoRe" +
"quest\022\023\n\013chatroom_id\030\001 \002(\t\022\021\n\tupdate_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\014member_" +
"count\030\004 \001(\005\022\021\n\tcreate_dt\030\005 \001(\003\022\021\n\tupdate" +
"_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\013chatr" +
"oom_id\030\001 \002(\t\022\021\n\tmax_count\030\002 \001(\005\";\n\022Chatr" +
"oomMemberInfo\022\024\n\014member_count\030\001 \001(\005\022\017\n\007m" +
"embers\030\002 \003(\t\"\026\n\010INT64Buf\022\n\n\002id\030\001 \002(\003\"4\n\023" +
"NotifyRecallMessage\022\n\n\002id\030\001 \002(\003\022\021\n\tfrom_" +
"user\030\002 \002(\t\"/\n\020BlackUserRequest\022\013\n\003uid\030\001 " +
"\002(\t\022\016\n\006status\030\002 \002(\005\"\323\001\n\014RouteRequest\022\013\n\003" +
"app\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\016device_ve" +
"rsion\030\005 \001(\t\022\022\n\nphone_name\030\006 \001(\t\022\020\n\010langu",
"age\030\007 \001(\t\022\024\n\014carrier_name\030\010 \001(\t\022\023\n\013app_v" +
"ersion\030\t \001(\t\022\023\n\013sdk_version\030\n \001(\t\"D\n\rRou" +
"teResponse\022\014\n\004host\030\001 \002(\t\022\021\n\tlong_port\030\002 " +
"\002(\005\022\022\n\nshort_port\030\003 \002(\005\"G\n\017GetTokenReque" +
"st\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\nb" +
"efore_uid\030\002 \002(\003\022\r\n\005count\030\003 \002(\005\022\024\n\014conten" +
"t_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.MessageCo",
"ntent\022\n\n\002to\030\003 \003(\t\022\014\n\004line\030\004 \002(\005\"E\n\035Recal" +
"lMultiCastMessageRequest\022\022\n\nmessage_id\030\001" +
" \002(\003\022\020\n\010receiver\030\002 \003(\t\"@\n\017AuthCodeReques" +
"t\022\021\n\ttarget_id\030\001 \002(\t\022\014\n\004type\030\002 \002(\005\022\014\n\004ho" +
"st\030\003 \002(\t\"o\n\030ApplicationConfigRequest\022\r\n\005" +
"appId\030\001 \002(\t\022\017\n\007appType\030\002 \002(\005\022\021\n\ttimestam" +
"p\030\003 \002(\003\022\r\n\005nonce\030\004 \002(\t\022\021\n\tsignature\030\005 \002(" +
"\tB/\n\025cn.wildfirechat.protoB\nWFCMessageZ\n" +
"./go;proto"
"\001(\005\022\014\n\004page\030\003 \001(\005\022\021\n\tdomain_id\030\004 \001(\t\022\014\n\004" +
"type\030\005 \001(\005\"(\n\020SearchUserResult\022\024\n\005entry\030" +
"\001 \003(\0132\005.User\"@\n\026GetChatroomInfoRequest\022\023" +
"\n\013chatroom_id\030\001 \002(\t\022\021\n\tupdate_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\014member_count\030\004" +
" \001(\005\022\021\n\tcreate_dt\030\005 \001(\003\022\021\n\tupdate_dt\030\006 \001",
"(\003\022\r\n\005extra\030\007 \001(\t\022\r\n\005state\030\010 \001(\005\"F\n\034GetC" +
"hatroomMemberInfoRequest\022\023\n\013chatroom_id\030" +
"\001 \002(\t\022\021\n\tmax_count\030\002 \001(\005\";\n\022ChatroomMemb" +
"erInfo\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\023NotifyR" +
"ecallMessage\022\n\n\002id\030\001 \002(\003\022\021\n\tfrom_user\030\002 " +
"\002(\t\"/\n\020BlackUserRequest\022\013\n\003uid\030\001 \002(\t\022\016\n\006" +
"status\030\002 \002(\005\"\323\001\n\014RouteRequest\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\016device_version\030\005",
" \001(\t\022\022\n\nphone_name\030\006 \001(\t\022\020\n\010language\030\007 \001" +
"(\t\022\024\n\014carrier_name\030\010 \001(\t\022\023\n\013app_version\030" +
"\t \001(\t\022\023\n\013sdk_version\030\n \001(\t\"D\n\rRouteRespo" +
"nse\022\014\n\004host\030\001 \002(\t\022\021\n\tlong_port\030\002 \002(\005\022\022\n\n" +
"short_port\030\003 \002(\005\"G\n\017GetTokenRequest\022\017\n\007u" +
"ser_id\030\001 \002(\t\022\021\n\tclient_id\030\002 \002(\t\022\020\n\010platf" +
"orm\030\003 \001(\005\"r\n\022LoadRemoteMessages\022#\n\014conve" +
"rsation\030\001 \002(\0132\r.Conversation\022\022\n\nbefore_u" +
"id\030\002 \002(\003\022\r\n\005count\030\003 \002(\005\022\024\n\014content_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.MessageContent\022\n" +
"\n\002to\030\003 \003(\t\022\014\n\004line\030\004 \002(\005\"E\n\035RecallMultiC" +
"astMessageRequest\022\022\n\nmessage_id\030\001 \002(\003\022\020\n" +
"\010receiver\030\002 \003(\t\"@\n\017AuthCodeRequest\022\021\n\tta" +
"rget_id\030\001 \002(\t\022\014\n\004type\030\002 \002(\005\022\014\n\004host\030\003 \002(" +
"\t\"o\n\030ApplicationConfigRequest\022\r\n\005appId\030\001" +
" \002(\t\022\017\n\007appType\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" +
".wildfirechat.protoB\nWFCMessageZ\n./go;pr" +
"oto"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -68007,7 +68245,7 @@ public final class WFCMessage {
internal_static_SearchUserRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_SearchUserRequest_descriptor,
new java.lang.String[] { "Keyword", "Fuzzy", "Page", });
new java.lang.String[] { "Keyword", "Fuzzy", "Page", "DomainId", "Type", });
internal_static_SearchUserResult_descriptor =
getDescriptor().getMessageTypes().get(60);
internal_static_SearchUserResult_fieldAccessorTable = new
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.2</version>
<version>1.4.0</version>
</parent>
<artifactId>distribution</artifactId>
+1 -1
View File
@@ -1,5 +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
java -jar checker.jar http://127.0.0.1:18080 123456 http://127.0.0.1 false false
```
来检查。检查之后会产生垃圾数据,请在检查之后停掉IM服务后,再删除掉IM服务数据库。此检查仅检查API,检查通过并不代表部署肯定成功,还需要客户端来验证。
@@ -33,6 +33,8 @@ local_port 80
## MySQL需要把事物隔离级别改成"Read committed",使用命令来修改"set global transaction_isolation='read-committed';",其他数据库默认已经是这个级别不用修改
## 如果使用MySQL,请在c3p0.xml文件中配置JDBC信息。
## 如果是MySQL5.7,需要开启长索引的支持,在数据库中执行命令:"set global innodb_large_prefix=on;"。其他版本默认支持,不用修改。
## 如果使用MySQL 8.0.30以上版本,有个特性是创建表时如果没有主键将会自动创建一个主键"my_key_id",如果此功能打开,在执行mysql脚本V19__add_id_for_sensitive_word.sql时将会报错,提示不能2个主键。
## 解决办法就是运行出错后删除掉系统自动创建的主键"my_key_id",然后继续执行。
embed.db 1
## 是否自动清理历史消息记录,当为true时,IM服务会定时扫描t_messages_x和t_user_messages_x表,清除掉3年前的历史消息。
@@ -106,7 +108,7 @@ message.disable_remote_search false
##如果要避免数据库中明文存储消息内容,请打开这个开关和message.disable_remote_search开关
message.encrypt_message_content false
##允许客户端撤回用户自己发送的消息时限,单位是秒。
##允许客户端撤回用户自己发送的消息时限,单位是秒。0是不允许撤回;-1是无限制撤回。
##Server API不受此限制,可以撤回任意时限内的消息
##群组管理员或群主撤回群成员消息不受此限制,可以撤回任意时限内的消息。但管理员或群主撤回自己的消息还是需要准守此时间限制。
##修改此参数需要同步修改客户端UI,客户端UI代码有判断撤回是否显示的逻辑。
@@ -147,12 +149,37 @@ message.no_forward_admin_message false
## 消息转发功能开启时,转发信息是否带上用户clientId和平台类型。
message.forward_with_client_info false
## 消息转发功能开启时,转发信息是否带上发送者的用户信息
message.forward_with_sender_info false
## 消息转发功能开启时,转发信息是否带上目标的信息,单聊时是对方用户信息,群聊时是群组信息,频道时是频道信息
message.forward_with_target_info false
## 允许发送单聊消息给被封禁用户
message.allow_send_to_forbidden_user false
## 机器人回调信息是否带上用户clientId和平台类型。
robot.callback_with_client_info false
## 机器人回调信息是否带上发送者的用户信息
robot.callback_with_sender_info false
## 机器人回调信息是否带上目标的信息,单聊时是对方用户信息,群聊时是群组信息,频道时是频道信息
robot.callback_with_target_info false
## 是否允许@会话外的机器人。如果为true,单聊或者群聊时,可以@不在会话中的机器人。当机器人收到消息后,可以回复消息。
## 如果为false,不能@不在会话中的机器人。机器人不在会话中时,也不能回复消息。
robot.mention_external_robot true
## 频道回调信息是否带上用户clientId和平台类型。
channel.callback_with_client_info false
## 频道回调信息是否带上发送者的用户信息。
channel.callback_with_sender_info false
## 频道回调信息是否带上频道信息
channel.callback_with_target_info false
## 频道回调新方式,在新方式下,如果有callback地址就会总是回调客户端发送的消息(包括owner和订阅者)。automatic属性控制订阅者发送的消息是否发给owner, 0发,1不发。
## 旧的方式是,automatic为0时,订阅者的消息发给owner,不转发消息到callback地址。为1时,把订阅者的消息转发给callback地址,不发给owner。
channel.new_callback_feature true
@@ -163,8 +190,8 @@ friend.disable_search false
##禁止按照昵称搜索用户。
friend.disable_nick_name_search false
##禁止按照用户id搜索用户,默认为true。
friend.disable_user_id_search true
##禁止按照用户id搜索用户,默认为false。
friend.disable_user_id_search false
##禁止发送好友邀请,通过server api添加好友不受此限制(force参数需要为true)
friend.disable_friend_request false
@@ -223,8 +250,12 @@ group.visible_quit_or_kickoff_notification 0
## 是否禁止陌生人拉人入群,默认为false
group.disable_stranger_invite false
## 创建群组或者加人时。可能会有成员加入失败(黑名单,或者不允许陌生人拉入群)。当出现有成员失败时,如果此开关为关,操作会失败。
## 如果此开关打开,操作会返回成功,另外在群里发送一条通知消息 XXX 拒绝加入群组。默认为开。
group.add_member_allow_part_success true
## 群组信息是否标记删除
group.enable_mark_deletion false
group.enable_mark_deletion true
## 隐藏用户信息属性类型,2是性别,3是电话号码,4是邮箱,5是地址,6是公司信息,7是社交账号,8是Extra信息。当需要隐藏多个时以英文逗号分开;
## 本配置是为了提高安全性,避免把对应信息同步到客户端,这样就能防止程序被破解从而拿到用户关键信息。仅对客户端有效,server api不受影响。
@@ -426,7 +457,14 @@ push.harmony.server.address http://localhost:8085/harmony/push
## 内置文本敏感词过滤处理方法,当命中敏感词后,消息会被记录到t_sensitive_messages表中,然后根据type类型做不同的处理,处理方式如下:
## 0 发送失败;1 发送成功但消息被服务器直接丢弃;2 命中的敏感词被替换成***然后正常发送;3 正常发送。
## 如果开启 message.sensitive.forward.url 配置,命中敏感词的消息还会被回调到这个地址
sensitive.filter.type 0
sensitive.filter.type 2
## 敏感词是否只处理消息。如果为true,只过滤消息;如果为false,会同时过滤用户昵称、群组名和群昵称。
## 除了消息之外的信息只支持内部敏感词处理,不支持外置审核。
sensitive.only_message false
## 敏感词添加或者删除有2种方式,一种是通过Server API进行,这种方式会立即生效。另外一种方法是修改数据库,直接中数据库的t_sensitive_word表中处理
## 修改数据库的方法不会立即生效,IM服务会2个小时重新加载一次敏感词。所以如果直接修改敏感词表,需要等2个小时,或者重启才能生效。
## 如果内置敏感词库无法满足您的需求,可以开发部署独立敏感词审核服务。配置如下地址和消息类型,IM服务会把指定消息类型的消息回调到指定地址,内置的敏感词审核和敏感词转发功能就不再起作用了。
## 审核服务返回状态码200表示继续发送,如果需要替换内容,返回状态码200并且内容为替换后的内容。返回403表示不允许发送。其它错误继续发送。
@@ -75,11 +75,9 @@ 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
@@ -90,7 +90,8 @@ JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=500"
#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服务预留的内存大小,注意需要刨除操作系统占用,如果有其它系统也需要相应去除占用。"
echo "请设置JVM参数Xmx和Xms,设置为您为IM服务预留的内存大小,注意需要刨除操作系统占用,如果有其它系统也需要相应去除占用,还需要减去堆外内存占用。"
echo "建议设置为总内存的60%以下,比如16G总内存,Xmx可以设置为9G"
echo ""
#JAVA_OPTS="$JAVA_OPTS -Xmx2G"
#JAVA_OPTS="$JAVA_OPTS -Xms2G"
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>1.3.2</version>
<version>1.4.0</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
+61 -1
View File
@@ -8,9 +8,69 @@
7. *** 从0.68 版本起添加了pc在线是否默认手机接收推送的开关,默认为开,与以前版本作用相反,请注意兼容(可以关掉与之前保持一致或者升级客户端) ***
8. *** 从0.78 版本起把MySQL数据库中关键字都改为大小写敏感,另外生成id的方法也做了改变,只生成小写的id,避免出现id重复的问题,建议所有客户都升级 ***
9. *** 从0.79 版本起把log4j升级到log4j2,因为log4j已经不再维护而且还有已知的漏洞,建议所有客户都升级,升级时注意更新log4j2的配置文件 ***
10. *** 5. 0.97版本更改了启动脚本```wildfirechat.sh```,如果是升级服务,请注意更新启动脚本。***
10. *** 0.97版本更改了启动脚本```wildfirechat.sh```,如果是升级服务,请注意更新启动脚本。***
11. *** 1.3.8版本添加了server api发送消息的限制,限制消息体最大内容不能超过64KB,如果升级请注意业务系统发送消息大小。***
# 更新记录
--------------
Release note 1.4.0:
1. 添加对用户IP来源的记录。
2. 移除无用的plugin,可以在java8环境下编译通过。
3. Server SDK解决某些Java版本下消息没有注册的问题。
4. Server SDK解决解析图片缩略图不存在的错误问题。
5. Server SDK解决发送带引用的消息客户端无法解析的问题。
--------------
Release note 1.3.9:
1. 解决server sdk反复初始化内存泄漏的问题。
2. 群组支持用户@不在群组中的机器人。
3. 单聊会话支持@机器人。
4. 机器人支持回复消息,可以回复单聊或者群聊消息。
--------------
Release note 1.3.8:
1. 添加限制,server api发送消息,限制消息体不能大于64KB。
2. 添加配置敏感词是否过滤用户信息群组信息昵称等。
3. 配置文件可以设置不允许使用的用户名字群组名称群名片等。
4. server api发送消息添加参数,可以以用户权限发送消息。
5. server api添加群备注和收藏群组接口。
--------------
Release note 1.3.7:
1. 搜索用户可以指定搜索机器人、普通用户或者所有。
2. 添加群组成员时,允许部分失败。
3. 解决内置存储上传文件时可能内存泄漏。
4. 支持客户端上传本地角标,用于推送得到较为精确的角标数字。
5. 解决机器人回调配置携带发送者用户信息无效的问题。
--------------
Release note 1.3.6:
1. Server API创建频道时,返回频道ID和频道密钥。
2. 解决外置审核替换内容没有成功的问题。
3. 修改撤回消息限制,可以运行不限制撤回。
4. 创建/更新频道接口可以传菜单参数。
5. Server API支持修改群组类型。
--------------
Release note 1.3.5:
1. 转发消息回调中可以配置带上发送者和目标信息。
2. Server SDK中添加撤回和删除消息。
3. Server SDK中添加发送朋友圈接口。
4. 添加配置是否允许发送消息给被封禁用户。
5. 音视频通话挂断推送中带上发起消息的ID
--------------
Release note 1.3.4:
1. 优化Server SDK中消息内容的处理方式。
2. Server SDK中添加注册消息接口,在使用自定义消息时,不需要修改Server SDK源码。
3. 用户撤回时间配置允许为负数,为负数时可以任意时间撤回。
4. Server SDK添加超时参数。
5. 解决当分段拉取消息时,可能丢失消息的问题。
--------------
Release note 1.3.3:
1. 转移群组时检查新群主是否在群中。
2. 机器人API添加定向消息接口。
--------------
Release note 1.3.2:
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.2</version>
<version>1.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -4,16 +4,19 @@ import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.pojos.*;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
import cn.wildfirechat.sdk.utilities.ChannelHttpUtils;
import com.google.gson.Gson;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Channel;
//仅专业版支持,社区版不支持
public class ChannelServiceApi {
public class ChannelServiceApi implements Closeable {
private final ChannelHttpUtils channelHttpUtils;
public ChannelServiceApi(String imurl, String channelId, String secret) {
@@ -51,7 +54,7 @@ public class ChannelServiceApi {
return channelHttpUtils.httpJsonPost(path, null, OutputGetChannelInfo.class);
}
public IMResult<Void> modifyChannelMenu(List<OutputGetChannelInfo.OutputMenu> menus) throws Exception {
public IMResult<Void> modifyChannelMenu(List<PojoChannelMenu> menus) throws Exception {
String menuStr = new Gson().toJson(menus);
return modifyChannelInfo(ProtoConstants.ModifyChannelInfoType.Modify_Channel_Menu, menuStr);
}
@@ -59,12 +62,27 @@ public class ChannelServiceApi {
public IMResult<SendMessageResult> sendMessage(int line, List<String> targets, MessagePayload payload) throws Exception {
String path = APIPath.Channel_Message_Send;
SendChannelMessageData messageData = new SendChannelMessageData();
messageData.setLine(0);
messageData.setLine(line);
messageData.setTargets(targets);
messageData.setPayload(payload);
return channelHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
}
public IMResult<String> recallMessage(long messageUid) throws Exception {
String path = APIPath.Channel_Msg_Recall;
RecallMessageData messageData = new RecallMessageData();
messageData.setMessageUid(messageUid);
return channelHttpUtils.httpJsonPost(path, messageData, String.class);
}
public IMResult<Void> republishMessage(long messageUid, List<String> targets) throws Exception {
String path = APIPath.Channel_Msg_Republish;
RepublishChannelMessageData messageData = new RepublishChannelMessageData();
messageData.setMessageId(messageUid);
messageData.setTargets(targets);
return channelHttpUtils.httpJsonPost(path, messageData, Void.class);
}
public IMResult<Void> subscribe(String userId) throws Exception {
String path = APIPath.Channel_Subscribe;
InputChannelSubscribe input = new InputChannelSubscribe();
@@ -113,4 +131,8 @@ public class ChannelServiceApi {
return configData;
}
@Override
public void close() throws IOException {
channelHttpUtils.close();
}
}
@@ -1,6 +1,7 @@
package cn.wildfirechat.sdk;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.*;
import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
@@ -178,6 +179,36 @@ public class GroupAdmin {
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
public static IMResult<Void> setGroupRemark(String userId, String groupId, String remark) throws Exception {
return GeneralAdmin.setUserSetting(userId, 26, groupId, remark);
}
public static IMResult<String> getGroupRemark(String userId, String groupId) throws Exception {
IMResult<UserSettingPojo> imResult = GeneralAdmin.getUserSetting(userId, 26, groupId);
IMResult<String> result = new IMResult<>();
result.code = imResult.code;;
result.msg = imResult.msg;;
if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
result.result = imResult.result.getValue();
}
return result;
}
public static IMResult<Void> setFavGroup(String userId, String groupId, boolean fav) throws Exception {
return GeneralAdmin.setUserSetting(userId, 6, groupId, fav?"1":"0");
}
public static IMResult<Boolean> isFavGroup(String userId, String groupId) throws Exception {
IMResult<UserSettingPojo> imResult = GeneralAdmin.getUserSetting(userId, 6, groupId);
IMResult<Boolean> result = new IMResult<>();
result.code = imResult.code;;
result.msg = imResult.msg;;
if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
result.result = "1".equals(imResult.getResult().getValue());
}
return result;
}
public static IMResult<OutputGroupIds> getUserGroups(String user) throws Exception {
String path = APIPath.Get_User_Groups;
InputUserId inputUserId = new InputUserId();
File diff suppressed because one or more lines are too long
@@ -39,12 +39,13 @@ public class MeshAdmin {
return AdminHttpUtils.httpJsonPost(path, getUserInfo, OutputUserInfoList.class);
}
public static IMResult<PojoSearchUserRes> searchUser(String keyword, int searchType, int page) throws Exception {
public static IMResult<PojoSearchUserRes> searchUser(String keyword, int searchType, int userType, int page) throws Exception {
String path = APIPath.Search_User;
PojoSearchUserReq req = new PojoSearchUserReq();
req.keyword = keyword;
req.searchType = searchType;
req.page = page;
req.userType = userType;
return AdminHttpUtils.httpJsonPost(path, req, PojoSearchUserRes.class);
}
@@ -226,4 +227,10 @@ public class MeshAdmin {
return AdminHttpUtils.httpJsonPost(path, event, Void.class);
}
public static IMResult<PojoDomainPingResponse> pingDomain(String domainId) throws Exception {
String path = APIPath.Ping_Domain;
PojoDomainPingRequest request = new PojoDomainPingRequest();
request.domainId = domainId;
return AdminHttpUtils.httpJsonPost(path, request, PojoDomainPingResponse.class);
}
}
@@ -11,14 +11,21 @@ public class MessageAdmin {
public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload) throws Exception {
return sendMessage(sender, conversation, payload, null);
}
//toUsers为发送给会话中部分用户用的,正常为null,仅当需要指定群/频道/聊天室中部分接收用户时使用
public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers) throws Exception {
return sendMessage(sender, conversation, payload, toUsers, false);
}
//toUsers为发送给会话中部分用户用的,正常为null,仅当需要指定群/频道/聊天室中部分接收用户时使用
public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers, boolean isUserMessage) throws Exception {
String path = APIPath.Msg_Send;
SendMessageData messageData = new SendMessageData();
messageData.setSender(sender);
messageData.setConv(conversation);
messageData.setPayload(payload);
messageData.setToUsers(toUsers);
messageData.setUserMessage(isUserMessage);
if (payload.getType() == 1 && (payload.getSearchableContent() == null || payload.getSearchableContent().isEmpty())) {
System.out.println("Payload错误,Payload格式应该跟客户端消息encode出来的Payload对齐,这样客户端才能正确识别。比如文本消息,文本需要放到searchableContent属性。请与客户端同事确认Payload的格式,或则去 https://gitee.com/wfchat/android-chat/tree/master/client/src/main/java/cn/wildfirechat/message 找到消息encode的实现方法!");
}
@@ -0,0 +1,15 @@
package cn.wildfirechat.sdk;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.pojos.*;
import cn.wildfirechat.pojos.moments.FeedPojo;
import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
public class MomentsAdmin {
public static IMResult<SendMessageResult> postFeeds(FeedPojo feedPojo) throws Exception {
String path = APIPath.Admin_Moments_Post_Feed;
return AdminHttpUtils.httpJsonPost(path, feedPojo, SendMessageResult.class);
}
}
@@ -8,11 +8,13 @@ import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.RobotHttpUtils;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Robot;
public class RobotService {
public class RobotService implements Closeable {
private final RobotHttpUtils robotHttpUtils;
public RobotService(String url, String robotId, String robotSecret) {
@@ -24,10 +26,24 @@ public class RobotService {
}
public IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload) throws Exception {
return sendMessage(sender, conversation, payload, null);
}
public IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers) throws Exception {
String path = APIPath.Robot_Message_Send;
SendMessageData messageData = new SendMessageData();
messageData.setSender(sender);
messageData.setConv(conversation);
messageData.setToUsers(toUsers);
messageData.setPayload(payload);
return robotHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
}
public IMResult<SendMessageResult> replyMessage(long messageUid, MessagePayload payload, boolean only2Sender) throws Exception {
String path = APIPath.Robot_Message_Reply;
ReplyMessageData messageData = new ReplyMessageData();
messageData.setMessageUid(messageUid);
messageData.setOnly2Sender(only2Sender);
messageData.setPayload(payload);
return robotHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
}
@@ -418,4 +434,9 @@ public class RobotService {
requestPojo.rl = removeList;
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
}
@Override
public void close() throws IOException {
robotHttpUtils.close();
}
}
@@ -32,7 +32,7 @@ public class ArticlesMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(topArticle.title);
JSONObject object = new JSONObject();
@@ -53,6 +53,7 @@ public class ArticlesMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
try {
super.decode(payload);
JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
JSONObject topObj = (JSONObject) object.get("top");
this.topArticle = Article.fromJson(topObj);
@@ -133,7 +133,7 @@ public class CallStartMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(callId);
payload.setPushContent("音视频通话邀请");
@@ -175,6 +175,7 @@ public class CallStartMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
callId = payload.getContent();
try {
@@ -100,7 +100,7 @@ public class CardMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(target);
JSONObject objWrite = new JSONObject();
objWrite.put("t", type);
@@ -116,6 +116,7 @@ public class CardMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
target = payload.getContent();
try {
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
@@ -0,0 +1,47 @@
package cn.wildfirechat.sdk.messagecontent;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class DeleteMessageContent extends MessageContent {
private long messageId;
private String operatorId;
//必须有个空的构造函数
public DeleteMessageContent() {
}
public long getMessageId() {
return messageId;
}
public String getOperatorId() {
return operatorId;
}
@Override
public int getContentType() {
return ProtoConstants.ContentType.Delete;
}
@Override
public int getPersistFlag() {
return ProtoConstants.PersistFlag.Not_Persist;
}
@Override
public MessagePayload encode() {
throw new RuntimeException("Delete message cannot encode");
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
operatorId = payload.getContent();
messageId = Long.parseLong(new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8));
}
}
@@ -26,7 +26,7 @@ public class FileMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(name);
payload.setContent(size + "");
@@ -51,7 +51,7 @@ public class FileMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
if (payload.getSearchableContent().startsWith(FILE_NAME_PREFIX)) {
name = payload.getSearchableContent().substring(payload.getSearchableContent().indexOf(FILE_NAME_PREFIX) + FILE_NAME_PREFIX.length());
@@ -34,9 +34,11 @@ public class ImageMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent("[图片]");
payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));
if(thumbnailBytes != null) {
payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));
}
return payload;
}
@@ -44,8 +46,10 @@ public class ImageMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());
super.decode(payload);
if(payload.getBase64edData() != null) {
thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());
}
}
@Override
@@ -72,9 +72,7 @@ public class LinkMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(title);
JSONObject objWrite = new JSONObject();
objWrite.put("d", contentDigest);
@@ -88,9 +86,8 @@ public class LinkMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
title = payload.getSearchableContent();
try {
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
@@ -66,7 +66,7 @@ public class LocationMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(title);
payload.setBase64edData(Base64.getEncoder().encodeToString(this.thumbnailByte));
@@ -82,6 +82,7 @@ public class LocationMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
this.thumbnailByte = Base64.getDecoder().decode(payload.getBase64edData());
}
@@ -14,12 +14,18 @@ abstract public class MediaMessageContent extends MessageContent {
}
@Override
protected MessagePayload encodeBase() {
MessagePayload payload = super.encodeBase();
public MessagePayload encode() {
MessagePayload payload = super.encode();
payload.setRemoteMediaUrl(remoteMediaUrl);
payload.setMediaType(getMediaType());
return payload;
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
remoteMediaUrl = payload.getRemoteMediaUrl();
}
protected abstract int getMediaType();
}
@@ -22,7 +22,7 @@ public abstract class MessageContent {
return this;
}
protected MessagePayload encodeBase() {
public MessagePayload encode() {
MessagePayload payload = new MessagePayload();
payload.setType(getContentType());
payload.setPersistFlag(getPersistFlag());
@@ -32,13 +32,11 @@ public abstract class MessageContent {
return payload;
}
protected void decodeBase(MessagePayload payload) {
protected void decode(MessagePayload payload) {
this.mentionedType = payload.getMentionedType();
this.mentionedTargets = payload.getMentionedTarget();
this.extra = payload.getExtra();
}
abstract public int getContentType();
abstract public int getPersistFlag();
abstract public MessagePayload encode();
abstract public void decode(MessagePayload payload);
}
@@ -8,11 +8,38 @@ import cn.wildfirechat.sdk.utilities.ClassUtil;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class MessageContentFactory {
private static final Map<Integer, Class<MessageContent>> contentClassMap = new ConcurrentHashMap<>();
private static final Map<Integer, Class<? extends MessageContent>> contentClassMap = new ConcurrentHashMap<>();
private static List<Class> buildinMessageContents = Arrays.asList(
ArticlesMessageContent.class,
StreamTextGeneratedMessageContent.class,
CallStartMessageContent.class,
StreamTextGeneratingMessageContent.class,
CardMessageContent.class,
MultiCallOngoingMessageContent.class,
TextMessageContent.class,
DeleteMessageContent.class,
NotDeliveredMessageContent.class,
TipNotificationMessageContent.class,
FileMessageContent.class,
PTTSoundMessageContent.class,
TypingMessageContent.class,
ImageMessageContent.class,
RecallMessageContent.class,
UnknownMessageContent.class,
LinkMessageContent.class,
RichNotificationMessageContent.class,
VideoMessageContent.class,
LocationMessageContent.class,
SoundMessageContent.class,
StickerMessageContent.class
);
static {
registerAllMessageContent();
@@ -36,7 +63,7 @@ public class MessageContentFactory {
}
public static MessageContent decodeMessageContent(MessagePayload messagePayload) {
Class<MessageContent> cls = contentClassMap.get(messagePayload.getType());
Class<? extends MessageContent> cls = contentClassMap.get(messagePayload.getType());
MessageContent messageContent;
if(cls != null) {
try {
@@ -49,12 +76,25 @@ public class MessageContentFactory {
} else {
messageContent = new UnknownMessageContent();
}
messageContent.decodeBase(messagePayload);
messageContent.decode(messagePayload);
return messageContent;
}
public static void registerCustomMessageContent(Class<? extends MessageContent> cls) throws Exception {
MessageContent content = cls.newInstance();
contentClassMap.put(content.getContentType(), cls);
}
private static void registerAllMessageContent() {
try {
for (Class buildinMessageContent : buildinMessageContents) {
MessageContent content = (MessageContent)buildinMessageContent.newInstance();
contentClassMap.put(content.getContentType(), buildinMessageContent);
}
} catch (Exception e) {
e.printStackTrace();
}
try {
for (Class cls : ClassUtil.getAllAssignedClass(MessageContent.class)) {
if(!Modifier.isAbstract(cls.getModifiers())) {
@@ -43,7 +43,7 @@ public class MultiCallOngoingMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(callId);
JSONObject object = new JSONObject();
object.put("initiator", this.initiator);
@@ -60,6 +60,7 @@ public class MultiCallOngoingMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
this.callId = payload.getContent();
try {
JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
@@ -57,7 +57,7 @@ public class NotDeliveredMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
JSONObject obj = new JSONObject();
obj.put("mid", this.messageUid);
obj.put("all", this.allFailure);
@@ -74,7 +74,7 @@ public class NotDeliveredMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
try {
super.decode(payload);
JSONObject obj = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
this.messageUid = (long) obj.get("mid");
this.allFailure = (boolean) obj.get("all");
@@ -0,0 +1,122 @@
package cn.wildfirechat.sdk.messagecontent;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import org.apache.http.util.TextUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class RecallMessageContent extends MessageContent {
private long messageId;
private String operatorId;
private String originalSender;
private int originalContentType;
private String originalSearchableContent;
private String originalContent;
private String originalExtra;
private byte[] originalBinaryContent;
private int originalMediaType;
private String originalMediaUrl;
private long originalMessageTimestamp;
//必须有个空的构造函数
public RecallMessageContent() {
}
public long getMessageId() {
return messageId;
}
public String getOperatorId() {
return operatorId;
}
public String getOriginalSender() {
return originalSender;
}
public int getOriginalContentType() {
return originalContentType;
}
public String getOriginalSearchableContent() {
return originalSearchableContent;
}
public String getOriginalContent() {
return originalContent;
}
public String getOriginalExtra() {
return originalExtra;
}
public long getOriginalMessageTimestamp() {
return originalMessageTimestamp;
}
public byte[] getOriginalBinaryContent() {
return originalBinaryContent;
}
public int getOriginalMediaType() {
return originalMediaType;
}
public String getOriginalMediaUrl() {
return originalMediaUrl;
}
@Override
public int getContentType() {
return ProtoConstants.ContentType.Recall;
}
@Override
public int getPersistFlag() {
return ProtoConstants.PersistFlag.Persist;
}
@Override
public MessagePayload encode() {
throw new RuntimeException("Recall message cannot encode");
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
operatorId = payload.getContent();
messageId = Long.parseLong(new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8));
if(!TextUtils.isEmpty(payload.getExtra())) {
try {
JSONObject dictionary = (JSONObject) new JSONParser().parse(payload.getExtra());
originalSender = (String) dictionary.get("s");
if (dictionary.containsKey("t")) {
originalContentType = ((Number) dictionary.get("t")).intValue();
}
originalSearchableContent = (String) dictionary.get("sc");
originalContent = (String) dictionary.get("c");
originalExtra = (String) dictionary.get("e");
if (dictionary.containsKey("ts")) {
originalMessageTimestamp = ((Number) dictionary.get("ts")).longValue();
}
if (dictionary.containsKey("mt")) {
originalMediaType = ((Number) dictionary.get("mt")).intValue();
}
originalMediaUrl = (String) dictionary.get("mu");
if (dictionary.containsKey("mb")) {
originalBinaryContent = Base64.getDecoder().decode((String) dictionary.get("mb"));
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -89,7 +89,7 @@ public class RichNotificationMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setPushContent(title);
payload.setContent(desc);
JSONObject jsonObject = new JSONObject();
@@ -113,5 +113,6 @@ public class RichNotificationMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
}
}
@@ -35,11 +35,12 @@ public class SoundMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
}
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
JSONObject jsonObject = new JSONObject();
jsonObject.put("duration", duration);
payload.setContent(jsonObject.toJSONString());
@@ -34,7 +34,7 @@ public class StickerMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent("[动态表情]");
JSONObject objWrite = new JSONObject();
objWrite.put("x", width);
@@ -47,8 +47,7 @@ public class StickerMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
try {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
width = (int) jsonObject.get("x");
@@ -38,13 +38,14 @@ public class StreamTextGeneratedMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
this.streamId = payload.getContent();
this.text = payload.getSearchableContent();
}
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(text);
payload.setContent(streamId);
return payload;
@@ -38,13 +38,14 @@ public class StreamTextGeneratingMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
streamId = payload.getContent();
text = payload.getSearchableContent();
}
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(text);
payload.setContent(streamId);
return payload;

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