Compare commits

...
16 Commits
Author SHA1 Message Date
heavyrian2012 98388a5129 update version and release note 2025-04-18 20:03:38 +08:00
heavyrian2012 1a89714df9 配置文件中群组标记删除默认开启 2025-04-18 19:59:37 +08:00
heavyrian2012 a855652c26 音视频通话挂断时推送数据包含开始通话的消息UID 2025-04-18 11:12:15 +08:00
heavyrian2012 21aadd9c0b 去掉空的echo 2025-04-14 10:42:26 +08:00
heavyrian2012 5522a8689d server api添加日志 2025-04-13 18:26:07 +08:00
heavyrian2012 bf52a00304 添加配置是否允许发送消息给被封禁用户 2025-04-12 14:00:55 +08:00
heavyrian2012 3349e2a4e5 添加server api发送朋友圈的api 2025-04-12 12:54:34 +08:00
heavyrian2012 70f3f96f7a server sdk添加撤回和删除消息 2025-04-12 09:57:10 +08:00
heavyrian2012 5e9d411f1b 内置存储支持在线播放 2025-04-09 16:40:37 +08:00
heavyrian2012 e74fd0c660 添加配置,转发消息时是否代码发送者信息和目标信息 2025-03-27 20:52:12 +08:00
heavyrian2012 d1232abe39 version and release note 2025-03-05 19:20:54 +08:00
heavyrian2012 1df192f730 解决分段拉取消息时可能丢消息的问题 2025-03-05 19:13:29 +08:00
heavyrian2012 f897e640fc SDK添加超时配置 2025-03-03 12:11:19 +08:00
heavyrian2012 ee6e4f96fb 配置允许撤回消息时间小于等于0时可以允许用户任意时间撤回消息 2025-02-21 19:28:57 +08:00
heavyrian2012 d14dc74566 sdk添加注册消息的接口,可以允许sdk注册自定义消息 2025-02-19 19:27:42 +08:00
heavyrian2012 ff75379779 优化server sdk 2025-02-18 09:53:34 +08:00
51 changed files with 685 additions and 145 deletions
+21
View File
@@ -152,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
+1 -1
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.3</version>
<version>1.3.5</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -36,6 +36,7 @@ public class PushMessage {
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;
@@ -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);
@@ -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);
}
@@ -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
@@ -163,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";
@@ -39,6 +39,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
private int mBlacklistStrategy = 0; //黑名单中时,0失败,1吞掉。
private boolean mBlacklistAllowSend2Black = true;
private boolean mNoForwardAdminMessage = false;
private boolean mAllowSend2ForbiddenUser = false;
private String mRemoteSensitiveServerUrl = null;
private Set<Integer> mRemoteSensitiveMessageTypes;
@@ -101,6 +102,9 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
Utility.printExecption(LOG, e);
}
try {
mAllowSend2ForbiddenUser = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER, "false"));
} catch (Exception e) {}
}
private void parseTypes(Collection<Integer> collection, String types) {
@@ -170,9 +174,11 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
}
}
userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());
if (userStatus == ProtoConstants.UserStatus.Forbidden) {
return ErrorCode.ERROR_CODE_USER_FORBIDDEN;
if (!mAllowSend2ForbiddenUser) {
userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());
if (userStatus == ProtoConstants.UserStatus.Forbidden) {
return ErrorCode.ERROR_CODE_USER_FORBIDDEN;
}
}
}
@@ -217,20 +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) {
@@ -239,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;
@@ -256,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)) {
@@ -205,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<>();
@@ -608,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"));
@@ -620,17 +632,27 @@ 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);
@@ -900,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();
@@ -933,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;
}
@@ -2454,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;
@@ -4724,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;
@@ -242,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());
}
}
@@ -486,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);
@@ -530,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())) {
@@ -545,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())) {
@@ -667,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;
@@ -678,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);
@@ -733,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);
@@ -752,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);
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.3</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";
@@ -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);
}
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.3</version>
<version>1.3.5</version>
</parent>
<artifactId>distribution</artifactId>
@@ -147,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
@@ -224,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不受影响。
@@ -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
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>1.3.3</version>
<version>1.3.5</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
+16
View File
@@ -12,6 +12,22 @@
# 更新记录
--------------
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. 转移群组时检查新群主是否在群中。
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>1.3.3</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);
File diff suppressed because one or more lines are too long
@@ -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);
}
}
@@ -32,7 +32,7 @@ public class ArticlesMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(topArticle.title);
JSONObject object = new JSONObject();
@@ -53,6 +53,7 @@ public class ArticlesMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
try {
super.decode(payload);
JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
JSONObject topObj = (JSONObject) object.get("top");
this.topArticle = Article.fromJson(topObj);
@@ -133,7 +133,7 @@ public class CallStartMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(callId);
payload.setPushContent("音视频通话邀请");
@@ -175,6 +175,7 @@ public class CallStartMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
callId = payload.getContent();
try {
@@ -100,7 +100,7 @@ public class CardMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(target);
JSONObject objWrite = new JSONObject();
objWrite.put("t", type);
@@ -116,6 +116,7 @@ public class CardMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
target = payload.getContent();
try {
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
@@ -0,0 +1,47 @@
package cn.wildfirechat.sdk.messagecontent;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class DeleteMessageContent extends MessageContent {
private long messageId;
private String operatorId;
//必须有个空的构造函数
public DeleteMessageContent() {
}
public long getMessageId() {
return messageId;
}
public String getOperatorId() {
return operatorId;
}
@Override
public int getContentType() {
return ProtoConstants.ContentType.Delete;
}
@Override
public int getPersistFlag() {
return ProtoConstants.PersistFlag.Not_Persist;
}
@Override
public MessagePayload encode() {
throw new RuntimeException("Delete message cannot encode");
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
operatorId = payload.getContent();
messageId = Long.parseLong(new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8));
}
}
@@ -26,7 +26,7 @@ public class FileMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(name);
payload.setContent(size + "");
@@ -51,7 +51,7 @@ public class FileMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
if (payload.getSearchableContent().startsWith(FILE_NAME_PREFIX)) {
name = payload.getSearchableContent().substring(payload.getSearchableContent().indexOf(FILE_NAME_PREFIX) + FILE_NAME_PREFIX.length());
@@ -34,7 +34,7 @@ public class ImageMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent("[图片]");
payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));
@@ -44,7 +44,7 @@ public class ImageMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());
}
@@ -72,9 +72,7 @@ public class LinkMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(title);
JSONObject objWrite = new JSONObject();
objWrite.put("d", contentDigest);
@@ -88,9 +86,8 @@ public class LinkMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
title = payload.getSearchableContent();
try {
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
@@ -66,7 +66,7 @@ public class LocationMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(title);
payload.setBase64edData(Base64.getEncoder().encodeToString(this.thumbnailByte));
@@ -82,6 +82,7 @@ public class LocationMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {
this.thumbnailByte = Base64.getDecoder().decode(payload.getBase64edData());
}
@@ -14,12 +14,18 @@ abstract public class MediaMessageContent extends MessageContent {
}
@Override
protected MessagePayload encodeBase() {
MessagePayload payload = super.encodeBase();
public MessagePayload encode() {
MessagePayload payload = super.encode();
payload.setRemoteMediaUrl(remoteMediaUrl);
payload.setMediaType(getMediaType());
return payload;
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
remoteMediaUrl = payload.getRemoteMediaUrl();
}
protected abstract int getMediaType();
}
@@ -22,7 +22,7 @@ public abstract class MessageContent {
return this;
}
protected MessagePayload encodeBase() {
public MessagePayload encode() {
MessagePayload payload = new MessagePayload();
payload.setType(getContentType());
payload.setPersistFlag(getPersistFlag());
@@ -32,13 +32,11 @@ public abstract class MessageContent {
return payload;
}
protected void decodeBase(MessagePayload payload) {
protected void decode(MessagePayload payload) {
this.mentionedType = payload.getMentionedType();
this.mentionedTargets = payload.getMentionedTarget();
this.extra = payload.getExtra();
}
abstract public int getContentType();
abstract public int getPersistFlag();
abstract public MessagePayload encode();
abstract public void decode(MessagePayload payload);
}
@@ -12,7 +12,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class MessageContentFactory {
private static final Map<Integer, Class<MessageContent>> contentClassMap = new ConcurrentHashMap<>();
private static final Map<Integer, Class<? extends MessageContent>> contentClassMap = new ConcurrentHashMap<>();
static {
registerAllMessageContent();
@@ -36,7 +36,7 @@ public class MessageContentFactory {
}
public static MessageContent decodeMessageContent(MessagePayload messagePayload) {
Class<MessageContent> cls = contentClassMap.get(messagePayload.getType());
Class<? extends MessageContent> cls = contentClassMap.get(messagePayload.getType());
MessageContent messageContent;
if(cls != null) {
try {
@@ -49,11 +49,15 @@ public class MessageContentFactory {
} else {
messageContent = new UnknownMessageContent();
}
messageContent.decodeBase(messagePayload);
messageContent.decode(messagePayload);
return messageContent;
}
public static void registerCustomMessageContent(Class<? extends MessageContent> cls) throws Exception {
MessageContent content = cls.newInstance();
contentClassMap.put(content.getContentType(), cls);
}
private static void registerAllMessageContent() {
try {
for (Class cls : ClassUtil.getAllAssignedClass(MessageContent.class)) {
@@ -43,7 +43,7 @@ public class MultiCallOngoingMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(callId);
JSONObject object = new JSONObject();
object.put("initiator", this.initiator);
@@ -60,6 +60,7 @@ public class MultiCallOngoingMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
this.callId = payload.getContent();
try {
JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
@@ -57,7 +57,7 @@ public class NotDeliveredMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
JSONObject obj = new JSONObject();
obj.put("mid", this.messageUid);
obj.put("all", this.allFailure);
@@ -74,7 +74,7 @@ public class NotDeliveredMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
try {
super.decode(payload);
JSONObject obj = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
this.messageUid = (long) obj.get("mid");
this.allFailure = (boolean) obj.get("all");
@@ -0,0 +1,122 @@
package cn.wildfirechat.sdk.messagecontent;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.proto.ProtoConstants;
import org.apache.http.util.TextUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class RecallMessageContent extends MessageContent {
private long messageId;
private String operatorId;
private String originalSender;
private int originalContentType;
private String originalSearchableContent;
private String originalContent;
private String originalExtra;
private byte[] originalBinaryContent;
private int originalMediaType;
private String originalMediaUrl;
private long originalMessageTimestamp;
//必须有个空的构造函数
public RecallMessageContent() {
}
public long getMessageId() {
return messageId;
}
public String getOperatorId() {
return operatorId;
}
public String getOriginalSender() {
return originalSender;
}
public int getOriginalContentType() {
return originalContentType;
}
public String getOriginalSearchableContent() {
return originalSearchableContent;
}
public String getOriginalContent() {
return originalContent;
}
public String getOriginalExtra() {
return originalExtra;
}
public long getOriginalMessageTimestamp() {
return originalMessageTimestamp;
}
public byte[] getOriginalBinaryContent() {
return originalBinaryContent;
}
public int getOriginalMediaType() {
return originalMediaType;
}
public String getOriginalMediaUrl() {
return originalMediaUrl;
}
@Override
public int getContentType() {
return ProtoConstants.ContentType.Recall;
}
@Override
public int getPersistFlag() {
return ProtoConstants.PersistFlag.Persist;
}
@Override
public MessagePayload encode() {
throw new RuntimeException("Recall message cannot encode");
}
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
operatorId = payload.getContent();
messageId = Long.parseLong(new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8));
if(!TextUtils.isEmpty(payload.getExtra())) {
try {
JSONObject dictionary = (JSONObject) new JSONParser().parse(payload.getExtra());
originalSender = (String) dictionary.get("s");
if (dictionary.containsKey("t")) {
originalContentType = ((Number) dictionary.get("t")).intValue();
}
originalSearchableContent = (String) dictionary.get("sc");
originalContent = (String) dictionary.get("c");
originalExtra = (String) dictionary.get("e");
if (dictionary.containsKey("ts")) {
originalMessageTimestamp = ((Number) dictionary.get("ts")).longValue();
}
if (dictionary.containsKey("mt")) {
originalMediaType = ((Number) dictionary.get("mt")).intValue();
}
originalMediaUrl = (String) dictionary.get("mu");
if (dictionary.containsKey("mb")) {
originalBinaryContent = Base64.getDecoder().decode((String) dictionary.get("mb"));
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -89,7 +89,7 @@ public class RichNotificationMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setPushContent(title);
payload.setContent(desc);
JSONObject jsonObject = new JSONObject();
@@ -113,5 +113,6 @@ public class RichNotificationMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
}
}
@@ -35,11 +35,12 @@ public class SoundMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
}
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
JSONObject jsonObject = new JSONObject();
jsonObject.put("duration", duration);
payload.setContent(jsonObject.toJSONString());
@@ -34,7 +34,7 @@ public class StickerMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent("[动态表情]");
JSONObject objWrite = new JSONObject();
objWrite.put("x", width);
@@ -47,8 +47,7 @@ public class StickerMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
try {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));
width = (int) jsonObject.get("x");
@@ -38,13 +38,14 @@ public class StreamTextGeneratedMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
this.streamId = payload.getContent();
this.text = payload.getSearchableContent();
}
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(text);
payload.setContent(streamId);
return payload;
@@ -38,13 +38,14 @@ public class StreamTextGeneratingMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decode(payload);
streamId = payload.getContent();
text = payload.getSearchableContent();
}
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(text);
payload.setContent(streamId);
return payload;
@@ -56,7 +56,7 @@ public class TextMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent(text);
if(quoteInfo != null) {
payload.setBase64edData(Base64.getEncoder().encodeToString(quoteInfo.encode().toJSONString().getBytes(StandardCharsets.UTF_8)));
@@ -66,6 +66,7 @@ public class TextMessageContent extends MessageContent {
@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);
@@ -24,7 +24,7 @@ public class TipNotificationMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(tip);
return payload;
@@ -32,7 +32,7 @@ public class TipNotificationMessageContent extends MessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
tip = payload.getContent();
}
@@ -43,14 +43,14 @@ public class TypingMessageContent extends MessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setContent(typingType + "");
return payload;
}
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
typingType = Integer.parseInt(payload.getContent());
}
}
@@ -58,7 +58,7 @@ public class VideoMessageContent extends MediaMessageContent {
@Override
public MessagePayload encode() {
MessagePayload payload = super.encodeBase();
MessagePayload payload = super.encode();
payload.setSearchableContent("[视频]");
payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));
@@ -73,7 +73,7 @@ public class VideoMessageContent extends MediaMessageContent {
@Override
public void decode(MessagePayload payload) {
super.decodeBase(payload);
super.decode(payload);
thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());
try {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent());
@@ -38,11 +38,24 @@ public class AdminHttpUtils extends JsonUtils {
private static CloseableHttpClient httpClient;
public static void init(String url, String 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)
@@ -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;
@@ -40,7 +41,16 @@ public class ChannelHttpUtils extends JsonUtils {
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)
@@ -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;
@@ -41,7 +42,16 @@ public class RobotHttpUtils extends JsonUtils {
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)