Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98388a5129 | ||
|
|
1a89714df9 | ||
|
|
a855652c26 | ||
|
|
21aadd9c0b | ||
|
|
5522a8689d | ||
|
|
bf52a00304 | ||
|
|
3349e2a4e5 | ||
|
|
70f3f96f7a | ||
|
|
5e9d411f1b | ||
|
|
e74fd0c660 | ||
|
|
d1232abe39 | ||
|
|
1df192f730 | ||
|
|
f897e640fc | ||
|
|
ee6e4f96fb | ||
|
|
d14dc74566 | ||
|
|
ff75379779 | ||
|
|
b95a6b7785 | ||
|
|
5acb3044ac | ||
|
|
ae084063f4 | ||
|
|
cb3a82559d | ||
|
|
9191204bb0 | ||
|
|
6587a88ca9 | ||
|
|
86c1a2e140 | ||
|
|
83e9679339 | ||
|
|
dafb0cd4d9 | ||
|
|
cbcc8310c4 | ||
|
|
ade58efc11 | ||
|
|
d45da9674e | ||
|
|
f603a677ea | ||
|
|
03894aea9a | ||
|
|
8635153e59 | ||
|
|
3d98d17b0d | ||
|
|
0549bc502f | ||
|
|
1b8cf3e5f9 | ||
|
|
f3f08b3026 | ||
|
|
78e6efce14 | ||
|
|
462423a6f3 | ||
|
|
55190a4f76 | ||
|
|
4ed21ecb03 | ||
|
|
1ff3b592bd | ||
|
|
fbc2351d82 | ||
|
|
dd1783d4ac | ||
|
|
845e6ff8aa | ||
|
|
6d91f3869e | ||
|
|
d100bd5fb1 | ||
|
|
bf22b365a8 | ||
|
|
f1298a51ae | ||
|
|
41f62c6354 | ||
|
|
a45de0ecd1 | ||
|
|
fc35865478 | ||
|
|
b1f59498e5 | ||
|
|
04f5471385 | ||
|
|
291fdfb08d | ||
|
|
52de13e20d | ||
|
|
c1d353bce9 | ||
|
|
9d83f8e3fa | ||
|
|
94833780ef | ||
|
|
d0fdf55db4 | ||
|
|
ea00ef6b7f | ||
|
|
a11cf3c564 | ||
|
|
f5af956298 | ||
|
|
4005a4babe | ||
|
|
6ef8b78452 | ||
|
|
100a1bd44c |
@@ -7,9 +7,9 @@
|
||||
* 性能强大,专业版IM服务支持百万在线和集群部署,业内顶尖性能水平,详情参考野火性能报告。
|
||||
* 部署运维简单,依赖服务少,稍加配置一键启动。
|
||||
* 安全加密。网络连接AES加密。客户端数据库SqlCipher加密。安全无小事。
|
||||
* 全平台客户端,支持Android、iOS、Web、小程序、UniApp、Flutter、Windows、Mac OS、Linux等所有常见平台。
|
||||
* 全平台客户端,支持Android、iOS、鸿蒙、Web、小程序、UniApp、Flutter、Windows、Mac OS、Linux等所有常见平台。
|
||||
* 四端同时在线(移动端,pc端,web端和小程序端),数据和状态多端完美同步。
|
||||
* 支持国产化。支持国产化操作系统、国产化芯片和国产操作系统。支持国密加密。
|
||||
* 支持国产化。支持国产化操作系统、国产化芯片和国产数据库。支持国密加密。
|
||||
* 客户端使用微信[mars](https://github.com/tencent/mars)连接库,野火IM可能是最适应中国网络国情的即时通讯服务。
|
||||
* 支持加速点加速,即可用于全球应用,也可用于政企内外双网复杂的网络环境。
|
||||
* 支持阅读回执和在线状态功能,适用于办公环境。
|
||||
@@ -22,9 +22,10 @@
|
||||
* API丰富,方便与其它服务系统的对接。
|
||||
* 拥有机器人和公众号功能,免费的频道(公众号)管理后台。
|
||||
* 超级群组功能,可以支持万人大群。
|
||||
* 支持多个IM服务组网互通,打破孤岛,适用于集团公司下多个分公司互联互通。
|
||||
* 社区版IM服务和移动端免费商用,可以免费构建出完备的移动互联网应用。
|
||||
* 收费项目非常便宜,野火独有的试用模式,可以先部署到客户环境试用6个月,试用满意后再购买,避免上当受骗。
|
||||
* 技术支持专业和高效,核心研发人员及时处理issue和论坛回复。
|
||||
* 技术支持专业高效,***核心研发***及时处理issue和工单,能最快解决用户的技术难题。技术支持不收费,让客户顺利使用是我们最大的愿望。
|
||||
|
||||
## 野火开源项目
|
||||
主要包括以下项目:
|
||||
@@ -156,6 +157,9 @@ mvn clean package
|
||||
## 服务对象
|
||||
因为野火的使用范围比较广,难免被一些不法分子利用,国内反诈反赌力度很大,所以国内多地警方都跟我们都有过联系。***为了预防我们的产品被用于非法目的,试用及购买只能支持境内法人单位,不接受个人或者境外团体。如果我们发现产品被用于非法目的,我们会立即停止技术支持服务并且报警和配合警方调查。请用于非法目的用户绕行!***
|
||||
|
||||
## 常见问题
|
||||
请参考文档[常见问题](https://docs.wildfirechat.cn/faq/server.html)
|
||||
|
||||
## 应用截图
|
||||
登录界面
|
||||
|
||||
|
||||
@@ -68,6 +68,10 @@ token.key testim
|
||||
##是否使用AES256加密。默认客户端和服务器都是AES128加密,如果需要开启AES256,需要客户端和IM服务同时开通。
|
||||
#encrypt.use_aes256 true
|
||||
|
||||
##当创建一个对象时(用户,群组,频道,机器人等),如果没有传入ID,野火会为这个对象生成一个ID。如果id.use_uuid为true,会使用uuid作为对象ID,否则会使用野火短ID,默认为false。
|
||||
## 短ID有个很大的风险是容易被人穷举进行攻击。建议用UUID。
|
||||
id.use_uuid true
|
||||
|
||||
##首次登录,是否接收之前的历史消息。
|
||||
##0 不接收历史消息,只接收${message.compensate_time_limit}毫秒以内的消息,由于服务器没有保存已经收取记录,所以如果有超过${message.compensate_time_limit}毫秒之前未收取的消息也不会收取下拉;
|
||||
##1接收,会接收 message.max_queue 配置的条数的历史消息
|
||||
@@ -91,9 +95,15 @@ message.disable_stranger_chat false
|
||||
##当禁止陌生人聊天时,允许聊天的用户id,比如管理员或者文件传输助手等。用户id以英文逗号分割。
|
||||
message.allow_stranger_chat_list admin,FireRobot,wfc_file_transfer
|
||||
|
||||
##当禁止陌生人聊天时,允许聊天的线路。
|
||||
#message.allow_stranger_line 100,101
|
||||
|
||||
##黑名单策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃
|
||||
message.blacklist.strategy 0
|
||||
|
||||
##拉黑对方后,对方不能发送消息给你。这个开关确定拉黑对方后你还能不能给对方发送消息。
|
||||
message.blacklist.allow_send_to_black false
|
||||
|
||||
##是否禁止服务器端消息搜索,该功能暂未实现。目前的影响是如果打开,则存储消息时不单独保存_searchable_content字段
|
||||
message.disable_remote_search false
|
||||
|
||||
@@ -142,12 +152,33 @@ 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
|
||||
|
||||
## 频道回调信息是否带上用户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
|
||||
@@ -173,6 +204,9 @@ friend.reject_request_duration 2592000000
|
||||
##好友请求过期时间,单位是毫秒,默认是7天,0为无限长期限。
|
||||
friend.request_expiration_duration 604800000
|
||||
|
||||
##好友请求限制频率,一个用户24小时之内允许请求好友的次数,默认不限频。
|
||||
friend.request_rate_limit 30
|
||||
|
||||
##请求添加机器人为好友时,机器人是否自动接受,默认为true
|
||||
friend.robot_auto_accept true
|
||||
|
||||
@@ -254,15 +288,6 @@ client.request_rate_limit 100
|
||||
##关于对象存储的详细信息请参考:https://docs.wildfirechat.cn/server/oss.html
|
||||
media.server.use_qiniu 0
|
||||
|
||||
##媒体类型分类
|
||||
#Media_Type_GENERAL = 0,
|
||||
#Media_Type_IMAGE = 1,
|
||||
#Media_Type_VOICE = 2,
|
||||
#Media_Type_VIDEO = 3,
|
||||
#Media_Type_FILE = 4,
|
||||
#Media_Type_PORTRAIT = 5,
|
||||
#Media_Type_FAVORITE = 6
|
||||
|
||||
# qiniu media server configuration
|
||||
qiniu.server_url http://up.qbox.me
|
||||
qiniu.access_key tU3vdBK5BL5j4N7jI5N5uZgq_HQDo170w5C9Amnn
|
||||
@@ -286,11 +311,21 @@ qiniu.bucket_portrait_domain http://cdn2.wildfirechat.cn
|
||||
qiniu.bucket_favorite_name storage
|
||||
qiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn
|
||||
|
||||
##媒体类型分类
|
||||
#Media_Type_GENERAL = 0,
|
||||
#Media_Type_IMAGE = 1,
|
||||
#Media_Type_VOICE = 2,
|
||||
#Media_Type_VIDEO = 3,
|
||||
#Media_Type_FILE = 4,
|
||||
#Media_Type_PORTRAIT = 5,
|
||||
#Media_Type_FAVORITE = 6,
|
||||
#Media_Type_STICKER = 7,
|
||||
#Media_Type_MOMENTS = 8
|
||||
|
||||
# local media server configuration
|
||||
# 本地媒体服务器配置。
|
||||
local.media.storage.root media
|
||||
# 如果使用内置文件存储,文件上传后地址默认为 http://server.ip:http_port/fs/5/2021/03/27/08/filename。
|
||||
# 如果使用内置文件存储,文件上传后地址默认为 http://server.ip:http_port/fs/5/2021/03/27/08/filename。fs目录下按照类型存放文件,媒体类型见上面注释,比如5就是Media_Type_PORTRAIT,是客户端的头像文件。
|
||||
# 如果需要使用nginx添加https支持,请打开下面配置,这样客户端得到的文件地址为 https://example.com/media/fs/5/2021/03/27/08/filename。
|
||||
# 需要nginx把请求从https://example.com/media/fs 转到 http://server.ip:http_port/fs。注意需要带上所有header。
|
||||
# 尽管内置文件存储可以使用,但是我们还是建议使用专业级别的对象存储服务,社区版可以使用七牛,专业版另外支持阿里云和也是私有对象存储。详情请参考 https://docs.wildfirechat.cn/server/oss.html
|
||||
@@ -316,7 +351,7 @@ server.mobile_default_silent_when_pc_online true
|
||||
|
||||
## 客户端是否支持kickoff事件。当客户端被其他端登录踢出时,如果此开关为false时,客户端协议栈上报secret_mismatch。如果此开关为ture时,客户端协议栈上报kicked_off。
|
||||
## 客户端被踢时上报kicked_off是在2021.9.15之后才加上的。如果客户端协议栈全部为此日期之后的版本才可以打开此开关。
|
||||
server.client_support_kickoff_event false
|
||||
server.client_support_kickoff_event true
|
||||
|
||||
#*********************************************************************
|
||||
# Push server configuration
|
||||
@@ -330,6 +365,10 @@ push.android.server.address http://localhost:8085/android/push
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
push.ios.server.address http://localhost:8085/ios/push
|
||||
|
||||
##鸿蒙推送服务器地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
push.harmony.server.address http://localhost:8085/harmony/push
|
||||
|
||||
#*********************************************************************
|
||||
# 监控配置
|
||||
#*********************************************************************
|
||||
@@ -403,7 +442,10 @@ push.ios.server.address http://localhost:8085/ios/push
|
||||
## 内置文本敏感词过滤处理方法,当命中敏感词后,消息会被记录到t_sensitive_messages表中,然后根据type类型做不同的处理,处理方式如下:
|
||||
## 0 发送失败;1 发送成功但消息被服务器直接丢弃;2 命中的敏感词被替换成***然后正常发送;3 正常发送。
|
||||
## 如果开启 message.sensitive.forward.url 配置,命中敏感词的消息还会被回调到这个地址
|
||||
sensitive.filter.type 0
|
||||
sensitive.filter.type 2
|
||||
|
||||
## 敏感词添加或者删除有2种方式,一种是通过Server API进行,这种方式会立即生效。另外一种方法是修改数据库,直接中数据库的t_sensitive_word表中处理
|
||||
## 修改数据库的方法不会立即生效,IM服务会2个小时重新加载一次敏感词。所以如果直接修改敏感词表,需要等2个小时,或者重启才能生效。
|
||||
|
||||
## 如果内置敏感词库无法满足您的需求,可以开发部署独立敏感词审核服务。配置如下地址和消息类型,IM服务会把指定消息类型的消息回调到指定地址,内置的敏感词审核和敏感词转发功能就不再起作用了。
|
||||
## 审核服务返回状态码200表示继续发送,如果需要替换内容,返回状态码200并且内容为替换后的内容。返回403表示不允许发送。其它错误继续发送。
|
||||
|
||||
@@ -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
-1
@@ -5,7 +5,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>1.2.7</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>moquette-broker</artifactId>
|
||||
|
||||
@@ -34,7 +34,9 @@ public class PushMessage {
|
||||
public String voipDeviceToken;
|
||||
public boolean isHiddenDetail;
|
||||
public String language;
|
||||
public boolean republish;
|
||||
public long messageId;
|
||||
public long callStartUid;
|
||||
|
||||
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;
|
||||
@@ -65,6 +67,7 @@ public class PushMessage {
|
||||
this.mentionedType = mentionedType;
|
||||
this.isHiddenDetail = isHiddenDetail;
|
||||
this.language = language;
|
||||
this.republish = messageContentType == 80 || messageContentType == 81;
|
||||
}
|
||||
public PushMessage(String sender, String target, long serverTime, String senderName, int unReceivedMsg, String language, int pushMessageType) {
|
||||
this.sender = sender;
|
||||
|
||||
@@ -24,8 +24,7 @@ import win.liyufan.im.Utility;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static io.moquette.BrokerConstants.PUSH_ANDROID_SERVER_ADDRESS;
|
||||
import static io.moquette.BrokerConstants.PUSH_IOS_SERVER_ADDRESS;
|
||||
import static io.moquette.BrokerConstants.*;
|
||||
import static win.liyufan.im.HttpUtils.HttpPostType.POST_TYPE_Push;
|
||||
|
||||
public class PushServer {
|
||||
@@ -47,6 +46,7 @@ public class PushServer {
|
||||
|
||||
private String androidPushServerUrl;
|
||||
private String iOSPushServerUrl;
|
||||
private String harmonyPushServerUrl;
|
||||
|
||||
private PushServer() {
|
||||
}
|
||||
@@ -59,6 +59,7 @@ public class PushServer {
|
||||
this.sessionsStore = sessionsStore;
|
||||
this.androidPushServerUrl = config.getProperty(PUSH_ANDROID_SERVER_ADDRESS);
|
||||
this.iOSPushServerUrl = config.getProperty(PUSH_IOS_SERVER_ADDRESS);
|
||||
this.harmonyPushServerUrl = config.getProperty(PUSH_HARMONY_SERVER_ADDRESS);
|
||||
}
|
||||
|
||||
public void pushMessage(PushMessage pushMessage, String deviceId, String pushContent) {
|
||||
@@ -106,6 +107,8 @@ public class PushServer {
|
||||
if (session.getPlatform() == ProtoConstants.Platform.Platform_iOS || session.getPlatform() == ProtoConstants.Platform.Platform_iPad) {
|
||||
url = iOSPushServerUrl;
|
||||
pushMessage.voipDeviceToken = session.getVoipDeviceToken();
|
||||
} else if (session.getPlatform() == ProtoConstants.Platform.Platform_Harmony || session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPad) {
|
||||
url = harmonyPushServerUrl;
|
||||
}
|
||||
HttpUtils.httpJsonPost(url, gson.toJson(pushMessage, pushMessage.getClass()), POST_TYPE_Push);
|
||||
} else {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.common.APIPath;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.*;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Route(APIPath.User_Batch_Get_Infos)
|
||||
@HttpMethod("POST")
|
||||
public class GetBatchUserAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputStringList inputUserId = getRequestBody(request.getNettyRequest(), InputStringList.class);
|
||||
if (inputUserId != null && inputUserId.getList() != null && !inputUserId.getList().isEmpty()) {
|
||||
|
||||
OutputUserInfoList res = new OutputUserInfoList();
|
||||
res.userInfos = new ArrayList<>();
|
||||
for (String userId : inputUserId.getList()) {
|
||||
WFCMessage.User user = messagesStore.getUserInfo(userId);
|
||||
if(user == null || StringUtil.isNullOrEmpty(user.getName())) {
|
||||
continue;
|
||||
}
|
||||
InputOutputUserInfo inputOutputUserInfo = InputOutputUserInfo.fromPbUser(user);
|
||||
res.userInfos.add(inputOutputUserInfo);
|
||||
}
|
||||
RestResult result = RestResult.ok(res);
|
||||
setResponseContent(result, response);
|
||||
} else {
|
||||
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ public class GetGroupInfoAction extends AdminAction {
|
||||
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());
|
||||
@@ -61,6 +62,8 @@ public class GetGroupInfoAction extends AdminAction {
|
||||
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());
|
||||
result = RestResult.ok(pojoGroupInfo);
|
||||
}
|
||||
setResponseContent(result, 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);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ public class GetGroupInfoAction extends RobotAction {
|
||||
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());
|
||||
@@ -60,6 +61,8 @@ public class GetGroupInfoAction extends RobotAction {
|
||||
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());
|
||||
result = RestResult.ok(pojoGroupInfo);
|
||||
}
|
||||
setResponseContent(result, response);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -90,6 +90,7 @@ public final class BrokerConstants {
|
||||
|
||||
public static final String PUSH_ANDROID_SERVER_ADDRESS = "push.android.server.address";
|
||||
public static final String PUSH_IOS_SERVER_ADDRESS = "push.ios.server.address";
|
||||
public static final String PUSH_HARMONY_SERVER_ADDRESS = "push.harmony.server.address";
|
||||
|
||||
public static final String MONITOR_Exception_Event_Address = "monitor.exception_event_address";
|
||||
|
||||
@@ -115,6 +116,8 @@ public final class BrokerConstants {
|
||||
public static final String CONNECT_CLIENT_SIGNATURE_LIST = "connect.client_signature_list";
|
||||
public static final String CONNECT_REJECT_EMPTY_SIGNATURE = "connect.reject_empty_signature";
|
||||
|
||||
public static final String ID_USE_UUID = "id.use_uuid";
|
||||
|
||||
public static final String EMBED_DB_PROPERTY_NAME = "embed.db";
|
||||
public static final String DB_AUTO_CLEAN_HISTORY_MESSAGES = "db.auto_clean_history_messages";
|
||||
public static final String H2DB_PATH = "h2db.path";
|
||||
@@ -149,8 +152,10 @@ public final class BrokerConstants {
|
||||
|
||||
public static final String MESSAGE_Disable_Stranger_Chat = "message.disable_stranger_chat";
|
||||
public static final String MESSAGE_Allow_Stranger_Chat_List = "message.allow_stranger_chat_list";
|
||||
public static final String MESSAGE_Allow_Stranger_Line = "message.allow_stranger_line";
|
||||
|
||||
public static final String MESSAGE_Blacklist_Strategy = "message.blacklist.strategy";
|
||||
public static final String MESSAGE_Blacklist_Allow_Send = "message.blacklist.allow_send_to_black";
|
||||
|
||||
public static final String MESSAGE_NO_Forward_Admin_Message = "message.no_forward_admin_message";
|
||||
|
||||
@@ -158,11 +163,20 @@ 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 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";
|
||||
|
||||
|
||||
@@ -173,6 +187,7 @@ public final class BrokerConstants {
|
||||
public static final String FRIEND_Repeat_Request_Duration = "friend.repeat_request_duration";
|
||||
public static final String FRIEND_Reject_Request_Duration = "friend.reject_request_duration";
|
||||
public static final String FRIEND_Request_Expiration_Duration = "friend.request_expiration_duration";
|
||||
public static final String FRIEND_Request_Rate_Limit = "friend.request_rate_limit";
|
||||
public static final String FRIEND_Request_Robot_Auto_Accept = "friend.robot_auto_accept";
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ public class AddFriendHandler extends GroupHandler<WFCMessage.AddFriendRequest>
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.AddFriendRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
long[] head = new long[1];
|
||||
boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;
|
||||
ErrorCode errorCode = m_messagesStore.saveAddFriendRequest(fromUser, request, head, isAdmin);
|
||||
boolean isRobot = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot;
|
||||
ErrorCode errorCode = m_messagesStore.saveAddFriendRequest(fromUser, request, head, isAdmin, isRobot);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
WFCMessage.User user = m_messagesStore.getUserInfo(request.getTargetUid());
|
||||
if (user != null && user.getType() == ProtoConstants.UserType.UserType_Normal) {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class AddGroupMember extends GroupHandler<WFCMessage.AddGroupMemberReques
|
||||
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())).getAddGroupNotifyContent();
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, getMemberIdList(request.getAddedMemberList())).setExtra(request.getExtra()).getAddGroupNotifyContent();
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupReque
|
||||
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
|
||||
} else {
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, groupInfo.getName(), "").getCreateGroupNotifyContent();
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, groupInfo.getName(), "").setExtra(request.getMemberExtra()).getCreateGroupNotifyContent();
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,9 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
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;
|
||||
@@ -69,6 +71,12 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
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)) {
|
||||
@@ -94,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) {
|
||||
@@ -145,7 +156,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
|
||||
if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
if(!m_messagesStore.getBlackListExceptionTypes().contains(message.getContent().getType())) {
|
||||
errorCode = m_messagesStore.isAllowUserMessage(message.getConversation().getTarget(), fromUser);
|
||||
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;
|
||||
@@ -154,11 +165,20 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mBlacklistAllowSend2Black) {
|
||||
errorCode = m_messagesStore.isBlacked(fromUser, message.getConversation().getTarget());
|
||||
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,20 +223,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) {
|
||||
@@ -225,7 +238,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;
|
||||
@@ -242,7 +255,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, mRemoteSensitiveServerUrl, clientID, new HttpUtils.HttpCallback() {
|
||||
@Override
|
||||
public void onSuccess(String content) {
|
||||
if(StringUtil.isNullOrEmpty(content)) {
|
||||
|
||||
@@ -2203,6 +2203,7 @@ public class DatabaseStore {
|
||||
", `_join_type`" +
|
||||
", `_private_chat`" +
|
||||
", `_searchable`" +
|
||||
", _deleted" +
|
||||
" from t_group where `_gid` = ?";
|
||||
|
||||
statement = connection.prepareStatement(sql);
|
||||
@@ -2259,6 +2260,9 @@ public class DatabaseStore {
|
||||
intValue = rs.getInt(index++);
|
||||
builder.setSearchable(intValue);
|
||||
|
||||
intValue = rs.getInt(index++);
|
||||
builder.setDeleted(intValue);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
|
||||
@@ -75,7 +75,7 @@ import static io.moquette.BrokerConstants.*;
|
||||
import static io.moquette.server.Constants.MAX_CHATROOM_MESSAGE_QUEUE;
|
||||
import static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;
|
||||
import static cn.wildfirechat.pojos.MyInfoType.*;
|
||||
import static win.liyufan.im.UserSettingScope.kUserSettingAddFriendNoVerify;
|
||||
import static win.liyufan.im.UserSettingScope.kUserSettingAddFriendStrategy;
|
||||
import static win.liyufan.im.UserSettingScope.kUserSettingPCOnline;
|
||||
|
||||
public class MemoryMessagesStore implements IMessagesStore {
|
||||
@@ -155,6 +155,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
private long mFriendRequestDuration = 7 * 24 * 60 * 60 * 1000;
|
||||
private long mFriendRejectDuration = 30 * 24 * 60 * 60 * 1000;
|
||||
private long mFriendRequestExpiration = 7 * 24 * 60 * 60 * 1000;
|
||||
private RateLimiter mFriendRateLimiter;
|
||||
private boolean mFriendRobotAutoAccept = true;
|
||||
|
||||
private long mPushExpiredTimes = 604800000L;
|
||||
@@ -164,8 +165,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
private boolean mMobileDefaultSilentWhenPCOnline = true;
|
||||
private boolean mDisableStrangerChat = false;
|
||||
private Set<String> mAllowStrangerChatSet = new HashSet<>();
|
||||
private Set<Integer> mAllowStrangerLineSet = new HashSet<>();
|
||||
private boolean mDisableStrangerAddGroup = false;
|
||||
|
||||
private boolean mIDUseUUID = true;
|
||||
|
||||
private Set<String> mClientSignatureSet = new HashSet<>();
|
||||
private boolean mRejectEmptySignature = true;
|
||||
|
||||
@@ -201,8 +205,16 @@ 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 mChannelCallbackWithClientInfo = false;
|
||||
private boolean mChannelCallbackWithSenderInfo = false;
|
||||
private boolean mChannelCallbackWithTargetInfo = false;
|
||||
private boolean mChannelNewCallbackFeature = true;
|
||||
|
||||
private Set<Integer> mUserHideProperties = new HashSet<>();
|
||||
@@ -262,6 +274,18 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
String allowStrangerList = m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Allow_Stranger_Line);
|
||||
if(!StringUtil.isNullOrEmptyAfterTrim(allowStrangerList)) {
|
||||
allowStrangerList = allowStrangerList.replace(",", ",");
|
||||
for (String s : allowStrangerList.split(",")) {
|
||||
mAllowStrangerLineSet.add(Integer.parseInt(s.trim()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
String forcePushTypes = m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Force_Push_Types);
|
||||
if(!StringUtil.isNullOrEmptyAfterTrim(forcePushTypes)) {
|
||||
@@ -342,6 +366,13 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
printMissConfigLog(FRIEND_Request_Expiration_Duration, mFriendRequestExpiration + "");
|
||||
}
|
||||
|
||||
try {
|
||||
int friendRequestRateLimit = Integer.parseInt(m_Server.getConfig().getProperty(FRIEND_Request_Rate_Limit, "0"));
|
||||
if(friendRequestRateLimit > 0) {
|
||||
mFriendRateLimiter = new RateLimiter(86400, friendRequestRateLimit);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
try {
|
||||
mFriendRobotAutoAccept = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Request_Robot_Auto_Accept, "true"));
|
||||
@@ -585,9 +616,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"));
|
||||
@@ -597,23 +632,38 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
try {
|
||||
mRobotCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Client_Info, "false"));
|
||||
} catch (Exception e) {
|
||||
} 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 {
|
||||
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);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
mIDUseUUID = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ID_USE_UUID, "false"));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void printMissConfigLog(String config, String defaultValue) {
|
||||
@@ -718,7 +768,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
pullType = ProtoConstants.PullType.Pull_Normal;
|
||||
} else if (type == ProtoConstants.ConversationType.ConversationType_ChatRoom) {
|
||||
boolean isDirect = !StringUtil.isNullOrEmpty(message.getToUser());
|
||||
boolean isDirect = !StringUtil.isNullOrEmpty(message.getToUser()) || !message.getToList().isEmpty();
|
||||
Collection<UserClientEntry> entries = getChatroomMembers(message.getConversation().getTarget());
|
||||
for (UserClientEntry entry : entries) {
|
||||
if (isDirect) {
|
||||
@@ -726,6 +776,9 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
notifyReceivers.add(message.getToUser());
|
||||
break;
|
||||
}
|
||||
if (message.getToList().contains(entry.userId)) {
|
||||
notifyReceivers.add(entry.userId);
|
||||
}
|
||||
} else {
|
||||
notifyReceivers.add(entry.userId);
|
||||
}
|
||||
@@ -869,11 +922,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();
|
||||
|
||||
@@ -902,6 +957,8 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
if (size >= 512 * 1024) { //3M
|
||||
if(builder.getMessageCount() == 0){
|
||||
builder.addMessage(bundle.getMessage());
|
||||
} else {
|
||||
current = previousCurrent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2235,15 +2292,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) {
|
||||
@@ -2409,7 +2480,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;
|
||||
@@ -2421,7 +2492,8 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
WFCMessage.GroupInfo groupInfo = groupMap.get(message.getConversation().getTarget());
|
||||
if (groupInfo == null) {
|
||||
return ErrorCode.ERROR_CODE_RECALL_TIME_EXPIRED;
|
||||
LOG.info("recall message failure, group {} not exist", message.getConversation().getTarget());
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
if (operatorId.equals(groupInfo.getOwner())) {
|
||||
if(operatorId.equals(message.getFromUser())) {
|
||||
@@ -2858,7 +2930,9 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
IMap<String, Integer> mUserMap = hzInstance.getMap(USER_STATUS);
|
||||
ArrayList<InputOutputUserBlockStatus> out = new ArrayList<>();
|
||||
for (Map.Entry<String, Integer> entry : mUserMap.entrySet()) {
|
||||
out.add(new InputOutputUserBlockStatus(entry.getKey(), entry.getValue()));
|
||||
if(entry.getValue() > 0) {
|
||||
out.add(new InputOutputUserBlockStatus(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -3175,7 +3249,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode isAllowUserMessage(String targetUser, String fromUser) {
|
||||
public ErrorCode isAllowUserMessage(String targetUser, String fromUser, int line) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);
|
||||
|
||||
@@ -3202,7 +3276,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
if (mDisableStrangerChat) {
|
||||
//在禁止私聊时,是否是允许私聊的用户id
|
||||
if(mAllowStrangerChatSet.contains(targetUser) || mAllowStrangerChatSet.contains(fromUser)) {
|
||||
if(mAllowStrangerChatSet.contains(targetUser) || mAllowStrangerChatSet.contains(fromUser) || mAllowStrangerLineSet.contains(line)) {
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -3226,6 +3300,30 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode isBlacked(String fromUser, String userId) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);
|
||||
|
||||
Collection<FriendData> friendDatas = friendsMap.get(fromUser);
|
||||
|
||||
if (friendDatas == null || friendDatas.size() == 0) {
|
||||
friendDatas = loadFriend(friendsMap, fromUser);
|
||||
}
|
||||
|
||||
for (FriendData friendData : friendDatas) {
|
||||
if (friendData.getFriendUid().equals(userId)) {
|
||||
if (friendData.getBlacked() == 1) {
|
||||
return ErrorCode.ERROR_CODE_IN_BLACK_LIST;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
synchronized Collection<FriendData> loadFriend(MultiMap<String, FriendData> friendsMap, String userId) {
|
||||
Collection<FriendData> friends = databaseStore.getPersistFriends(userId);
|
||||
if (friends != null) {
|
||||
@@ -3343,16 +3441,28 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin) {
|
||||
public ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin, boolean isRobot) {
|
||||
if (!isAdmin && mDisableFriendRequest) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
if(!isRobot && !isAdmin && mFriendRateLimiter != null) {
|
||||
if(!mFriendRateLimiter.isGranted(userId)) {
|
||||
LOG.error("User {} request add friend over frequency", userId);
|
||||
return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
|
||||
}
|
||||
}
|
||||
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);
|
||||
|
||||
WFCMessage.UserSettingEntry userSettingData = getUserSetting(request.getTargetUid(), kUserSettingAddFriendNoVerify, "");
|
||||
WFCMessage.UserSettingEntry userSettingData = getUserSetting(request.getTargetUid(), kUserSettingAddFriendStrategy, "");
|
||||
boolean noVerify = userSettingData != null && "1".equals(userSettingData.getValue());
|
||||
boolean noAllow = userSettingData != null && "2".equals(userSettingData.getValue());
|
||||
|
||||
if(noAllow) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
Collection<WFCMessage.FriendRequest> requests = requestMap.get(userId);
|
||||
if (requests == null || requests.size() == 0) {
|
||||
@@ -4640,16 +4750,46 @@ 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 isChannelCallbackWithClientInfo() {
|
||||
return mChannelCallbackWithClientInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChannelCallbackWithSenderInfo() {
|
||||
return mChannelCallbackWithSenderInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChannelCallbackWithTargetInfo() {
|
||||
return mChannelCallbackWithTargetInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChannelNewCallbackFeature() {
|
||||
return mChannelNewCallbackFeature;
|
||||
@@ -4788,9 +4928,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
@Override
|
||||
public String getShortUUID(){
|
||||
int id = databaseStore.getGeneratedId();
|
||||
if (id > 0) {
|
||||
return IDUtils.toUid(id);
|
||||
if(!mIDUseUUID) {
|
||||
int id = databaseStore.getGeneratedId();
|
||||
if (id > 0) {
|
||||
return IDUtils.toUid(id);
|
||||
}
|
||||
}
|
||||
return UUIDGenerator.getUUID();
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ public class Server {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(instance::stopServer));
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(httpServer::shutdown));
|
||||
|
||||
System.out.println("Wildfire IM server start success...");
|
||||
System.out.println("Wildfire IM server start success.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -179,13 +179,14 @@ public interface IMessagesStore {
|
||||
void clearUserFriend(String userId);
|
||||
List<WFCMessage.FriendRequest> getFriendRequestList(String userId, long version);
|
||||
|
||||
ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin);
|
||||
ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin, boolean isRobot);
|
||||
ErrorCode handleFriendRequest(String userId, WFCMessage.HandleFriendRequest request, WFCMessage.Message.Builder msgBuilder, long[] heads, boolean isAdmin);
|
||||
ErrorCode deleteFriend(String userId, String friendUid, long[] head);
|
||||
ErrorCode blackUserRequest(String fromUser, String targetUserId, int status, long[] head);
|
||||
FriendData getFriendData(String fromUser, String targetUserId);
|
||||
ErrorCode SyncFriendRequestUnread(String userId, long unreadDt, long[] head);
|
||||
ErrorCode isAllowUserMessage(String fromUser, String userId);
|
||||
ErrorCode isAllowUserMessage(String fromUser, String userId, int line);
|
||||
ErrorCode isBlacked(String fromUser, String userId);
|
||||
ErrorCode setFriendAliasRequest(String fromUser, String targetUserId, String alias, long[] head);
|
||||
ErrorCode setFriendExtraRequest(String fromUser, String targetUserId, String extra, long[] head);
|
||||
|
||||
@@ -241,8 +242,16 @@ public interface IMessagesStore {
|
||||
int getGroupForbiddenClientOperation();
|
||||
|
||||
boolean isForwardMessageWithClientInfo();
|
||||
boolean isForwardMessageWithSenderInfo();
|
||||
boolean isForwardMessageWithTargetInfo();
|
||||
|
||||
boolean isRobotCallbackWithClientInfo();
|
||||
boolean isRobotCallbackWithSenderInfo();
|
||||
boolean isRobotCallbackWithTargetInfo();
|
||||
|
||||
boolean isChannelCallbackWithClientInfo();
|
||||
boolean isChannelCallbackWithSenderInfo();
|
||||
boolean isChannelCallbackWithTargetInfo();
|
||||
boolean isChannelNewCallbackFeature();
|
||||
|
||||
boolean isRobotAutoAcceptFriendRequest();
|
||||
|
||||
@@ -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;
|
||||
@@ -283,7 +285,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();
|
||||
@@ -398,7 +400,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,7 +423,7 @@ 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, targetSession.getUnReceivedMsgs(), curMentionType, isHiddenDetail, targetSession.getLanguage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -451,6 +453,7 @@ public class MessagesPublisher {
|
||||
WFCMessage.Message message = m_messagesStore.getMessage(messageHead);
|
||||
|
||||
if (message != null) {
|
||||
message = message.toBuilder().setMessageId(0).build();
|
||||
for (String user : receivers) {
|
||||
Collection<Session> sessions = m_sessionsStore.sessionForUser(user);
|
||||
|
||||
@@ -485,19 +488,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);
|
||||
@@ -529,9 +523,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())) {
|
||||
@@ -544,7 +538,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())) {
|
||||
@@ -666,7 +660,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;
|
||||
@@ -677,18 +671,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);
|
||||
@@ -732,18 +718,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);
|
||||
@@ -751,9 +811,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,12 +37,13 @@ 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) {
|
||||
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;
|
||||
PushServer.getServer().pushMessage(pushMessage, deviceId, pushContent);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public class HttpUtils {
|
||||
if(httpCallback != null) {
|
||||
int code = response.code();
|
||||
if(code == 200) {
|
||||
if(response.body() != null && response.body().contentLength() > 0) {
|
||||
if(response.body() != null) {
|
||||
httpCallback.onSuccess(response.body().string());
|
||||
} else {
|
||||
httpCallback.onSuccess(null);
|
||||
|
||||
@@ -20,5 +20,5 @@ public interface UserSettingScope {
|
||||
int kUserSettingPttSilent = 25;
|
||||
int kUserSettingGroupRemark = 26;
|
||||
int kUserSettingPrivacySearchable = 27;
|
||||
int kUserSettingAddFriendNoVerify = 28;
|
||||
int kUserSettingAddFriendStrategy = 28;
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>1.2.7</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -61,6 +61,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";
|
||||
@@ -71,6 +73,8 @@ public interface APIPath {
|
||||
String Msg_Multicast = "/admin/message/multicast";
|
||||
String Msg_RecallBroadCast = "/admin/message/recall_broadcast";
|
||||
String Msg_RecallMultiCast = "/admin/message/recall_multicast";
|
||||
String Msg_DeleteBroadCast = "/admin/message/delete_broadcast";
|
||||
String Msg_DeleteMultiCast = "/admin/message/delete_multicast";
|
||||
String Msg_ConvRead = "/admin/message/conv_read";
|
||||
String Msg_Delivery = "/admin/message/delivery";
|
||||
String Conversation_Delete = "/admin/conversation/delete";
|
||||
@@ -155,5 +159,17 @@ public interface APIPath {
|
||||
String Robot_Group_Transfer = "/robot/group/transfer";
|
||||
String Robot_Group_Set_Manager = "/robot/group/manager/set";
|
||||
|
||||
String Robot_Moments_Post_Feed = "/robot/moments/feed/post";
|
||||
String Robot_Moments_Pull_Feeds = "/robot/moments/feed/pull";
|
||||
String Robot_Moments_Update_Feed = "/robot/moments/feed/update";
|
||||
String Robot_Moments_Post_Comment = "/robot/moments/comment/post";
|
||||
String Robot_Moments_Pull_Comment = "/robot/moments/comment/pull";
|
||||
String Robot_Moments_Fetch_Feed = "/robot/moments/feed/pull_one";
|
||||
String Robot_Moments_Fetch_Profiles = "/robot/moments/profiles/pull";
|
||||
String Robot_Moments_Recall_Comment = "/robot/moments/comment/recall";
|
||||
String Robot_Moments_Recall_Feed = "/robot/moments/feed/recall";
|
||||
String Robot_Moments_Update_Profiles_List_Value = "/robot/moments/profiles/list/push";
|
||||
String Robot_Moments_Update_Profiles_Value = "/robot/moments/profiles/value/push";
|
||||
|
||||
String Robot_Conference_Request = "/robot/conference/request";
|
||||
}
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
|
||||
abstract public class MediaMessageContentBuilder extends MessageContentBuilder{
|
||||
private String remoteMediaUrl;
|
||||
|
||||
public MediaMessageContentBuilder remoteMediaUrl(String remoteMediaUrl) {
|
||||
this.remoteMediaUrl = remoteMediaUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MessagePayload encodeBase() {
|
||||
MessagePayload payload = super.encodeBase();
|
||||
payload.setRemoteMediaUrl(remoteMediaUrl);
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MessageContentBuilder {
|
||||
private int mentionedType;
|
||||
private List<String> mentionedTargets;
|
||||
private String extra;
|
||||
public MessageContentBuilder mentionedType(int mentionedType) {
|
||||
this.mentionedType = mentionedType;
|
||||
return this;
|
||||
}
|
||||
public MessageContentBuilder mentionedTargets(List<String> mentionedTargets) {
|
||||
this.mentionedTargets = mentionedTargets;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MessageContentBuilder extra(String extra) {
|
||||
this.extra = extra;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected MessagePayload encodeBase() {
|
||||
MessagePayload payload = new MessagePayload();
|
||||
payload.setMentionedType(mentionedType);
|
||||
payload.setMentionedTarget(mentionedTargets);
|
||||
payload.setExtra(extra);
|
||||
return payload;
|
||||
}
|
||||
abstract public MessagePayload build();
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class SoundMessageContentBuilder extends MediaMessageContentBuilder {
|
||||
private int duration;
|
||||
public static SoundMessageContentBuilder newBuilder(int duration) {
|
||||
SoundMessageContentBuilder builder = new SoundMessageContentBuilder();
|
||||
builder.duration = duration;
|
||||
return builder;
|
||||
}
|
||||
@Override
|
||||
public MessagePayload build() {
|
||||
MessagePayload payload = encodeBase();
|
||||
payload.setType(ProtoConstants.ContentType.Voice);
|
||||
payload.setMediaType(ProtoConstants.MessageMediaType.VOICE);
|
||||
payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("duration", duration);
|
||||
payload.setContent(jsonObject.toJSONString());
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class StreamingTextMessageContentBuilder extends MessageContentBuilder{
|
||||
private String text;
|
||||
private String streamId;
|
||||
private boolean generating;
|
||||
public static StreamingTextMessageContentBuilder newBuilder(String streamId) {
|
||||
StreamingTextMessageContentBuilder builder = new StreamingTextMessageContentBuilder();
|
||||
builder.generating = false;
|
||||
builder.streamId = streamId;
|
||||
return builder;
|
||||
}
|
||||
public StreamingTextMessageContentBuilder text(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamingTextMessageContentBuilder generating(boolean generating) {
|
||||
this.generating = generating;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload build() {
|
||||
MessagePayload payload = encodeBase();
|
||||
payload.setSearchableContent(text);
|
||||
payload.setContent(streamId);
|
||||
if(generating) {
|
||||
//正在生成消息的类型是14,存储标记位为透传为4。
|
||||
payload.setType(14);
|
||||
payload.setPersistFlag(4);
|
||||
} else {
|
||||
//已经生成消息的类型是15,存储标记位为透传为3。
|
||||
payload.setType(15);
|
||||
payload.setPersistFlag(3);
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class TextMessageContentBuilder extends MessageContentBuilder{
|
||||
private String text;
|
||||
public static TextMessageContentBuilder newBuilder(String text) {
|
||||
TextMessageContentBuilder builder = new TextMessageContentBuilder();
|
||||
builder.text = text;
|
||||
return builder;
|
||||
}
|
||||
@Override
|
||||
public MessagePayload build() {
|
||||
MessagePayload payload = encodeBase();
|
||||
payload.setType(ProtoConstants.ContentType.Text);
|
||||
payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count);
|
||||
payload.setSearchableContent(text);
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -32,6 +33,8 @@ public class GroupNotificationBinaryContent {
|
||||
//value2(member or something)
|
||||
private String m;
|
||||
|
||||
private String extra;
|
||||
|
||||
public GroupNotificationBinaryContent() {
|
||||
}
|
||||
|
||||
@@ -89,8 +92,18 @@ public class GroupNotificationBinaryContent {
|
||||
this.ms = ms;
|
||||
}
|
||||
|
||||
public GroupNotificationBinaryContent setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getGroupNotifyContent(int groupContentType) {
|
||||
return WFCMessage.MessageContent.newBuilder().setType(groupContentType).setData(ByteString.copyFromUtf8(new GsonBuilder().disableHtmlEscaping().create().toJson(this))).build();
|
||||
WFCMessage.MessageContent.Builder builder = WFCMessage.MessageContent.newBuilder().setType(groupContentType).setData(ByteString.copyFromUtf8(new GsonBuilder().disableHtmlEscaping().create().toJson(this)));
|
||||
if(!StringUtil.isNullOrEmpty(extra)) {
|
||||
builder.setExtra(extra);
|
||||
}
|
||||
return builder.build();
|
||||
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getAddGroupNotifyContent() {
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.List;
|
||||
public class InputAddGroupMember extends InputGroupBase {
|
||||
private String group_id;
|
||||
private List<PojoGroupMember> members;
|
||||
private String member_extra;
|
||||
|
||||
public String getGroup_id() {
|
||||
return group_id;
|
||||
@@ -34,6 +35,14 @@ public class InputAddGroupMember extends InputGroupBase {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
public String getMember_extra() {
|
||||
return member_extra;
|
||||
}
|
||||
|
||||
public void setMemberExtra(String extra) {
|
||||
this.member_extra = extra;
|
||||
}
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
}
|
||||
@@ -41,6 +50,9 @@ public class InputAddGroupMember extends InputGroupBase {
|
||||
public WFCMessage.AddGroupMemberRequest toProtoGroupRequest() {
|
||||
WFCMessage.AddGroupMemberRequest.Builder addGroupBuilder = WFCMessage.AddGroupMemberRequest.newBuilder();
|
||||
addGroupBuilder.setGroupId(group_id);
|
||||
if(!StringUtil.isNullOrEmpty(member_extra)) {
|
||||
addGroupBuilder.setExtra(member_extra);
|
||||
}
|
||||
for (PojoGroupMember pojoGroupMember : getMembers()) {
|
||||
WFCMessage.GroupMember.Builder groupMemberBuilder = WFCMessage.GroupMember.newBuilder().setMemberId(pojoGroupMember.getMember_id());
|
||||
if (!StringUtil.isNullOrEmpty(pojoGroupMember.getAlias())) {
|
||||
|
||||
@@ -16,9 +16,10 @@ import java.util.List;
|
||||
|
||||
public class InputCreateGroup extends InputGroupBase {
|
||||
private PojoGroup group;
|
||||
private String member_extra;
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
return !StringUtil.isNullOrEmpty(operator) && group != null;
|
||||
}
|
||||
|
||||
public WFCMessage.CreateGroupRequest toProtoGroupRequest() {
|
||||
@@ -87,6 +88,9 @@ public class InputCreateGroup extends InputGroupBase {
|
||||
|
||||
WFCMessage.CreateGroupRequest.Builder createGroupReqBuilder = WFCMessage.CreateGroupRequest.newBuilder();
|
||||
createGroupReqBuilder.setGroup(groupBuilder);
|
||||
if(!StringUtil.isNullOrEmpty(member_extra)) {
|
||||
createGroupReqBuilder.setMemberExtra(member_extra);
|
||||
}
|
||||
if (to_lines != null) {
|
||||
for (Integer line : to_lines
|
||||
) {
|
||||
@@ -107,4 +111,12 @@ public class InputCreateGroup extends InputGroupBase {
|
||||
public void setGroup(PojoGroup group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public String getMember_extra() {
|
||||
return member_extra;
|
||||
}
|
||||
|
||||
public void setMember_extra(String member_extra) {
|
||||
this.member_extra = member_extra;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.wildfirechat.pojos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputStringList {
|
||||
private List<String> list;
|
||||
|
||||
public InputStringList() {
|
||||
}
|
||||
|
||||
public InputStringList(List<String> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public List<String> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(List<String> list) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
@@ -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,38 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CommentMsgPojo {
|
||||
//commentId;
|
||||
public long commentId;
|
||||
|
||||
//sender;
|
||||
public String sender;
|
||||
|
||||
//timestamp
|
||||
public long serverTime;
|
||||
|
||||
//feedId
|
||||
public long feedId;
|
||||
|
||||
//type
|
||||
public int type;
|
||||
|
||||
//content
|
||||
public String text;
|
||||
|
||||
//to replyTo
|
||||
public String replyTo;
|
||||
|
||||
//extra
|
||||
public String extra;
|
||||
|
||||
public int ftype;
|
||||
|
||||
public String fcontent;
|
||||
|
||||
public String fsender;
|
||||
|
||||
public List<MediaEntry> fmedias;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class CommentPojo {
|
||||
//commentId;
|
||||
public long commentId;
|
||||
|
||||
//replyId;
|
||||
public long replyId;
|
||||
|
||||
//sender;
|
||||
public String sender;
|
||||
|
||||
//timestamp
|
||||
public long timestamp;
|
||||
|
||||
//feedId
|
||||
public long feedId;
|
||||
|
||||
//type
|
||||
public int type;
|
||||
|
||||
//content
|
||||
public String text;
|
||||
|
||||
//to replyTo
|
||||
public String replyTo;
|
||||
|
||||
//extra
|
||||
public String extra;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FeedPojo {
|
||||
//feedid
|
||||
public long feedId;
|
||||
|
||||
//sender
|
||||
public String sender;
|
||||
|
||||
//timestamp
|
||||
public long timestamp;
|
||||
|
||||
//type
|
||||
public int type;
|
||||
|
||||
//content
|
||||
public String text;
|
||||
|
||||
//media urls
|
||||
public List<MediaEntry> medias;
|
||||
|
||||
//to users
|
||||
public List<String> to;
|
||||
|
||||
//excloud users
|
||||
public List<String> ex;
|
||||
|
||||
//mentioned users
|
||||
public List<String> mu;
|
||||
|
||||
//extra
|
||||
public String extra;
|
||||
|
||||
public List<CommentPojo> comments;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FeedsPojo {
|
||||
public List<FeedPojo> feeds;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class IdPojo {
|
||||
//feedid
|
||||
public long id;
|
||||
|
||||
//feedid
|
||||
public long id2;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class MediaEntry {
|
||||
public String m;
|
||||
public String t;
|
||||
public int w;
|
||||
public int h;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MomentProfilePojo {
|
||||
public String bgUrl;
|
||||
public List<String> blackList;
|
||||
public List<String> blockList;
|
||||
//stranger visiable count
|
||||
public int svc;
|
||||
public int visiableScope;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class PostFeedResult {
|
||||
public long id;
|
||||
public long timestamp;
|
||||
|
||||
public PostFeedResult(long id, long timestamp) {
|
||||
this.id = id;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PullCommentsRequestPojo {
|
||||
public static class IdPair {
|
||||
public long fid;
|
||||
public long cid;
|
||||
}
|
||||
public List<IdPair> ids;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class PullFeedRequestPojo {
|
||||
//feedid
|
||||
public long feedId;
|
||||
public int count;
|
||||
public String user;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class PullOneFeedRequestPojo {
|
||||
public long feedId;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class PullProfileRequestPojo {
|
||||
//userId
|
||||
public String u;
|
||||
|
||||
//update date
|
||||
public long d;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PushProfileListRequestPojo {
|
||||
//block or black
|
||||
public boolean b;
|
||||
|
||||
//add user list
|
||||
public List<String> al;
|
||||
|
||||
//remove user list
|
||||
public List<String> rl;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.wildfirechat.pojos.moments;
|
||||
|
||||
public class PushProfileValueRequestPojo {
|
||||
/*
|
||||
WFMUpdateUserProfileType_BackgroudUrl,
|
||||
WFMUpdateUserProfileType_StrangerVisiableCount,
|
||||
WFMUpdateUserProfileType_VisiableScope
|
||||
*/
|
||||
public int t;
|
||||
|
||||
//string value depends on t
|
||||
public String v;
|
||||
|
||||
//int value depends on t
|
||||
public int i;
|
||||
}
|
||||
@@ -97,6 +97,10 @@ public class ProtoConstants {
|
||||
int Composited = 11;
|
||||
int Rich_Notification = 12;
|
||||
int Articles = 13;
|
||||
int StreamingText_Generationg = 14;
|
||||
int StreamingText_Generated = 15;
|
||||
int Not_Delivered = 16;
|
||||
int Ptt_Voice = 23;
|
||||
int Enter_Channel_Chat = 71;
|
||||
int Leave_Channel_Chat = 72;
|
||||
int Recall = 80;
|
||||
@@ -126,6 +130,12 @@ public class ProtoConstants {
|
||||
int Quit_Group_Visible_Notification = 121;
|
||||
int Modify_Group_Extra = 122;
|
||||
int Modify_Group_Member_Extra = 123;
|
||||
|
||||
int Call_Start = 400;
|
||||
int Call_Accept = 401;
|
||||
int Call_End = 402;
|
||||
int Call_Add_Participant = 406;
|
||||
int Call_Multi_Call_Ongoing = 416;
|
||||
}
|
||||
|
||||
public interface MessagePersistFlag {
|
||||
@@ -337,6 +347,25 @@ public class ProtoConstants {
|
||||
int Forbidden_Mute_Group_Member = 0x800;
|
||||
}
|
||||
|
||||
public interface MomentsContentType {
|
||||
int Moments_Content_Text_Type = 0;
|
||||
int Moments_Content_Image_Type = 1;
|
||||
int Moments_Content_Video_Type = 2;
|
||||
int Moments_Content_Link_Type = 3;
|
||||
}
|
||||
|
||||
public interface MomentsCommentType {
|
||||
int Moments_Comment_Text_Type = 0;
|
||||
int Moments_Comment_Thumbup_Type = 1;
|
||||
}
|
||||
|
||||
public interface MomentsVisibleScope {
|
||||
int Moments_VisibleScope_NoLimit = 0;
|
||||
int Moments_VisibleScope_3Days = 1;
|
||||
int Moments_VisibleScope_1Month = 2;
|
||||
int Moments_VisibleScope_6Months = 3;
|
||||
};
|
||||
|
||||
public static final int MESSAGE_CONTENT_TYPE_CREATE_GROUP = 104;
|
||||
public static final int MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER = 105;
|
||||
public static final int MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER = 106;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<!--<relativePath>../pom.xml</relativePath>-->
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>1.2.7</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>distribution</artifactId>
|
||||
|
||||
@@ -66,6 +66,10 @@ token.key testim
|
||||
##是否使用AES256加密。默认客户端和服务器都是AES128加密,如果需要开启AES256,需要客户端和IM服务同时开通。
|
||||
#encrypt.use_aes256 true
|
||||
|
||||
##当创建一个对象时(用户,群组,频道,机器人等),如果没有传入ID,野火会为这个对象生成一个ID。如果id.use_uuid为true,会使用uuid作为对象ID,否则会使用野火短ID,默认为false。
|
||||
## 短ID有个很大的风险是容易被人穷举进行攻击。建议用UUID。
|
||||
id.use_uuid true
|
||||
|
||||
##首次登录,是否接收之前的历史消息。
|
||||
##0 不接收历史消息,只接收${message.compensate_time_limit}毫秒以内的消息,由于服务器没有保存已经收取记录,所以如果有超过${message.compensate_time_limit}毫秒之前未收取的消息也不会收取下拉;
|
||||
##1接收,会接收 message.max_queue 配置的条数的历史消息
|
||||
@@ -89,6 +93,9 @@ message.disable_stranger_chat false
|
||||
##当禁止陌生人聊天时,允许聊天的用户id,比如管理员或者文件传输助手等。用户id以英文逗号分割。
|
||||
message.allow_stranger_chat_list admin,FireRobot,wfc_file_transfer
|
||||
|
||||
##当禁止陌生人聊天时,允许聊天的线路。
|
||||
#message.allow_stranger_line 100,101
|
||||
|
||||
##黑名单策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃
|
||||
message.blacklist.strategy 0
|
||||
|
||||
@@ -140,12 +147,33 @@ 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
|
||||
|
||||
## 频道回调信息是否带上用户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
|
||||
@@ -171,6 +199,9 @@ friend.reject_request_duration 2592000000
|
||||
##好友请求过期时间,单位是毫秒,默认是7天,0为无限长期限。
|
||||
friend.request_expiration_duration 604800000
|
||||
|
||||
##好友请求限制频率,一个用户24小时之内允许请求好友的次数,默认不限频。
|
||||
#friend.request_rate_limit 30
|
||||
|
||||
##请求添加机器人为好友时,机器人是否自动接受,默认为true
|
||||
friend.robot_auto_accept true
|
||||
|
||||
@@ -214,7 +245,7 @@ group.visible_quit_or_kickoff_notification 0
|
||||
group.disable_stranger_invite false
|
||||
|
||||
## 群组信息是否标记删除
|
||||
group.enable_mark_deletion false
|
||||
group.enable_mark_deletion true
|
||||
|
||||
## 隐藏用户信息属性类型,2是性别,3是电话号码,4是邮箱,5是地址,6是公司信息,7是社交账号,8是Extra信息。当需要隐藏多个时以英文逗号分开;
|
||||
## 本配置是为了提高安全性,避免把对应信息同步到客户端,这样就能防止程序被破解从而拿到用户关键信息。仅对客户端有效,server api不受影响。
|
||||
@@ -250,15 +281,6 @@ client.request_rate_limit 100
|
||||
##关于对象存储的详细信息请参考:https://docs.wildfirechat.cn/server/oss.html
|
||||
media.server.use_qiniu 0
|
||||
|
||||
##媒体类型分类
|
||||
#Media_Type_GENERAL = 0,
|
||||
#Media_Type_IMAGE = 1,
|
||||
#Media_Type_VOICE = 2,
|
||||
#Media_Type_VIDEO = 3,
|
||||
#Media_Type_FILE = 4,
|
||||
#Media_Type_PORTRAIT = 5,
|
||||
#Media_Type_FAVORITE = 6
|
||||
|
||||
# qiniu media server configuration
|
||||
## 上传地址,不同的区域,上传地址也不同,请注意现在正确的地址
|
||||
qiniu.server_url http://up.qbox.me
|
||||
@@ -284,11 +306,21 @@ qiniu.bucket_portrait_domain http://cdn2.wildfirechat.cn
|
||||
qiniu.bucket_favorite_name storage
|
||||
qiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn
|
||||
|
||||
##媒体类型分类
|
||||
#Media_Type_GENERAL = 0,
|
||||
#Media_Type_IMAGE = 1,
|
||||
#Media_Type_VOICE = 2,
|
||||
#Media_Type_VIDEO = 3,
|
||||
#Media_Type_FILE = 4,
|
||||
#Media_Type_PORTRAIT = 5,
|
||||
#Media_Type_FAVORITE = 6,
|
||||
#Media_Type_STICKER = 7,
|
||||
#Media_Type_MOMENTS = 8
|
||||
|
||||
# local media server configuration
|
||||
# 本地媒体服务器配置。
|
||||
local.media.storage.root ./media
|
||||
# 如果使用内置文件存储,文件上传后地址默认为 http://server.ip:http_port/fs/5/2021/03/27/08/filename。
|
||||
local.media.storage.root media
|
||||
# 如果使用内置文件存储,文件上传后地址默认为 http://server.ip:http_port/fs/5/2021/03/27/08/filename。fs目录下按照类型存放文件,媒体类型见上面注释,比如5就是Media_Type_PORTRAIT,是客户端的头像文件。
|
||||
# 如果需要使用nginx添加https支持,请打开下面配置,这样客户端得到的文件地址为 https://example.com/media/fs/5/2021/03/27/08/filename。
|
||||
# 需要nginx把请求从https://example.com/media/fs 转到 http://server.ip:http_port/fs。注意需要带上所有header。
|
||||
# 尽管内置文件存储可以使用,但是我们还是建议使用专业级别的对象存储服务,社区版可以使用七牛,专业版另外支持阿里云和也是私有对象存储。详情请参考 https://docs.wildfirechat.cn/server/oss.html
|
||||
@@ -314,7 +346,7 @@ server.mobile_default_silent_when_pc_online true
|
||||
|
||||
## 客户端是否支持kickoff事件。当客户端被其他端登录踢出时,如果此开关为false时,客户端协议栈上报secret_mismatch。如果此开关为ture时,客户端协议栈上报kicked_off。
|
||||
## 客户端被踢时上报kicked_off是在2021.9.15之后才加上的。如果客户端协议栈全部为此日期之后的版本才可以打开此开关。
|
||||
server.client_support_kickoff_event false
|
||||
server.client_support_kickoff_event true
|
||||
|
||||
#*********************************************************************
|
||||
# Push server configuration
|
||||
@@ -328,6 +360,10 @@ push.android.server.address http://localhost:8085/android/push
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
push.ios.server.address http://localhost:8085/ios/push
|
||||
|
||||
##鸿蒙推送服务器地址
|
||||
##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!
|
||||
push.harmony.server.address http://localhost:8085/harmony/push
|
||||
|
||||
#*********************************************************************
|
||||
# 监控配置
|
||||
#*********************************************************************
|
||||
@@ -411,7 +447,10 @@ push.ios.server.address http://localhost:8085/ios/push
|
||||
## 内置文本敏感词过滤处理方法,当命中敏感词后,消息会被记录到t_sensitive_messages表中,然后根据type类型做不同的处理,处理方式如下:
|
||||
## 0 发送失败;1 发送成功但消息被服务器直接丢弃;2 命中的敏感词被替换成***然后正常发送;3 正常发送。
|
||||
## 如果开启 message.sensitive.forward.url 配置,命中敏感词的消息还会被回调到这个地址
|
||||
sensitive.filter.type 0
|
||||
sensitive.filter.type 2
|
||||
|
||||
## 敏感词添加或者删除有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"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<version>1.2.7</version>
|
||||
<version>1.3.5</version>
|
||||
<name>Wildfire Chat</name>
|
||||
<description>Wildfire Chat Server</description>
|
||||
<inceptionYear>2019</inceptionYear>
|
||||
|
||||
@@ -12,6 +12,62 @@
|
||||
|
||||
# 更新记录
|
||||
|
||||
--------------
|
||||
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. 机器人Server SDK添加朋友圈相关接口。
|
||||
2. Server API添加批量获取用户接口。
|
||||
3. 解决聊天室定向消息无效的问题。
|
||||
4. 添加配置,可以在禁止私聊时添加例外聊天线路。
|
||||
|
||||
--------------
|
||||
Release note 1.3.1:
|
||||
1. 透传消息去掉消息ID,减少消息传输大小。
|
||||
2. 修改添加好友策略,可以设置禁止加自己好友。
|
||||
3. Server API创建群组时,检查是否设置operator。
|
||||
4. SDK添加删除广播和组播消息接口
|
||||
|
||||
--------------
|
||||
Release note 1.3.0:
|
||||
1. 推送信息中添加republish参数,用于标识消息是重新发布的。
|
||||
2. 添加好友请求限频功能,在IM服务配置中可以配置每天限制添加的好友数。
|
||||
3. 添加配置,是否允许用户发送消息给被拉黑的用户。
|
||||
4. 添加鸿蒙回调地址。
|
||||
5. 创建群组或者添加群组成员时,群组成员的Extra会放到通知消息的extra中,这样便于业务处理通知消息。
|
||||
|
||||
--------------
|
||||
Release note 1.2.9:
|
||||
1. 解决server api获取群组信息不全的问题。
|
||||
2. 添加配置使用uuid作为用户群组等ID。
|
||||
|
||||
--------------
|
||||
Release note 1.2.8:
|
||||
1. server api获取被封禁用户时,过滤掉正常用户。
|
||||
2. 解决群组标记删除错误。
|
||||
3. SDK中添加发送消息的示例。
|
||||
4. 群解散后撤回群中的消息应该失败。
|
||||
5. 解决某些时候http请求返回信息无法读取问题。
|
||||
|
||||
--------------
|
||||
Release note 1.2.7:
|
||||
1. 解决搜索频道时某些类型的频道无法被搜索的问题。
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>1.2.7</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ 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);
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
package cn.wildfirechat.sdk;
|
||||
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.*;
|
||||
import cn.wildfirechat.sdk.model.IMResult;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 生成测试数据。本应用生成以下数据:
|
||||
* 1. 创建${totalUserCount}个用户
|
||||
* 2. 每个用户同其他${friendCount}个用户建立好友关系
|
||||
* 3. 确保每个人都加入${smallGroupCount}个群组成员数为${smallGroupMemberSize}的小群组
|
||||
* 4. 确保每个人都加入${middleGroupCount}个群组成员数为${middleGroupMemberSize}的中群组
|
||||
* 5. 确保每个人都加入${bigGroupCount}个群组成员数为${bigGroupMemberSize}的大群组
|
||||
* 6. 把数据分片${splitFileCount}个保存在文件中
|
||||
*
|
||||
* 好友关系和群组关系都是随机生成,有可能会出现最后几个用户无法满足精确好友数或者群组数的问题,但绝大部分数据都能满足需求。
|
||||
*/
|
||||
public class GenerateTestData {
|
||||
//IM服务Server API
|
||||
private static String AdminUrl = "http://10.206.0.5:18080";
|
||||
private static String AdminSecret = "123456";
|
||||
|
||||
private static int totalUserCount = 20000;
|
||||
|
||||
//每个用户的好友数
|
||||
private static int friendCount = 100;
|
||||
|
||||
//每个用户拥有的小群数,和小群的大小。
|
||||
private static int smallGroupCount = 100;
|
||||
private static int smallGroupMemberSize = 20;
|
||||
|
||||
//每个用户拥有的中群数,和中群的大小。
|
||||
private static int middleGroupCount = 100;
|
||||
private static int middleGroupMemberSize = 100;
|
||||
|
||||
//每个用户拥有的大群数,和大群的大小。
|
||||
private static int bigGroupCount = 20;
|
||||
private static int bigGroupMemberSize = 1000;
|
||||
|
||||
//数据文件分割成几个文件存储。
|
||||
private static int splitFileCount = 1;
|
||||
|
||||
|
||||
//统计添加好友数和创建群组数。
|
||||
private static AtomicInteger addFriendCount = new AtomicInteger(0);
|
||||
private static AtomicInteger createGroupCount = new AtomicInteger(0);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AdminConfig.initAdmin(AdminUrl, AdminSecret);
|
||||
int addFriendRequestCount = friendCount*totalUserCount/2;
|
||||
int createSmallGroupCount = smallGroupCount * totalUserCount / smallGroupMemberSize;
|
||||
int createMiddleGroupCount = middleGroupCount * totalUserCount / middleGroupMemberSize;
|
||||
int createBigGroupCount = bigGroupCount * totalUserCount / bigGroupMemberSize;
|
||||
System.out.println("根据当前的参数,将创建 " + totalUserCount + " 名用户");
|
||||
System.out.println("添加大概 " + addFriendRequestCount + " 次好友请求");
|
||||
System.out.println("创建大概 " + createSmallGroupCount + " 个小型群组");
|
||||
System.out.println("创建大概 " + createMiddleGroupCount + " 个中等群组");
|
||||
System.out.println("创建大概 " + createBigGroupCount + " 个大型群组");
|
||||
System.out.println("等待10秒开始");
|
||||
Thread.sleep(10*1000);
|
||||
|
||||
List<String> userIds = generateUserIds(totalUserCount);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(5);
|
||||
|
||||
new Thread(() -> {
|
||||
createUsers(userIds);
|
||||
latch.countDown();
|
||||
}).start();
|
||||
|
||||
Map<String, Integer> unfulfilledFriendMap = new HashMap<>();
|
||||
new Thread(() -> {
|
||||
addFriends(userIds, friendCount, unfulfilledFriendMap);
|
||||
latch.countDown();
|
||||
}).start();
|
||||
|
||||
Map<String, Set<String>> userSmallGroupMap = new HashMap<>();
|
||||
Map<String, Integer> unfulfilledSmallMap = new HashMap<>();
|
||||
new Thread(() ->{
|
||||
for (String userId : userIds) {
|
||||
createGroup(userId, userIds, userSmallGroupMap, smallGroupCount, smallGroupMemberSize, unfulfilledSmallMap);
|
||||
}
|
||||
latch.countDown();
|
||||
}).start();
|
||||
|
||||
Map<String, Set<String>> userMiddleGroupMap = new HashMap<>();
|
||||
Map<String, Integer> unfulfilledMiddleMap = new HashMap<>();
|
||||
new Thread(() ->{
|
||||
for (String userId : userIds) {
|
||||
createGroup(userId, userIds, userMiddleGroupMap, middleGroupCount, middleGroupMemberSize, unfulfilledMiddleMap);
|
||||
}
|
||||
latch.countDown();
|
||||
}).start();
|
||||
|
||||
Map<String, Set<String>> userBigGroupMap = new HashMap<>();
|
||||
Map<String, Integer> unfulfilledBigMap = new HashMap<>();
|
||||
new Thread(() ->{
|
||||
for (String userId : userIds) {
|
||||
createGroup(userId, userIds, userBigGroupMap, bigGroupCount, bigGroupMemberSize, unfulfilledBigMap);
|
||||
}
|
||||
latch.countDown();
|
||||
}).start();
|
||||
|
||||
latch.await();
|
||||
|
||||
System.out.println("数据初始化结束,实际建立好友关系: " + addFriendCount.get() + " 条。");
|
||||
if (!unfulfilledFriendMap.isEmpty()) {
|
||||
System.out.println("有部分用户没有建立" + friendCount + "个好友关系,分别是:");
|
||||
printUnfulfilledMap(unfulfilledFriendMap);
|
||||
}
|
||||
|
||||
System.out.println("数据初始化结束,创建群组: " + createGroupCount.get() + " 个。");
|
||||
if (!unfulfilledSmallMap.isEmpty()) {
|
||||
System.out.println("有部分用户没有建立" + smallGroupMemberSize + "个群组成员的群,分别是:");
|
||||
printUnfulfilledMap(unfulfilledSmallMap);
|
||||
}
|
||||
if (!unfulfilledMiddleMap.isEmpty()) {
|
||||
System.out.println("有部分用户没有建立" + middleGroupMemberSize + "个群组成员的群,分别是:");
|
||||
printUnfulfilledMap(unfulfilledMiddleMap);
|
||||
}
|
||||
if (!unfulfilledBigMap.isEmpty()) {
|
||||
System.out.println("有部分用户没有建立" + bigGroupMemberSize + "个群组成员的群,分别是:");
|
||||
printUnfulfilledMap(unfulfilledBigMap);
|
||||
}
|
||||
|
||||
|
||||
System.out.println("保存数据到" + splitFileCount + "个文件中。");
|
||||
for (int i = 0; i < splitFileCount; i++) {
|
||||
String filePath = "data"+i+".csv"; // 文件路径
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
|
||||
int partSize = totalUserCount/splitFileCount;
|
||||
for (int j = 0; j < partSize; j++) {
|
||||
String userId = userIds.get(i*partSize+j);
|
||||
writeDeviceInfo(writer, userId, 3);
|
||||
Set<String> smallGroupIds = userSmallGroupMap.get(userId);
|
||||
writeGroupIds(writer, smallGroupIds);
|
||||
Set<String> middleGroupIds = userMiddleGroupMap.get(userId);
|
||||
writeGroupIds(writer, middleGroupIds);
|
||||
Set<String> bigGroupIds = userBigGroupMap.get(userId);
|
||||
writeGroupIds(writer, bigGroupIds);
|
||||
}
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
System.out.println("保存结束。");
|
||||
}
|
||||
|
||||
private static void printUnfulfilledMap(Map<String, Integer> map) {
|
||||
if(map.isEmpty())
|
||||
return;
|
||||
|
||||
map.forEach((s, integer) -> System.out.print(s + ":" + integer + " "));
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static void writeDeviceInfo(BufferedWriter writer, String userId, int platform) throws IOException {
|
||||
writer.write(userId);
|
||||
writer.write(",");
|
||||
writer.write(UUID.randomUUID().toString());
|
||||
writer.write(",");
|
||||
writer.write(""+platform);
|
||||
writer.write("\n");
|
||||
}
|
||||
|
||||
private static void writeGroupIds(BufferedWriter writer, Set<String> groupIds) throws IOException {
|
||||
int writeCount = 0;
|
||||
for (String bigGroupId : groupIds) {
|
||||
writer.write(bigGroupId);
|
||||
writeCount++;
|
||||
if(writeCount < groupIds.size()) {
|
||||
writer.write(",");
|
||||
} else {
|
||||
writer.write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void createGroup(String userId, List<String> userIds, Map<String, Set<String>> userGroupMap, int groupCount, int memberSize, Map<String, Integer> unfulfilledUserMap) {
|
||||
Set<String> groupIds = userGroupMap.computeIfAbsent(userId, s -> new HashSet<>());
|
||||
int i = 0;
|
||||
while (groupIds.size() < groupCount){
|
||||
PojoGroupInfo groupInfo = new PojoGroupInfo();
|
||||
groupInfo.setTarget_id(UUID.randomUUID().toString());
|
||||
groupInfo.setOwner(userId);
|
||||
groupInfo.setName("Group_"+userId+i++);
|
||||
groupInfo.setType(2);
|
||||
groupIds.add(groupInfo.getTarget_id());
|
||||
|
||||
List<String> memberCandidates = new ArrayList<>(userIds);
|
||||
List<String> memberIds = new ArrayList<>();
|
||||
memberIds.add(userId);
|
||||
|
||||
while (!memberCandidates.isEmpty() && memberIds.size() < memberSize) {
|
||||
String memberId = memberCandidates.get((int)(Math.random()*memberCandidates.size()));
|
||||
memberCandidates.remove(memberId);
|
||||
if(memberId.equals(userId)) {
|
||||
continue;
|
||||
}
|
||||
if (memberIds.contains(memberId)) {
|
||||
continue;
|
||||
}
|
||||
Set<String> memberGroupIds = userGroupMap.computeIfAbsent(memberId, s -> new HashSet<>());
|
||||
if(memberGroupIds.contains(groupInfo.getTarget_id()) || memberGroupIds.size() >= groupCount) {
|
||||
continue;
|
||||
}
|
||||
memberGroupIds.add(groupInfo.getTarget_id());
|
||||
memberIds.add(memberId);
|
||||
}
|
||||
|
||||
List<PojoGroupMember> members = new ArrayList<>();
|
||||
for (String memberId : memberIds) {
|
||||
PojoGroupMember member1 = new PojoGroupMember();
|
||||
member1.setMember_id(memberId);
|
||||
members.add(member1);
|
||||
}
|
||||
|
||||
try {
|
||||
IMResult<OutputCreateGroupResult> resultCreateGroup = GroupAdmin.createGroup(groupInfo.getOwner(), groupInfo, members, null, null, null);
|
||||
if (resultCreateGroup != null && resultCreateGroup.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
System.out.println("create group success");
|
||||
} else {
|
||||
System.out.println("create group failure");
|
||||
System.exit(-1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("create group failure:" + e);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
createGroupCount.incrementAndGet();
|
||||
if(memberIds.size() < memberSize) {
|
||||
unfulfilledUserMap.put(userId + "'s group " + groupInfo.getTarget_id(), memberIds.size());
|
||||
System.out.println("Error, can not find enough user to create group for user:" + userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addFriends(List<String> userIds, int count, Map<String, Integer> unfulfilledFriendMap) {
|
||||
ConcurrentLinkedQueue<Pair<String, String>> toAddSet = new ConcurrentLinkedQueue<>();
|
||||
Map<String, Set<String>> userFriends = new HashMap<>();
|
||||
for (String userId : userIds) {
|
||||
List<String> candidates = new ArrayList<>(userIds);
|
||||
Set<String> currentUserFriends = userFriends.computeIfAbsent(userId, s -> new HashSet<>());
|
||||
while (!candidates.isEmpty() && currentUserFriends.size() < count) {
|
||||
String friendId = candidates.get((int) (Math.random()*candidates.size()));
|
||||
candidates.remove(friendId);
|
||||
if(friendId.equals(userId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!currentUserFriends.contains(friendId)) {
|
||||
Set<String> targetUserFriends = userFriends.computeIfAbsent(friendId, s -> new HashSet<>());
|
||||
if(targetUserFriends.size() < count) {
|
||||
currentUserFriends.add(friendId);
|
||||
targetUserFriends.add(userId);
|
||||
toAddSet.add(new Pair<>(userId, friendId));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentUserFriends.size() < count) {
|
||||
unfulfilledFriendMap.put(userId, currentUserFriends.size());
|
||||
System.out.println("Error, can not find enough user to add friend for user:" + userId);
|
||||
}
|
||||
}
|
||||
int threadNum = 5;
|
||||
CountDownLatch latch = new CountDownLatch(threadNum);
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
Pair<String, String> pair = toAddSet.poll();
|
||||
if(pair == null) {
|
||||
latch.countDown();
|
||||
break;
|
||||
}
|
||||
try {
|
||||
IMResult<Void> result = RelationAdmin.setUserFriend(pair.first, pair.second, true, null);
|
||||
if (result != null && (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || result.getErrorCode() == ErrorCode.ERROR_CODE_ALREADY_FRIENDS)) {
|
||||
System.out.println("add friend success");
|
||||
addFriendCount.incrementAndGet();
|
||||
} else {
|
||||
System.out.println("failure");
|
||||
System.exit(-1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("failure:" + e);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("failure:" + e);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateUserId(int index) {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
private static List<String> generateUserIds(int count) {
|
||||
List<String> userIds = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
userIds.add(generateUserId(i));
|
||||
}
|
||||
return userIds;
|
||||
}
|
||||
|
||||
private static void createUsers(List<String> userIds) {
|
||||
for (int i = 0; i < userIds.size(); i++) {
|
||||
InputOutputUserInfo userInfo = generateUserInfo(userIds.get(i), i);
|
||||
try {
|
||||
IMResult<OutputCreateUser> resultCreateUser = UserAdmin.createUser(userInfo);
|
||||
if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
System.out.println("Create user " + resultCreateUser.getResult().getName() + " success");
|
||||
} else {
|
||||
System.out.println("Create user failure");
|
||||
System.exit(-1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Create user failure");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static InputOutputUserInfo generateUserInfo(String userId, int index) {
|
||||
InputOutputUserInfo userInfo = new InputOutputUserInfo();
|
||||
//用户ID,必须保证唯一性
|
||||
userInfo.setUserId(userId);
|
||||
//用户名,一般是用户登录帐号,也必须保证唯一性。也就是说所有用户的userId必须不能重复,所有用户的name必须不能重复,但可以同一个用户的userId和name是同一个,一般建议userId使用一个uuid,name是"微信号"且可以修改,
|
||||
userInfo.setName(userId);
|
||||
userInfo.setMobile((11000000000L+index) + "");
|
||||
userInfo.setDisplayName("User"+index);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
static class Pair<K, V> {
|
||||
K first;
|
||||
V second;
|
||||
|
||||
public Pair() {
|
||||
}
|
||||
|
||||
public Pair(K first, V second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,13 @@ package cn.wildfirechat.sdk;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
public class GroupAdmin {
|
||||
public static IMResult<OutputCreateGroupResult> createGroup(String operator, PojoGroupInfo group_info, List<PojoGroupMember> members, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public static IMResult<OutputCreateGroupResult> createGroup(String operator, PojoGroupInfo group_info, List<PojoGroupMember> members, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Create_Group;
|
||||
PojoGroup pojoGroup = new PojoGroup();
|
||||
pojoGroup.setGroup_info(group_info);
|
||||
@@ -17,6 +16,7 @@ public class GroupAdmin {
|
||||
InputCreateGroup createGroup = new InputCreateGroup();
|
||||
createGroup.setGroup(pojoGroup);
|
||||
createGroup.setOperator(operator);
|
||||
createGroup.setMember_extra(member_extra);
|
||||
createGroup.setTo_lines(to_lines);
|
||||
createGroup.setNotify_message(notify_message);
|
||||
|
||||
@@ -85,12 +85,13 @@ public class GroupAdmin {
|
||||
return AdminHttpUtils.httpJsonPost(path, input, PojoGroupMember.class);
|
||||
}
|
||||
|
||||
public static IMResult<Void> addGroupMembers(String operator, String groupId, List<PojoGroupMember> groupMembers, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public static IMResult<Void> addGroupMembers(String operator, String groupId, List<PojoGroupMember> groupMembers, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Group_Member_Add;
|
||||
InputAddGroupMember addGroupMember = new InputAddGroupMember();
|
||||
addGroupMember.setGroup_id(groupId);
|
||||
addGroupMember.setMembers(groupMembers);
|
||||
addGroupMember.setOperator(operator);
|
||||
addGroupMember.setMemberExtra(member_extra);
|
||||
addGroupMember.setTo_lines(to_lines);
|
||||
addGroupMember.setNotify_message(notify_message);
|
||||
return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -81,13 +81,7 @@ public class MessageAdmin {
|
||||
return AdminHttpUtils.httpJsonPost(path, inputMessageUid, OutputMessageData.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回群发或者广播的消息
|
||||
* @param operator 操作者
|
||||
* @param messageUid 消息唯一ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
//仅专业版支持
|
||||
public static IMResult<Void> recallBroadCastMessage(String operator, long messageUid) throws Exception {
|
||||
String path = APIPath.Msg_RecallBroadCast;
|
||||
RecallMessageData messageData = new RecallMessageData();
|
||||
@@ -102,10 +96,28 @@ public class MessageAdmin {
|
||||
messageData.operator = operator;
|
||||
messageData.messageUid = messageUid;
|
||||
messageData.receivers = receivers;
|
||||
|
||||
return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);
|
||||
}
|
||||
|
||||
//仅专业版支持
|
||||
public static IMResult<Void> deleteBroadCastMessage(String operator, long messageUid) throws Exception {
|
||||
String path = APIPath.Msg_DeleteBroadCast;
|
||||
RecallMessageData messageData = new RecallMessageData();
|
||||
messageData.setOperator(operator);
|
||||
messageData.setMessageUid(messageUid);
|
||||
return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);
|
||||
}
|
||||
|
||||
public static IMResult<Void> deleteMultiCastMessage(String operator, long messageUid, List<String> receivers) throws Exception {
|
||||
String path = APIPath.Msg_DeleteMultiCast;
|
||||
RecallMultiCastMessageData messageData = new RecallMultiCastMessageData();
|
||||
messageData.operator = operator;
|
||||
messageData.messageUid = messageUid;
|
||||
messageData.receivers = receivers;
|
||||
return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);
|
||||
}
|
||||
|
||||
//仅专业版支持
|
||||
public static IMResult<BroadMessageResult> broadcastMessage(String sender, int line, MessagePayload payload) throws Exception {
|
||||
String path = APIPath.Msg_Broadcast;
|
||||
BroadMessageData messageData = new BroadMessageData();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package cn.wildfirechat.sdk;
|
||||
|
||||
import cn.wildfirechat.common.APIPath;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.*;
|
||||
import cn.wildfirechat.pojos.moments.*;
|
||||
import cn.wildfirechat.sdk.model.IMResult;
|
||||
import cn.wildfirechat.sdk.utilities.RobotHttpUtils;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
@@ -22,10 +24,15 @@ 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);
|
||||
}
|
||||
@@ -96,13 +103,14 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, pojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<OutputCreateGroupResult> createGroup(PojoGroupInfo group_info, List<PojoGroupMember> members, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<OutputCreateGroupResult> createGroup(PojoGroupInfo group_info, List<PojoGroupMember> members, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Create_Group;
|
||||
PojoGroup pojoGroup = new PojoGroup();
|
||||
pojoGroup.setGroup_info(group_info);
|
||||
pojoGroup.setMembers(members);
|
||||
InputCreateGroup createGroup = new InputCreateGroup();
|
||||
createGroup.setGroup(pojoGroup);
|
||||
createGroup.setMember_extra(member_extra);
|
||||
createGroup.setTo_lines(to_lines);
|
||||
createGroup.setNotify_message(notify_message);
|
||||
|
||||
@@ -117,7 +125,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, input, PojoGroupInfo.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> dismissGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> dismissGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Dismiss;
|
||||
InputDismissGroup dismissGroup = new InputDismissGroup();
|
||||
dismissGroup.setGroup_id(groupId);
|
||||
@@ -126,7 +134,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, dismissGroup, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> transferGroup(String groupId, String newOwner, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> transferGroup(String groupId, String newOwner, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Transfer;
|
||||
InputTransferGroup transferGroup = new InputTransferGroup();
|
||||
transferGroup.setGroup_id(groupId);
|
||||
@@ -136,7 +144,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, transferGroup, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> modifyGroupInfo(String groupId, /*ModifyGroupInfoType*/int type, String value, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> modifyGroupInfo(String groupId, /*ModifyGroupInfoType*/int type, String value, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Modify_Info;
|
||||
InputModifyGroupInfo modifyGroupInfo = new InputModifyGroupInfo();
|
||||
modifyGroupInfo.setGroup_id(groupId);
|
||||
@@ -163,17 +171,18 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, input, PojoGroupMember.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> addGroupMembers(String groupId, List<PojoGroupMember> groupMembers, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> addGroupMembers(String groupId, List<PojoGroupMember> groupMembers, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Member_Add;
|
||||
InputAddGroupMember addGroupMember = new InputAddGroupMember();
|
||||
addGroupMember.setGroup_id(groupId);
|
||||
addGroupMember.setMembers(groupMembers);
|
||||
addGroupMember.setMemberExtra(member_extra);
|
||||
addGroupMember.setTo_lines(to_lines);
|
||||
addGroupMember.setNotify_message(notify_message);
|
||||
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> setGroupManager(String groupId, List<String> groupMemberIds, boolean isManager, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> setGroupManager(String groupId, List<String> groupMemberIds, boolean isManager, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Set_Manager;
|
||||
InputSetGroupManager addGroupMember = new InputSetGroupManager();
|
||||
addGroupMember.setGroup_id(groupId);
|
||||
@@ -184,7 +193,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> muteGroupMember(String groupId, List<String> groupMemberIds, boolean isMute, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> muteGroupMember(String groupId, List<String> groupMemberIds, boolean isMute, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Mute_Member;
|
||||
InputMuteGroupMember addGroupMember = new InputMuteGroupMember();
|
||||
addGroupMember.setGroup_id(groupId);
|
||||
@@ -195,7 +204,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> allowGroupMember(String groupId, List<String> groupMemberIds, boolean isAllow, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> allowGroupMember(String groupId, List<String> groupMemberIds, boolean isAllow, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Allow_Member;
|
||||
InputMuteGroupMember addGroupMember = new InputMuteGroupMember();
|
||||
addGroupMember.setGroup_id(groupId);
|
||||
@@ -206,7 +215,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> kickoffGroupMembers(String groupId, List<String> groupMemberIds, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> kickoffGroupMembers(String groupId, List<String> groupMemberIds, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Member_Kickoff;
|
||||
InputKickoffGroupMember kickoffGroupMember = new InputKickoffGroupMember();
|
||||
kickoffGroupMember.setGroup_id(groupId);
|
||||
@@ -216,7 +225,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, kickoffGroupMember, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> quitGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> quitGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Member_Quit;
|
||||
InputQuitGroup quitGroup = new InputQuitGroup();
|
||||
quitGroup.setGroup_id(groupId);
|
||||
@@ -225,7 +234,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, quitGroup, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> setGroupMemberAlias(String groupId, String memberId, String alias, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> setGroupMemberAlias(String groupId, String memberId, String alias, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Set_Member_Alias;
|
||||
InputSetGroupMemberAlias input = new InputSetGroupMemberAlias();
|
||||
input.setGroup_id(groupId);
|
||||
@@ -236,7 +245,7 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, input, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> setGroupMemberExtra(String groupId, String memberId, String extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
public IMResult<Void> setGroupMemberExtra(String groupId, String memberId, String extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {
|
||||
String path = APIPath.Robot_Group_Set_Member_Extra;
|
||||
InputSetGroupMemberExtra input = new InputSetGroupMemberExtra();
|
||||
input.setGroup_id(groupId);
|
||||
@@ -274,4 +283,144 @@ public class RobotService {
|
||||
return robotHttpUtils.httpJsonPost(path, input, String.class);
|
||||
}
|
||||
|
||||
public IMResult<FeedPojo> postMomentsFeed(int/*MomentsContentType*/ type, String text, List<MediaEntry> medias, List<String> toUsers, List<String> excludeUsers, List<String> mentionedUsers, String extra) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Post_Feed;
|
||||
FeedPojo feedPojo = new FeedPojo();
|
||||
feedPojo.type = type;
|
||||
feedPojo.text = text;
|
||||
feedPojo.medias = medias;
|
||||
feedPojo.to = toUsers;
|
||||
feedPojo.ex = excludeUsers;
|
||||
feedPojo.mu = mentionedUsers;
|
||||
feedPojo.extra = extra;
|
||||
IMResult<PostFeedResult> imResult = robotHttpUtils.httpJsonPost(path, feedPojo, PostFeedResult.class);
|
||||
IMResult<FeedPojo> feedResult = new IMResult<>();
|
||||
if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
feedPojo.feedId = imResult.result.id;
|
||||
feedPojo.timestamp = imResult.result.timestamp;
|
||||
feedResult.setCode(ErrorCode.ERROR_CODE_SUCCESS.getCode());
|
||||
feedResult.setResult(feedPojo);
|
||||
} else {
|
||||
feedResult.setCode(imResult.getCode());
|
||||
feedResult.setMsg(imResult.getMsg());
|
||||
}
|
||||
return feedResult;
|
||||
}
|
||||
|
||||
public IMResult<Void> updateMomentsFeed(long feedId, int/*MomentsContentType*/ type, String text, List<MediaEntry> medias, List<String> toUsers, List<String> excludeUsers, List<String> mentionedUsers, String extra) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Update_Feed;
|
||||
FeedPojo feedPojo = new FeedPojo();
|
||||
feedPojo.feedId = feedId;
|
||||
feedPojo.type = type;
|
||||
feedPojo.text = text;
|
||||
feedPojo.medias = medias;
|
||||
feedPojo.to = toUsers;
|
||||
feedPojo.ex = excludeUsers;
|
||||
feedPojo.mu = mentionedUsers;
|
||||
feedPojo.extra = extra;
|
||||
return robotHttpUtils.httpJsonPost(path, feedPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<FeedsPojo> getMomentsFeeds(long feedId, int count, String user) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Pull_Feeds;
|
||||
PullFeedRequestPojo requestPojo = new PullFeedRequestPojo();
|
||||
requestPojo.feedId = feedId;
|
||||
requestPojo.count = count;
|
||||
requestPojo.user = user;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, FeedsPojo.class);
|
||||
}
|
||||
|
||||
public IMResult<FeedPojo> getMomentsFeed(long feedId) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Fetch_Feed;
|
||||
PullOneFeedRequestPojo requestPojo = new PullOneFeedRequestPojo();
|
||||
requestPojo.feedId = feedId;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, FeedPojo.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> deleteMomentsFeed(long feedId) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Recall_Feed;
|
||||
IdPojo requestPojo = new IdPojo();
|
||||
requestPojo.id = feedId;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<CommentPojo> postMomentsComment(long feedId, long replyId, int/*MomentsCommentType*/ type, String text, String replyTo, String extra) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Post_Comment;
|
||||
CommentPojo commentPojo = new CommentPojo();
|
||||
commentPojo.type = type;
|
||||
commentPojo.text = text;
|
||||
commentPojo.replyId = replyId;
|
||||
commentPojo.feedId = feedId;
|
||||
commentPojo.replyTo = replyTo;
|
||||
commentPojo.extra = extra;
|
||||
IMResult<PostFeedResult> imResult = robotHttpUtils.httpJsonPost(path, commentPojo, PostFeedResult.class);
|
||||
IMResult<CommentPojo> feedResult = new IMResult<>();
|
||||
if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
commentPojo.commentId = imResult.result.id;
|
||||
commentPojo.timestamp = imResult.result.timestamp;
|
||||
feedResult.setCode(ErrorCode.ERROR_CODE_SUCCESS.getCode());
|
||||
feedResult.setResult(commentPojo);
|
||||
} else {
|
||||
feedResult.setCode(imResult.getCode());
|
||||
feedResult.setMsg(imResult.getMsg());
|
||||
}
|
||||
return feedResult;
|
||||
}
|
||||
|
||||
public IMResult<Void> deleteMomentsComment(long feedId, long commentId) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Recall_Comment;
|
||||
IdPojo requestPojo = new IdPojo();
|
||||
requestPojo.id = commentId;
|
||||
requestPojo.id2 = feedId;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<MomentProfilePojo> getUserMomentsProfile(String userId) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Fetch_Profiles;
|
||||
PullProfileRequestPojo requestPojo = new PullProfileRequestPojo();
|
||||
requestPojo.u = userId;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, MomentProfilePojo.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> updateMomentsBackgroundUrl(String url) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Update_Profiles_Value;
|
||||
PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();
|
||||
requestPojo.t = 0;
|
||||
requestPojo.v = url;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> updateMomentsStrangerVisibleCount(int count) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Update_Profiles_Value;
|
||||
PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();
|
||||
requestPojo.t = 1;
|
||||
requestPojo.i = count;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> updateMomentsVisibleScope(int/*MomentsVisibleScope*/ scope) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Update_Profiles_Value;
|
||||
PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();
|
||||
requestPojo.t = 2;
|
||||
requestPojo.i = scope;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> updateMomentsBlackList(List<String> addList, List<String> removeList) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Update_Profiles_List_Value;
|
||||
PushProfileListRequestPojo requestPojo = new PushProfileListRequestPojo();
|
||||
requestPojo.b = false;
|
||||
requestPojo.al = addList;
|
||||
requestPojo.rl = removeList;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
|
||||
public IMResult<Void> updateMomentsBlockList(List<String> addList, List<String> removeList) throws Exception {
|
||||
String path = APIPath.Robot_Moments_Update_Profiles_List_Value;
|
||||
PushProfileListRequestPojo requestPojo = new PushProfileListRequestPojo();
|
||||
requestPojo.b = true;
|
||||
requestPojo.al = addList;
|
||||
requestPojo.rl = removeList;
|
||||
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import cn.wildfirechat.pojos.*;
|
||||
import cn.wildfirechat.sdk.model.IMResult;
|
||||
import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UserAdmin {
|
||||
public static IMResult<InputOutputUserInfo> getUserByName(String name) throws Exception {
|
||||
String path = APIPath.User_Get_Info;
|
||||
@@ -37,6 +39,13 @@ public class UserAdmin {
|
||||
return AdminHttpUtils.httpJsonPost(path, input, OutputGetUserList.class);
|
||||
}
|
||||
|
||||
public static IMResult<OutputUserInfoList> getBatchUsers(List<String> userIds) throws Exception {
|
||||
String path = APIPath.User_Batch_Get_Infos;
|
||||
InputStringList input = new InputStringList();
|
||||
input.setList(userIds);
|
||||
return AdminHttpUtils.httpJsonPost(path, input, OutputUserInfoList.class);
|
||||
}
|
||||
|
||||
public static IMResult<OutputCreateUser> createUser(InputOutputUserInfo user) throws Exception {
|
||||
String path = APIPath.Create_User;
|
||||
return AdminHttpUtils.httpJsonPost(path, user, OutputCreateUser.class);
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2022 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class ArticlesMessageContent extends MessageContent {
|
||||
public Article topArticle;
|
||||
public ArrayList<Article> subArticles;
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Articles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(topArticle.title);
|
||||
JSONObject object = new JSONObject();
|
||||
|
||||
object.put("top", topArticle.toJson());
|
||||
if (subArticles != null) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
object.put("subArticles", jsonArray);
|
||||
for (Article article : subArticles) {
|
||||
jsonArray.add(article.toJson());
|
||||
}
|
||||
}
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(object.toString().getBytes()));
|
||||
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@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);
|
||||
JSONArray jsonArray = (JSONArray) object.get("subArticles");
|
||||
if (jsonArray != null && jsonArray.size() > 0) {
|
||||
this.subArticles = new ArrayList<>();
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
subArticles.add(Article.fromJson((JSONObject) jsonArray.get(i)));
|
||||
}
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<LinkMessageContent> toLinkMessageContent() {
|
||||
List<LinkMessageContent> contents = new ArrayList<>();
|
||||
contents.add(this.topArticle.toLinkMessageContent());
|
||||
if (this.subArticles != null) {
|
||||
for (Article article : subArticles) {
|
||||
contents.add(article.toLinkMessageContent());
|
||||
}
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
public static class Article {
|
||||
public String articleId;
|
||||
public String cover;
|
||||
public String title;
|
||||
public String digest;
|
||||
public String url;
|
||||
boolean readReport;
|
||||
|
||||
JSONObject toJson() {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("id", articleId);
|
||||
obj.put("cover", cover);
|
||||
obj.put("title", title);
|
||||
obj.put("digest", digest);
|
||||
obj.put("url", url);
|
||||
obj.put("rr", readReport);
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static Article fromJson(JSONObject obj) {
|
||||
Article article = new Article();
|
||||
article.articleId = (String) obj.get("id");
|
||||
article.cover = (String) obj.get("cover");
|
||||
article.title = (String) obj.get("title");
|
||||
article.digest = (String) obj.get("digest");
|
||||
article.url = (String) obj.get("url");
|
||||
article.readReport = (boolean) obj.get("rr");
|
||||
return article;
|
||||
}
|
||||
|
||||
public LinkMessageContent toLinkMessageContent() {
|
||||
LinkMessageContent content = new LinkMessageContent(this.title, this.url);
|
||||
content.setContentDigest(this.digest);
|
||||
content.setThumbnailUrl(this.cover);
|
||||
return content;
|
||||
}
|
||||
|
||||
public Article() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by heavyrain lee on 2017/12/6.
|
||||
*/
|
||||
|
||||
public class CallStartMessageContent extends MessageContent {
|
||||
private String callId;
|
||||
// 多人视音频是有效,不包含自己,一对一忽略此参数
|
||||
private List<String> targetIds;
|
||||
private long connectTime;
|
||||
private long endTime;
|
||||
private boolean audioOnly;
|
||||
private String pin;
|
||||
|
||||
|
||||
/**
|
||||
* 0, UnKnown,
|
||||
* 1, Busy,
|
||||
* 2, SignalError,
|
||||
* 3, Hangup,
|
||||
* 4, MediaError,
|
||||
* 5, RemoteHangup,
|
||||
* 6, OpenCameraFailure,
|
||||
* 7, Timeout,
|
||||
* 8, AcceptByOtherClient
|
||||
*/
|
||||
private int status;
|
||||
|
||||
/**
|
||||
* 0,未知;1,多人版音视频;2,高级版音视频
|
||||
*/
|
||||
private int type;
|
||||
|
||||
public CallStartMessageContent() {
|
||||
}
|
||||
|
||||
public CallStartMessageContent(String callId, List<String> targetIds, boolean audioOnly) {
|
||||
this.callId = callId;
|
||||
this.audioOnly = audioOnly;
|
||||
this.targetIds = targetIds;
|
||||
}
|
||||
|
||||
public String getCallId() {
|
||||
return callId;
|
||||
}
|
||||
|
||||
public void setCallId(String callId) {
|
||||
this.callId = callId;
|
||||
}
|
||||
|
||||
public long getConnectTime() {
|
||||
return connectTime;
|
||||
}
|
||||
|
||||
public void setConnectTime(long connectTime) {
|
||||
this.connectTime = connectTime;
|
||||
}
|
||||
|
||||
public long getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(long endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean isAudioOnly() {
|
||||
return audioOnly;
|
||||
}
|
||||
|
||||
public void setAudioOnly(boolean audioOnly) {
|
||||
this.audioOnly = audioOnly;
|
||||
}
|
||||
|
||||
public List<String> getTargetIds() {
|
||||
return targetIds;
|
||||
}
|
||||
|
||||
public void setTargetIds(List<String> targetIds) {
|
||||
this.targetIds = targetIds;
|
||||
}
|
||||
|
||||
public String getPin() {
|
||||
return pin;
|
||||
}
|
||||
|
||||
public void setPin(String pin) {
|
||||
this.pin = pin;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Call_Start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setContent(callId);
|
||||
payload.setPushContent("音视频通话邀请");
|
||||
|
||||
JSONObject objWrite = new JSONObject();
|
||||
if (connectTime > 0) {
|
||||
objWrite.put("c", connectTime);
|
||||
}
|
||||
|
||||
if (endTime > 0) {
|
||||
objWrite.put("e", endTime);
|
||||
}
|
||||
|
||||
if (status > 0) {
|
||||
objWrite.put("s", status);
|
||||
}
|
||||
|
||||
objWrite.put("t", targetIds.get(0));
|
||||
JSONArray ts = new JSONArray();
|
||||
ts.addAll(targetIds);
|
||||
objWrite.put("ts", ts);
|
||||
objWrite.put("a", audioOnly ? 1 : 0);
|
||||
objWrite.put("p", pin);
|
||||
if (this.type > 0) {
|
||||
objWrite.put("ty", this.type);
|
||||
}
|
||||
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));
|
||||
|
||||
JSONObject pushDataWrite = new JSONObject();
|
||||
pushDataWrite.put("callId", callId);
|
||||
pushDataWrite.put("audioOnly", audioOnly);
|
||||
if (targetIds != null && targetIds.size() > 0) {
|
||||
pushDataWrite.put("participants", targetIds);
|
||||
}
|
||||
payload.setPushData(pushDataWrite.toString());
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
callId = payload.getContent();
|
||||
|
||||
try {
|
||||
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
|
||||
connectTime = (long) jsonObject.get("c");
|
||||
endTime = (long) jsonObject.get("e");
|
||||
status = (int) jsonObject.get("s");
|
||||
pin = (String) jsonObject.get("p");
|
||||
type = (int) jsonObject.get("ty");
|
||||
JSONArray array = (JSONArray) jsonObject.get("ts");
|
||||
targetIds = new ArrayList<>();
|
||||
if (array == null) {
|
||||
targetIds.add((String) jsonObject.get("t"));
|
||||
} else {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
if (array.get(i) instanceof String) {
|
||||
targetIds.add((String) array.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
audioOnly = (int)jsonObject.get("a") > 0;
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class CardMessageContent extends MessageContent {
|
||||
/**
|
||||
* 0,用户;1,群组;2,聊天室;3,频道
|
||||
*/
|
||||
private int type;
|
||||
private String target;
|
||||
// 用户名,一般是type为用户时使用
|
||||
private String name;
|
||||
private String displayName;
|
||||
private String portrait;
|
||||
private String from;
|
||||
|
||||
public CardMessageContent() {
|
||||
}
|
||||
|
||||
public CardMessageContent(int type, String target, String displayName, String portrait, String from) {
|
||||
this.type = type;
|
||||
this.target = target;
|
||||
this.displayName = displayName;
|
||||
this.portrait = portrait;
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(String target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getPortrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public void setPortrait(String portrait) {
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Name_Card;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setContent(target);
|
||||
JSONObject objWrite = new JSONObject();
|
||||
objWrite.put("t", type);
|
||||
objWrite.put("n", name);
|
||||
objWrite.put("d", displayName);
|
||||
objWrite.put("p", portrait);
|
||||
objWrite.put("f", from);
|
||||
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
target = payload.getContent();
|
||||
try {
|
||||
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
|
||||
type = (int) jsonObject.get("t");
|
||||
name = (String) jsonObject.get("n");
|
||||
displayName = (String) jsonObject.get("d");
|
||||
portrait = (String) jsonObject.get("p");
|
||||
from = (String) jsonObject.get("f");
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class FileMessageContent extends MediaMessageContent {
|
||||
private String name;
|
||||
private int size;
|
||||
private static final String FILE_NAME_PREFIX = "[文件] ";
|
||||
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.File;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(name);
|
||||
payload.setContent(size + "");
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload 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());
|
||||
} else {
|
||||
name = payload.getSearchableContent();
|
||||
}
|
||||
size = Integer.parseInt(payload.getContent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaType() {
|
||||
return ProtoConstants.MessageMediaType.FILE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class ImageMessageContent extends MediaMessageContent {
|
||||
private byte[] thumbnailBytes;
|
||||
|
||||
|
||||
public void setThumbnailBytes(byte[] thumbnailBytes) {
|
||||
this.thumbnailBytes = thumbnailBytes;
|
||||
}
|
||||
|
||||
public byte[] getThumbnailBytes() {
|
||||
return thumbnailBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent("[图片]");
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaType() {
|
||||
return ProtoConstants.MessageMediaType.IMAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class LinkMessageContent extends MessageContent {
|
||||
private String title;
|
||||
private String contentDigest;
|
||||
private String url;
|
||||
private String thumbnailUrl;
|
||||
|
||||
public LinkMessageContent() {
|
||||
}
|
||||
|
||||
public LinkMessageContent(String title, String url) {
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getContentDigest() {
|
||||
return contentDigest;
|
||||
}
|
||||
|
||||
public void setContentDigest(String contentDigest) {
|
||||
this.contentDigest = contentDigest;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getThumbnailUrl() {
|
||||
return thumbnailUrl;
|
||||
}
|
||||
|
||||
public void setThumbnailUrl(String thumbnailUrl) {
|
||||
this.thumbnailUrl = thumbnailUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(title);
|
||||
JSONObject objWrite = new JSONObject();
|
||||
objWrite.put("d", contentDigest);
|
||||
objWrite.put("u", url);
|
||||
objWrite.put("t", thumbnailUrl);
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@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())));
|
||||
contentDigest = (String) jsonObject.get("d");
|
||||
url = (String) jsonObject.get("u");
|
||||
thumbnailUrl = (String) jsonObject.get("t");
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class LocationMessageContent extends MessageContent {
|
||||
private String title;
|
||||
public byte[] thumbnailByte;
|
||||
private double longitude;
|
||||
private double latitude;
|
||||
|
||||
public LocationMessageContent() {
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public byte[] getThumbnailByte() {
|
||||
return thumbnailByte;
|
||||
}
|
||||
|
||||
public void setThumbnailByte(byte[] thumbnailByte) {
|
||||
this.thumbnailByte = thumbnailByte;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(title);
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(this.thumbnailByte));
|
||||
|
||||
JSONObject objWrite = new JSONObject();
|
||||
objWrite.put("lat", latitude);
|
||||
objWrite.put("long", longitude);
|
||||
|
||||
payload.setContent(objWrite.toString());
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
|
||||
this.thumbnailByte = Base64.getDecoder().decode(payload.getBase64edData());
|
||||
}
|
||||
title = payload.getSearchableContent();
|
||||
try {
|
||||
if (payload.getContent() != null) {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent());
|
||||
latitude = (double) jsonObject.get("lat");
|
||||
longitude = (double) jsonObject.get("long");
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
|
||||
abstract public class MediaMessageContent extends MessageContent {
|
||||
private String remoteMediaUrl;
|
||||
|
||||
public String getRemoteMediaUrl() {
|
||||
return remoteMediaUrl;
|
||||
}
|
||||
|
||||
public void setRemoteMediaUrl(String remoteMediaUrl) {
|
||||
this.remoteMediaUrl = remoteMediaUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MessageContent {
|
||||
private int mentionedType;
|
||||
private List<String> mentionedTargets;
|
||||
private String extra;
|
||||
public MessageContent mentionedType(int mentionedType) {
|
||||
this.mentionedType = mentionedType;
|
||||
return this;
|
||||
}
|
||||
public MessageContent mentionedTargets(List<String> mentionedTargets) {
|
||||
this.mentionedTargets = mentionedTargets;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MessageContent extra(String extra) {
|
||||
this.extra = extra;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = new MessagePayload();
|
||||
payload.setType(getContentType());
|
||||
payload.setPersistFlag(getPersistFlag());
|
||||
payload.setMentionedType(mentionedType);
|
||||
payload.setMentionedTarget(mentionedTargets);
|
||||
payload.setExtra(extra);
|
||||
return 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();
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.Conversation;
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import cn.wildfirechat.sdk.model.Message;
|
||||
import cn.wildfirechat.sdk.utilities.ClassUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MessageContentFactory {
|
||||
private static final Map<Integer, Class<? extends MessageContent>> contentClassMap = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
registerAllMessageContent();
|
||||
}
|
||||
|
||||
public static Message decodeMessage(WFCMessage.Message protoMessage) {
|
||||
Message message = new Message();
|
||||
message.content = decodeMessageContent(protoMessage.getContent());
|
||||
WFCMessage.Conversation protoConversation = protoMessage.getConversation();
|
||||
message.conversation = new Conversation(protoConversation.getType(), protoConversation.getTarget(), protoConversation.getLine());
|
||||
message.messageUid = protoMessage.getMessageId();
|
||||
message.sender = protoMessage.getFromUser();
|
||||
message.serverTime = protoMessage.getServerTimestamp();
|
||||
message.toUsers = protoMessage.getToList();
|
||||
return message;
|
||||
}
|
||||
|
||||
public static MessageContent decodeMessageContent(WFCMessage.MessageContent protoMessageContent) {
|
||||
MessagePayload payload = MessagePayload.fromProtoMessageContent(protoMessageContent);
|
||||
return decodeMessageContent(payload);
|
||||
}
|
||||
|
||||
public static MessageContent decodeMessageContent(MessagePayload messagePayload) {
|
||||
Class<? extends MessageContent> cls = contentClassMap.get(messagePayload.getType());
|
||||
MessageContent messageContent;
|
||||
if(cls != null) {
|
||||
try {
|
||||
messageContent = cls.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
messageContent = new UnknownMessageContent();
|
||||
}
|
||||
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 cls : ClassUtil.getAllAssignedClass(MessageContent.class)) {
|
||||
if(!Modifier.isAbstract(cls.getModifiers())) {
|
||||
try {
|
||||
MessageContent content = (MessageContent)cls.newInstance();
|
||||
contentClassMap.put(content.getContentType(), cls);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2022 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiCallOngoingMessageContent extends MessageContent {
|
||||
private String callId;
|
||||
private String initiator;
|
||||
private boolean audioOnly;
|
||||
private List<String> targets;
|
||||
|
||||
public MultiCallOngoingMessageContent() {
|
||||
}
|
||||
|
||||
public MultiCallOngoingMessageContent(String callId, String initiator, boolean audioOnly, List<String> targets) {
|
||||
this.callId = callId;
|
||||
this.initiator = initiator;
|
||||
this.audioOnly = audioOnly;
|
||||
this.targets = targets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Call_Multi_Call_Ongoing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Transparent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setContent(callId);
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("initiator", this.initiator);
|
||||
JSONArray arr = new JSONArray();
|
||||
for (int i = 0; i < targets.size(); i++) {
|
||||
arr.add(i, targets.get(i));
|
||||
}
|
||||
object.put("targets", arr);
|
||||
object.put("audioOnly", this.audioOnly ? 1 : 0);
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(object.toString().getBytes()));
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@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())));
|
||||
this.initiator = (String) object.get("initiator");
|
||||
this.targets = new ArrayList<>();
|
||||
JSONArray array = (JSONArray) object.get("targets");
|
||||
if (array != null) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
targets.add((String) array.get(i));
|
||||
}
|
||||
}
|
||||
this.audioOnly = (int)object.get("audioOnly") == 1;
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getCallId() {
|
||||
return callId;
|
||||
}
|
||||
|
||||
public void setCallId(String callId) {
|
||||
this.callId = callId;
|
||||
}
|
||||
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
public void setInitiator(String initiator) {
|
||||
this.initiator = initiator;
|
||||
}
|
||||
|
||||
public boolean isAudioOnly() {
|
||||
return audioOnly;
|
||||
}
|
||||
|
||||
public void setAudioOnly(boolean audioOnly) {
|
||||
this.audioOnly = audioOnly;
|
||||
}
|
||||
|
||||
public List<String> getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
public void setTargets(List<String> targets) {
|
||||
this.targets = targets;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2024 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
public class NotDeliveredMessageContent extends MessageContent {
|
||||
// 请求的类型,1 发送消息,2 撤回消息,3 删除消息
|
||||
private int type;
|
||||
|
||||
// 发送的消息 uid
|
||||
private long messageUid;
|
||||
|
||||
// 是全部失败,还是部分失败
|
||||
private boolean allFailure;
|
||||
|
||||
// 部分失败时,失败的用户 id 列表
|
||||
private List<String> userIds;
|
||||
|
||||
// 归属IM服务请求桥接服务出现的错误,有可能是桥接服务没有配置,或者不可用。
|
||||
private int localImErrorCode;
|
||||
|
||||
// 归属桥接服务出现的错误
|
||||
private int localBridgeErrorCode;
|
||||
|
||||
// 远端桥接服务出现的错误
|
||||
private int remoteBridgeErrorCode;
|
||||
|
||||
// 远端IM服务出现的错误
|
||||
private int remoteServerErrorCode;
|
||||
|
||||
// 错误提示信息
|
||||
private String errorMessage;
|
||||
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Not_Delivered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("mid", this.messageUid);
|
||||
obj.put("all", this.allFailure);
|
||||
obj.put("us", this.userIds);
|
||||
obj.put("lme", this.localImErrorCode);
|
||||
obj.put("lbe", this.localBridgeErrorCode);
|
||||
obj.put("rbe", this.remoteBridgeErrorCode);
|
||||
obj.put("rme", this.remoteServerErrorCode);
|
||||
obj.put("em", this.errorMessage);
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(obj.toString().getBytes()));
|
||||
return payload;
|
||||
}
|
||||
|
||||
@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");
|
||||
this.userIds = new ArrayList<>();
|
||||
JSONArray arr = (JSONArray) obj.get("us");
|
||||
if (arr != null) {
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
this.userIds.add((String) arr.get(i));
|
||||
}
|
||||
}
|
||||
this.localImErrorCode = (int) obj.get("lme");
|
||||
this.localBridgeErrorCode = (int) obj.get("lbe");
|
||||
this.remoteBridgeErrorCode = (int) obj.get("rbe");
|
||||
this.remoteServerErrorCode = (int) obj.get("rme");
|
||||
this.errorMessage = (String) obj.get("em");
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2021 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class PTTSoundMessageContent extends SoundMessageContent {
|
||||
|
||||
public PTTSoundMessageContent() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent("[对讲语音]");
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Ptt_Voice;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
-18
@@ -1,4 +1,4 @@
|
||||
package cn.wildfirechat.messagecontentbuilder;
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
@@ -9,7 +9,7 @@ import org.json.simple.JSONObject;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public class RichNotificationContentBuilder extends MessageContentBuilder{
|
||||
public class RichNotificationMessageContent extends MessageContent {
|
||||
private String title;
|
||||
private String desc;
|
||||
private String remark;
|
||||
@@ -19,34 +19,51 @@ public class RichNotificationContentBuilder extends MessageContentBuilder{
|
||||
private String exUrl;
|
||||
private String appId;
|
||||
|
||||
public static RichNotificationContentBuilder newBuilder(String title, String desc, String exUrl) {
|
||||
RichNotificationContentBuilder builder = new RichNotificationContentBuilder();
|
||||
builder.title = title;
|
||||
builder.desc = desc;
|
||||
builder.exUrl = exUrl;
|
||||
return builder;
|
||||
//必须有个空的构造函数
|
||||
public RichNotificationMessageContent() {
|
||||
}
|
||||
|
||||
public RichNotificationContentBuilder remark(String remark) {
|
||||
public RichNotificationMessageContent(String title, String desc, String exUrl) {
|
||||
this.title = title;
|
||||
this.desc = desc;
|
||||
this.exUrl = exUrl;
|
||||
}
|
||||
|
||||
public RichNotificationMessageContent title(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RichNotificationMessageContent desc(String desc) {
|
||||
this.desc = desc;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RichNotificationMessageContent exUrl(String exUrl) {
|
||||
this.exUrl = exUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RichNotificationMessageContent remark(String remark) {
|
||||
this.remark = remark;
|
||||
return this;
|
||||
}
|
||||
public RichNotificationContentBuilder exName(String exName) {
|
||||
public RichNotificationMessageContent exName(String exName) {
|
||||
this.exName = exName;
|
||||
return this;
|
||||
}
|
||||
public RichNotificationContentBuilder exPortrait(String exPortrait) {
|
||||
public RichNotificationMessageContent exPortrait(String exPortrait) {
|
||||
this.exPortrait = exPortrait;
|
||||
return this;
|
||||
}
|
||||
public RichNotificationContentBuilder appId(String appId) {
|
||||
public RichNotificationMessageContent appId(String appId) {
|
||||
this.appId = appId;
|
||||
return this;
|
||||
}
|
||||
public RichNotificationContentBuilder addItem(String key, String value) {
|
||||
public RichNotificationMessageContent addItem(String key, String value) {
|
||||
return addItem(key, value, null);
|
||||
}
|
||||
public RichNotificationContentBuilder addItem(String key, String value, String color) {
|
||||
public RichNotificationMessageContent addItem(String key, String value, String color) {
|
||||
if(this.datas == null) {
|
||||
this.datas = new JSONArray();
|
||||
}
|
||||
@@ -61,10 +78,18 @@ public class RichNotificationContentBuilder extends MessageContentBuilder{
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload build() {
|
||||
MessagePayload payload = encodeBase();
|
||||
payload.setType(ProtoConstants.ContentType.Rich_Notification);
|
||||
payload.setPersistFlag(ProtoConstants.PersistFlag.Persist_And_Count);
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Rich_Notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setPushContent(title);
|
||||
payload.setContent(desc);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
@@ -85,4 +110,9 @@ public class RichNotificationContentBuilder extends MessageContentBuilder{
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class SoundMessageContent extends MediaMessageContent {
|
||||
private int duration;
|
||||
|
||||
//必须有个空的构造函数
|
||||
public SoundMessageContent() {
|
||||
}
|
||||
|
||||
public SoundMessageContent(int duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Voice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("duration", duration);
|
||||
payload.setContent(jsonObject.toJSONString());
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaType() {
|
||||
return ProtoConstants.MessageMediaType.VOICE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class StickerMessageContent extends MediaMessageContent {
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent("[动态表情]");
|
||||
JSONObject objWrite = new JSONObject();
|
||||
objWrite.put("x", width);
|
||||
objWrite.put("y", height);
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
try {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
|
||||
width = (int) jsonObject.get("x");
|
||||
height = (int) jsonObject.get("y");
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaType() {
|
||||
return ProtoConstants.MessageMediaType.STICKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Sticker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class StreamTextGeneratedMessageContent extends MessageContent {
|
||||
private String text;
|
||||
private String streamId;
|
||||
|
||||
//必须有个空的构造函数
|
||||
public StreamTextGeneratedMessageContent() {
|
||||
}
|
||||
|
||||
public StreamTextGeneratedMessageContent(String text, String streamId) {
|
||||
this.text = text;
|
||||
this.streamId = streamId;
|
||||
}
|
||||
|
||||
public StreamTextGeneratedMessageContent text(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamTextGeneratedMessageContent streamId(String streamId) {
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.StreamingText_Generated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
this.streamId = payload.getContent();
|
||||
this.text = payload.getSearchableContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(text);
|
||||
payload.setContent(streamId);
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class StreamTextGeneratingMessageContent extends MessageContent {
|
||||
private String text;
|
||||
private String streamId;
|
||||
|
||||
//必须有个空的构造函数
|
||||
public StreamTextGeneratingMessageContent() {
|
||||
}
|
||||
|
||||
public StreamTextGeneratingMessageContent(String text, String streamId) {
|
||||
this.text = text;
|
||||
this.streamId = streamId;
|
||||
}
|
||||
|
||||
public StreamTextGeneratingMessageContent text(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamTextGeneratingMessageContent streamId(String streamId) {
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.StreamingText_Generationg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Transparent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
streamId = payload.getContent();
|
||||
text = payload.getSearchableContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(text);
|
||||
payload.setContent(streamId);
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.sdk.model.QuoteInfo;
|
||||
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 TextMessageContent extends MessageContent {
|
||||
private String text;
|
||||
private QuoteInfo quoteInfo;
|
||||
|
||||
//必须有个空的构造函数
|
||||
public TextMessageContent() {
|
||||
}
|
||||
|
||||
public TextMessageContent(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public TextMessageContent text(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public QuoteInfo getQuoteInfo() {
|
||||
return quoteInfo;
|
||||
}
|
||||
|
||||
public void setQuoteInfo(QuoteInfo quoteInfo) {
|
||||
this.quoteInfo = quoteInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent(text);
|
||||
if(quoteInfo != null) {
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(quoteInfo.encode().toJSONString().getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
text = payload.getSearchableContent();
|
||||
if(!TextUtils.isEmpty(payload.getBase64edData())) {
|
||||
String jsonStr = new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8);
|
||||
try {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(jsonStr);
|
||||
quoteInfo = new QuoteInfo();
|
||||
quoteInfo.decode(jsonObject);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class TipNotificationMessageContent extends MessageContent {
|
||||
public String tip;
|
||||
|
||||
public TipNotificationMessageContent() {
|
||||
}
|
||||
|
||||
public String getTip() {
|
||||
return tip;
|
||||
}
|
||||
|
||||
public void setTip(String tip) {
|
||||
this.tip = tip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setContent(tip);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
tip = payload.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Tip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class TypingMessageContent extends MessageContent {
|
||||
public static final int TYPING_TEXT = 0;
|
||||
public static final int TYPING_VOICE = 1;
|
||||
public static final int TYPING_CAMERA = 2;
|
||||
public static final int TYPING_LOCATION = 3;
|
||||
public static final int TYPING_FILE = 4;
|
||||
|
||||
private int typingType;
|
||||
|
||||
public TypingMessageContent() {
|
||||
}
|
||||
|
||||
public TypingMessageContent(int typingType) {
|
||||
this.typingType = typingType;
|
||||
}
|
||||
|
||||
public int getTypingType() {
|
||||
return typingType;
|
||||
}
|
||||
|
||||
public void setTypingType(int typingType) {
|
||||
this.typingType = typingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Typing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Transparent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setContent(typingType + "");
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
typingType = Integer.parseInt(payload.getContent());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
|
||||
public class UnknownMessageContent extends MessageContent {
|
||||
private MessagePayload orignalPayload;
|
||||
|
||||
//必须有个空的构造函数
|
||||
public UnknownMessageContent() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
return orignalPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
this.orignalPayload = payload;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.messagecontent;
|
||||
|
||||
import cn.wildfirechat.pojos.MessagePayload;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
|
||||
/**
|
||||
* Created by heavyrain lee on 2017/12/6.
|
||||
*
|
||||
* @refactor dhl
|
||||
* 添加小视频的宽高,时长
|
||||
*/
|
||||
|
||||
|
||||
public class VideoMessageContent extends MediaMessageContent {
|
||||
private byte[] thumbnailBytes;
|
||||
private long duration ;
|
||||
|
||||
//必须有个空的构造函数
|
||||
public VideoMessageContent() {
|
||||
}
|
||||
|
||||
public VideoMessageContent setThumbnailBytes(byte[] thumbnailBytes) {
|
||||
this.thumbnailBytes = thumbnailBytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] getThumbnailBytes() {
|
||||
return thumbnailBytes;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentType() {
|
||||
return ProtoConstants.ContentType.Video;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPersistFlag() {
|
||||
return ProtoConstants.PersistFlag.Persist_And_Count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessagePayload encode() {
|
||||
MessagePayload payload = super.encode();
|
||||
payload.setSearchableContent("[视频]");
|
||||
|
||||
payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));
|
||||
|
||||
JSONObject objWrite = new JSONObject();
|
||||
objWrite.put("d", duration);
|
||||
objWrite.put("duration", duration);
|
||||
payload.setContent(objWrite.toJSONString());
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(MessagePayload payload) {
|
||||
super.decode(payload);
|
||||
thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());
|
||||
try {
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent());
|
||||
if(jsonObject.containsKey("d")) {
|
||||
duration = (long) jsonObject.get("d");
|
||||
} else {
|
||||
duration = (long) jsonObject.get("duration");
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaType() {
|
||||
return ProtoConstants.MessageMediaType.VIDEO;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package cn.wildfirechat.sdk.model;
|
||||
|
||||
import cn.wildfirechat.pojos.Conversation;
|
||||
import cn.wildfirechat.sdk.messagecontent.MessageContent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Message {
|
||||
public Conversation conversation;
|
||||
public MessageContent content;
|
||||
public long messageUid;
|
||||
public String sender;
|
||||
public long serverTime;
|
||||
public List<String> toUsers;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2020 WildFireChat. All rights reserved.
|
||||
*/
|
||||
|
||||
package cn.wildfirechat.sdk.model;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class QuoteInfo {
|
||||
private long messageUid;
|
||||
private String userId;
|
||||
private String userDisplayName;
|
||||
private String messageDigest;
|
||||
|
||||
public long getMessageUid() {
|
||||
return messageUid;
|
||||
}
|
||||
|
||||
public void setMessageUid(long messageUid) {
|
||||
this.messageUid = messageUid;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserDisplayName() {
|
||||
return userDisplayName;
|
||||
}
|
||||
|
||||
public void setUserDisplayName(String userDisplayName) {
|
||||
this.userDisplayName = userDisplayName;
|
||||
}
|
||||
|
||||
public String getMessageDigest() {
|
||||
return messageDigest;
|
||||
}
|
||||
|
||||
public void setMessageDigest(String messageDigest) {
|
||||
this.messageDigest = messageDigest;
|
||||
}
|
||||
|
||||
public JSONObject encode() {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("u", messageUid);
|
||||
object.put("i", userId);
|
||||
object.put("n", userDisplayName);
|
||||
object.put("d", messageDigest);
|
||||
return object;
|
||||
}
|
||||
|
||||
public void decode(JSONObject object) {
|
||||
messageUid = (long) object.get("u");
|
||||
userId = (String) object.get("i");
|
||||
userDisplayName = (String) object.get("n");
|
||||
messageDigest = (String) object.get("d");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.wildfirechat.sdk.utilities;
|
||||
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.sdk.model.IMResult;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -37,11 +38,24 @@ public class AdminHttpUtils extends JsonUtils {
|
||||
private static CloseableHttpClient httpClient;
|
||||
|
||||
public static void init(String url, String secret) {
|
||||
adminUrl = url;
|
||||
adminSecret = secret;
|
||||
init(url, secret, 15000);
|
||||
}
|
||||
|
||||
public static void init(String url, String secret, int timeout) {
|
||||
adminUrl = url.trim();
|
||||
adminSecret = secret.trim();
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
cm.setValidateAfterInactivity(1000);
|
||||
int connectTimeout = 15000; // 连接超时时间
|
||||
int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(connectTimeout)
|
||||
.setSocketTimeout(timeout)
|
||||
.setConnectionRequestTimeout(connectionRequestTimeout)
|
||||
.build();
|
||||
|
||||
httpClient = HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setConnectionManager(cm)
|
||||
.evictExpiredConnections()
|
||||
.evictIdleConnections(60L, TimeUnit.SECONDS)
|
||||
@@ -157,7 +171,15 @@ public class AdminHttpUtils extends JsonUtils {
|
||||
LOG.info("Request error: " + statusCode + " error msg:" + content);
|
||||
throw new Exception("Http request error with code:" + statusCode);
|
||||
} else {
|
||||
return fromJsonObject(content, clazz);
|
||||
IMResult<T> result = fromJsonObject(content, clazz);
|
||||
if(result != null){
|
||||
if(result.getErrorCode() == ErrorCode.ERROR_CODE_AUTH_FAILURE) {
|
||||
LOG.error("鉴权失败,IM服务地址或者密钥配置错误,请检查IM服务{}的配置文件中的http.admin.secret_key是否是{}", adminUrl, adminSecret);
|
||||
} else if(result.getErrorCode() == ErrorCode.ERROR_CODE_SIGN_EXPIRED) {
|
||||
LOG.error("时间验证失败,请确保当前服务和IM服务{}的时间是一致的", adminUrl);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
@@ -35,12 +36,21 @@ public class ChannelHttpUtils extends JsonUtils {
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
public ChannelHttpUtils(String imurl, String channelId, String secret) {
|
||||
this.imurl = imurl;
|
||||
this.channelId = channelId;
|
||||
this.channelSecret = secret;
|
||||
this.imurl = imurl.trim();
|
||||
this.channelId = channelId.trim();
|
||||
this.channelSecret = secret.trim();
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
cm.setValidateAfterInactivity(1000);
|
||||
int connectTimeout = 5000; // 连接超时时间
|
||||
int socketTimeout = 15000; // 请求超时时间
|
||||
int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(connectTimeout)
|
||||
.setSocketTimeout(socketTimeout)
|
||||
.setConnectionRequestTimeout(connectionRequestTimeout)
|
||||
.build();
|
||||
httpClient = HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setConnectionManager(cm)
|
||||
.evictExpiredConnections()
|
||||
.evictIdleConnections(60L, TimeUnit.SECONDS)
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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.sdk.utilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* 获取同一路径下所有子类或接口实现类
|
||||
*
|
||||
* @param cls
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException,
|
||||
ClassNotFoundException {
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
for (Class<?> c : getClasses(cls)) {
|
||||
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
|
||||
classes.add(c);
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前类路径下的所有类
|
||||
*
|
||||
* @param cls
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static List<Class<?>> getClasses(Class<?> cls) throws IOException,
|
||||
ClassNotFoundException {
|
||||
String pk = cls.getPackage().getName();
|
||||
// String path = pk.replace('.', '/');
|
||||
// ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
// URL url = classloader.getResource(path);
|
||||
// String type = url.getProtocol();
|
||||
//
|
||||
// System.out.println("the type is " + type);
|
||||
// System.out.println(url.getPath());
|
||||
//
|
||||
// return getClasses(new File(url.getFile()), pk);
|
||||
List<String> classNames = getClassName(pk, true);
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (String className :
|
||||
classNames) {
|
||||
if (className.endsWith(".class")) {
|
||||
className = className.substring(0, className.length() - 6);
|
||||
className = className.substring(className.lastIndexOf("/")+1, className.length());
|
||||
}
|
||||
|
||||
classes.add(Class.forName(className));
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代查找类
|
||||
*
|
||||
* @param dir
|
||||
* @param pk
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {
|
||||
System.out.println(dir.getAbsolutePath());
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
if (!dir.exists()) {
|
||||
return classes;
|
||||
}
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.isDirectory()) {
|
||||
classes.addAll(getClasses(f, pk + "." + f.getName()));
|
||||
}
|
||||
String name = f.getName();
|
||||
if (name.endsWith(".class")) {
|
||||
classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6)));
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取某包下所有类
|
||||
* @param packageName 包名
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
public static List<String> getClassName(String packageName, boolean childPackage) {
|
||||
List<String> fileNames = null;
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
String packagePath = packageName.replace(".", "/");
|
||||
URL url = loader.getResource(packagePath);
|
||||
if (url != null) {
|
||||
String type = url.getProtocol();
|
||||
if (type.equals("file")) {
|
||||
fileNames = getClassNameByFile(url.getPath(), null, childPackage);
|
||||
} else if (type.equals("jar")) {
|
||||
fileNames = getClassNameByJar(url.getPath(), childPackage);
|
||||
}
|
||||
} else {
|
||||
fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage);
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从项目文件获取某包下所有类
|
||||
* @param filePath 文件路径
|
||||
* @param className 类名集合
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) {
|
||||
List<String> myClassName = new ArrayList<String>();
|
||||
File file = new File(filePath);
|
||||
File[] childFiles = file.listFiles();
|
||||
for (File childFile : childFiles) {
|
||||
if (childFile.isDirectory()) {
|
||||
if (childPackage) {
|
||||
myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage));
|
||||
}
|
||||
} else {
|
||||
String childFilePath = childFile.getPath();
|
||||
if (childFilePath.endsWith(".class")) {
|
||||
if (childFilePath.indexOf("\\classes") >= 0 || childFilePath.indexOf("/classes") >= 0) {
|
||||
int start = childFilePath.indexOf("\\classes");
|
||||
if (start == -1) {
|
||||
start = childFilePath.indexOf("/classes");
|
||||
}
|
||||
childFilePath = childFilePath.substring(start + 9, childFilePath.lastIndexOf("."));
|
||||
}
|
||||
childFilePath = childFilePath.replace("\\", ".");
|
||||
childFilePath = childFilePath.replace("/", ".");
|
||||
myClassName.add(childFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jar获取某包下所有类
|
||||
* @param jarPath jar文件路径
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
private static List<String> getClassNameByJar(String jarPath, boolean childPackage) {
|
||||
List<String> myClassName = new ArrayList<String>();
|
||||
String[] jarInfo = jarPath.split("!");
|
||||
String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/"));
|
||||
String packagePath = jarInfo[1].substring(1);
|
||||
try {
|
||||
JarFile jarFile = new JarFile(jarFilePath);
|
||||
Enumeration<JarEntry> entrys = jarFile.entries();
|
||||
while (entrys.hasMoreElements()) {
|
||||
JarEntry jarEntry = entrys.nextElement();
|
||||
String entryName = jarEntry.getName();
|
||||
|
||||
if (entryName.endsWith(".class")) {
|
||||
if (childPackage) {
|
||||
if (entryName.startsWith(packagePath)) {
|
||||
entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
|
||||
myClassName.add(entryName);
|
||||
}
|
||||
} else {
|
||||
int index = entryName.lastIndexOf("/");
|
||||
String myPackagePath;
|
||||
if (index != -1) {
|
||||
myPackagePath = entryName.substring(0, index);
|
||||
} else {
|
||||
myPackagePath = entryName;
|
||||
}
|
||||
if (myPackagePath.equals(packagePath)) {
|
||||
entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
|
||||
myClassName.add(entryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从所有jar中搜索该包,并获取该包下所有类
|
||||
* @param urls URL集合
|
||||
* @param packagePath 包路径
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
private static List<String> getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) {
|
||||
List<String> myClassName = new ArrayList<String>();
|
||||
if (urls != null) {
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
URL url = urls[i];
|
||||
String urlPath = url.getPath();
|
||||
// 不必搜索classes文件夹
|
||||
if (urlPath.endsWith("classes/")) {
|
||||
continue;
|
||||
}
|
||||
String jarPath = urlPath + "!/" + packagePath;
|
||||
myClassName.addAll(getClassNameByJar(jarPath, childPackage));
|
||||
}
|
||||
}
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
@@ -36,12 +37,21 @@ public class RobotHttpUtils extends JsonUtils {
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
public RobotHttpUtils(String url, String robotId, String robotSecret) {
|
||||
this.url = url;
|
||||
this.robotId = robotId;
|
||||
this.robotSecret = robotSecret;
|
||||
this.url = url.trim();
|
||||
this.robotId = robotId.trim();
|
||||
this.robotSecret = robotSecret.trim();
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
cm.setValidateAfterInactivity(1000);
|
||||
int connectTimeout = 5000; // 连接超时时间
|
||||
int socketTimeout = 15000; // 请求超时时间
|
||||
int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(connectTimeout)
|
||||
.setSocketTimeout(socketTimeout)
|
||||
.setConnectionRequestTimeout(connectionRequestTimeout)
|
||||
.build();
|
||||
httpClient = HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setConnectionManager(cm)
|
||||
.evictExpiredConnections()
|
||||
.evictIdleConnections(60L, TimeUnit.SECONDS)
|
||||
|
||||
Reference in New Issue
Block a user