Compare commits

..
11 Commits
22 changed files with 153 additions and 52 deletions
+17 -2
View File
@@ -111,7 +111,7 @@ friend.disable_search false
##禁止按照昵称搜索用户。 ##禁止按照昵称搜索用户。
friend.disable_nick_name_search false friend.disable_nick_name_search false
##禁止发送好友邀请,通过server api添加好友不受此限制 ##禁止发送好友邀请,通过server api添加好友不受此限制(force参数需要为true)
friend.disable_friend_request false friend.disable_friend_request false
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制 ##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制
@@ -154,6 +154,20 @@ group.visible_quit_or_kickoff_notification 0
# 因此需要分段多次同步,此开关定义了每次同步的数据的条数。此需要客户端支持,客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。 # 因此需要分段多次同步,此开关定义了每次同步的数据的条数。此需要客户端支持,客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。
#sync.data_part_size 1000 #sync.data_part_size 1000
#*********************************************************************
# 限频配置
#*********************************************************************
##API接口限频设置,时间是10秒内允许的请求次数。
##管理api频率限制,默认是10秒10000次。
http.admin.rate_limit 10000
##机器人api频率限制,默认是10秒1000次,按照机器人ID区分。
http.robot.rate_limit 1000
##频道api频率限制,默认是10秒1000次,按照频道ID区分。
http.channel.rate_limit 1000
##客户端请求频率限制,默认是5秒100次。通常情况下不要修改这个值。
client.request_rate_limit 100
#********************************************************************* #*********************************************************************
# hazelcase configuration # hazelcase configuration
#********************************************************************* #*********************************************************************
@@ -163,7 +177,8 @@ hazelcast.configuration config/hazelcast.xml
# Media server configuration # Media server configuration
#********************************************************************* #*********************************************************************
##是否使用七牛云存储。1使用七牛;0使用内存文件服务器。默认的七牛账户信息不可用,请在七牛官网申请账户并配置 ##是否使用七牛云存储。1使用七牛;0使用内存文件服务器。默认的七牛账户信息不可用,请在七牛官网申请账户并配置
##配置使用七牛请参考:https://docs.wildfirechat.cn/server/media_server.html ##专业版另外支持阿里云存储和野火私有存储,关于野火私有存储请参考:https://github.com/wildfirechat/WF-minio
##关于对象存储的详细信息请参考:https://docs.wildfirechat.cn/server/oss.html
media.server.use_qiniu 0 media.server.use_qiniu 0
##媒体类型分类 ##媒体类型分类
+1 -1
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath> <relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId> <artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId> <groupId>cn.wildfirechat</groupId>
<version>0.73</version> <version>0.75</version>
</parent> </parent>
<artifactId>moquette-broker</artifactId> <artifactId>moquette-broker</artifactId>
@@ -13,6 +13,7 @@ import com.xiaoleilu.loServer.RestResult;
import com.xiaoleilu.loServer.annotation.RequireAuthentication; import com.xiaoleilu.loServer.annotation.RequireAuthentication;
import com.xiaoleilu.loServer.handler.Request; import com.xiaoleilu.loServer.handler.Request;
import com.xiaoleilu.loServer.handler.Response; import com.xiaoleilu.loServer.handler.Response;
import io.moquette.server.config.IConfig;
import io.moquette.spi.IMessagesStore; import io.moquette.spi.IMessagesStore;
import io.moquette.spi.ISessionsStore; import io.moquette.spi.ISessionsStore;
import io.moquette.spi.impl.Utils; import io.moquette.spi.impl.Utils;
@@ -21,10 +22,12 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import cn.wildfirechat.common.ErrorCode; import cn.wildfirechat.common.ErrorCode;
import win.liyufan.im.RateLimiter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS; import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
import static io.moquette.BrokerConstants.*;
/** /**
* 请求处理接口<br> * 请求处理接口<br>
@@ -38,6 +41,36 @@ abstract public class Action {
public static ISessionsStore sessionsStore = null; public static ISessionsStore sessionsStore = null;
public ChannelHandlerContext ctx; public ChannelHandlerContext ctx;
protected static RateLimiter adminLimiter = null;
protected static RateLimiter robotLimiter = null;
protected static RateLimiter channelLimiter = null;
public static void init(IConfig config) {
int adminRate = 10000;
int robotRate = 1000;
int channelRate = 1000;
try {
adminRate = Integer.parseInt(config.getProperty(HTTP_ADMIN_RATE_LIMIT, "10000"));
} catch (NumberFormatException e) {
}
try {
robotRate = Integer.parseInt(config.getProperty(HTTP_ROBOT_RATE_LIMIT, "1000"));
} catch (NumberFormatException e) {
}
try {
channelRate = Integer.parseInt(config.getProperty(HTTP_CHANNEL_RATE_LIMIT, "1000"));
} catch (NumberFormatException e) {
}
adminLimiter = new RateLimiter(10, adminRate);
robotLimiter = new RateLimiter(10, robotRate);
channelLimiter = new RateLimiter(10, channelRate);
}
protected class Result { protected class Result {
Object data; Object data;
ErrorCode errorCode; ErrorCode errorCode;
@@ -29,7 +29,6 @@ abstract public class AdminAction extends Action {
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AdminAction.class); private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AdminAction.class);
private static String SECRET_KEY = "123456"; private static String SECRET_KEY = "123456";
private static boolean NO_CHECK_TIME = false; private static boolean NO_CHECK_TIME = false;
private final RateLimiter mLimitCounter = new RateLimiter(10, 500);
public static void setSecretKey(String secretKey) { public static void setSecretKey(String secretKey) {
SECRET_KEY = secretKey; SECRET_KEY = secretKey;
} }
@@ -44,7 +43,7 @@ abstract public class AdminAction extends Action {
@Override @Override
public ErrorCode preAction(Request request, Response response) { public ErrorCode preAction(Request request, Response response) {
if (!mLimitCounter.isGranted("admin")) { if (!adminLimiter.isGranted("admin")) {
return ErrorCode.ERROR_CODE_OVER_FREQUENCY; return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
} }
@@ -88,14 +87,16 @@ abstract public class AdminAction extends Action {
} }
protected void sendResponse(Response response, ErrorCode errorCode, Object data) { protected void sendResponse(Response response, ErrorCode errorCode, Object data) {
response.setStatus(HttpResponseStatus.OK); if(response != null) {
if (errorCode == null) { response.setStatus(HttpResponseStatus.OK);
errorCode = ErrorCode.ERROR_CODE_SUCCESS; if (errorCode == null) {
} errorCode = ErrorCode.ERROR_CODE_SUCCESS;
}
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data); RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);
response.setContent(new Gson().toJson(result)); response.setContent(new Gson().toJson(result));
response.send(); response.send();
}
} }
protected void sendApiMessage(Response response, String fromUser, String topic, byte[] message, ApiCallback callback) { protected void sendApiMessage(Response response, String fromUser, String topic, byte[] message, ApiCallback callback) {
sendApiMessage(response, fromUser, null, topic, message, callback, false); sendApiMessage(response, fromUser, null, topic, message, callback, false);
@@ -12,16 +12,22 @@ import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode; import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputGetFriendList; import cn.wildfirechat.pojos.InputGetFriendList;
import cn.wildfirechat.pojos.InputUpdateAlias; import cn.wildfirechat.pojos.InputUpdateAlias;
import cn.wildfirechat.pojos.OutputCreateChannel;
import cn.wildfirechat.pojos.OutputStringList; import cn.wildfirechat.pojos.OutputStringList;
import cn.wildfirechat.proto.WFCMessage;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.hazelcast.util.StringUtil;
import com.xiaoleilu.loServer.RestResult; import com.xiaoleilu.loServer.RestResult;
import com.xiaoleilu.loServer.annotation.HttpMethod; import com.xiaoleilu.loServer.annotation.HttpMethod;
import com.xiaoleilu.loServer.annotation.Route; import com.xiaoleilu.loServer.annotation.Route;
import com.xiaoleilu.loServer.handler.Request; import com.xiaoleilu.loServer.handler.Request;
import com.xiaoleilu.loServer.handler.Response; import com.xiaoleilu.loServer.handler.Response;
import com.xiaoleilu.loServer.model.FriendData; import com.xiaoleilu.loServer.model.FriendData;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import win.liyufan.im.IMTopic;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -39,8 +45,26 @@ public class AliasPutAction extends AdminAction {
public boolean action(Request request, Response response) { public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) { if (request.getNettyRequest() instanceof FullHttpRequest) {
InputUpdateAlias input = getRequestBody(request.getNettyRequest(), InputUpdateAlias.class); InputUpdateAlias input = getRequestBody(request.getNettyRequest(), InputUpdateAlias.class);
ErrorCode errorCode = messagesStore.setFriendAliasRequest(input.getOperator(), input.getTargetId(), input.getAlias(), new long[1]); if(!StringUtil.isNullOrEmpty(input.getOperator()) && !StringUtil.isNullOrEmpty(input.getTargetId())) {
setResponseContent(RestResult.resultOf(errorCode), response); WFCMessage.AddFriendRequest addFriendRequest = WFCMessage.AddFriendRequest.newBuilder().setTargetUid(input.getTargetId()).setReason(input.getAlias()==null?"":input.getAlias()).build();
sendApiMessage(response, input.getOperator(), IMTopic.SetFriendAliasTopic, addFriendRequest.toByteArray(), result -> {
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(result);
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
byte[] data = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(data);
String channelId = new String(data);
return new Result(ErrorCode.ERROR_CODE_SUCCESS, new OutputCreateChannel(channelId));
} else {
return new Result(errorCode);
}
});
return false;
} else {
ErrorCode errorCode = messagesStore.setFriendAliasRequest(input.getOperator(), input.getTargetId(), input.getAlias(), new long[1]);
setResponseContent(RestResult.resultOf(errorCode), response);
}
} }
return true; return true;
} }
@@ -45,7 +45,7 @@ public class BlockUserAction extends AdminAction {
response.setContent(new Gson().toJson(result)); response.setContent(new Gson().toJson(result));
if (inputUserBlock.getStatus() == 2) { if (inputUserBlock.getStatus() == 2) {
sendApiMessage(response, null, ServerAPIHelper.KICKOFF_USER_REQUEST, inputUserBlock.getUserId().getBytes(), null); sendApiMessage(null, null, ServerAPIHelper.KICKOFF_USER_REQUEST, inputUserBlock.getUserId().getBytes(), null);
} }
sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, null); sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, null);
@@ -31,7 +31,6 @@ import java.util.concurrent.Executor;
abstract public class ChannelAction extends Action { abstract public class ChannelAction extends Action {
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ChannelAction.class); private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ChannelAction.class);
private final RateLimiter mLimitCounter = new RateLimiter(10, 200);
protected WFCMessage.ChannelInfo channelInfo; protected WFCMessage.ChannelInfo channelInfo;
protected interface Callback { protected interface Callback {
@@ -61,7 +60,7 @@ abstract public class ChannelAction extends Action {
return ErrorCode.ERROR_CODE_API_NOT_SIGNED; return ErrorCode.ERROR_CODE_API_NOT_SIGNED;
} }
if (!mLimitCounter.isGranted(cid)) { if (!channelLimiter.isGranted(cid)) {
return ErrorCode.ERROR_CODE_OVER_FREQUENCY; return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
} }
@@ -33,7 +33,6 @@ import java.util.concurrent.Executor;
abstract public class RobotAction extends Action { abstract public class RobotAction extends Action {
protected static final Logger LOG = LoggerFactory.getLogger(RobotAction.class); protected static final Logger LOG = LoggerFactory.getLogger(RobotAction.class);
private final RateLimiter mLimitCounter = new RateLimiter(10, 1000);
protected WFCMessage.Robot robot; protected WFCMessage.Robot robot;
@@ -64,7 +63,7 @@ abstract public class RobotAction extends Action {
return ErrorCode.ERROR_CODE_API_NOT_SIGNED; return ErrorCode.ERROR_CODE_API_NOT_SIGNED;
} }
if (!mLimitCounter.isGranted(rid)) { if (!robotLimiter.isGranted(rid)) {
return ErrorCode.ERROR_CODE_OVER_FREQUENCY; return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
} }
@@ -178,6 +178,10 @@ public final class BrokerConstants {
public static final String MESSAGES_RECALL_TIME_LIMIT = "message.recall_time_limit"; public static final String MESSAGES_RECALL_TIME_LIMIT = "message.recall_time_limit";
public static final String MESSAGES_DISABLE_GROUP_MANAGER_RECALL = "message.disable_group_manager_recall"; public static final String MESSAGES_DISABLE_GROUP_MANAGER_RECALL = "message.disable_group_manager_recall";
public static final String HTTP_ADMIN_RATE_LIMIT = "http.admin.rate_limit";
public static final String HTTP_ROBOT_RATE_LIMIT = "http.robot.rate_limit";
public static final String HTTP_CHANNEL_RATE_LIMIT = "http.channel.rate_limit";
public static final String CLIENT_REQUEST_RATE_LIMIT = "client.request_rate_limit";
private BrokerConstants() { private BrokerConstants() {
} }
@@ -9,6 +9,7 @@
package io.moquette.imhandler; package io.moquette.imhandler;
import cn.wildfirechat.proto.WFCMessage; import cn.wildfirechat.proto.WFCMessage;
import com.xiaoleilu.hutool.system.UserInfo;
import io.moquette.persistence.MemorySessionStore; import io.moquette.persistence.MemorySessionStore;
import io.moquette.spi.impl.Qos1PublishHandler; import io.moquette.spi.impl.Qos1PublishHandler;
import io.moquette.spi.impl.security.TokenAuthenticator; import io.moquette.spi.impl.security.TokenAuthenticator;
@@ -21,6 +22,11 @@ public class GetTokenHandler extends IMHandler<WFCMessage.GetTokenRequest> {
@Override @Override
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.GetTokenRequest request, Qos1PublishHandler.IMCallback callback) { public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.GetTokenRequest request, Qos1PublishHandler.IMCallback callback) {
MemorySessionStore.Session session = m_sessionsStore.updateOrCreateUserSession(fromUser, clientID, request.getPlatform()); MemorySessionStore.Session session = m_sessionsStore.updateOrCreateUserSession(fromUser, clientID, request.getPlatform());
WFCMessage.User userInfo = m_messagesStore.getUserInfo(fromUser);
if(userInfo != null && userInfo.getType() == 1) {
return ErrorCode.ERROR_CODE_ROBOT_NO_TOKEN;
}
TokenAuthenticator authenticator = new TokenAuthenticator(); TokenAuthenticator authenticator = new TokenAuthenticator();
String strToken = authenticator.generateToken(fromUser); String strToken = authenticator.generateToken(fromUser);
String result = strToken + "|" + session.getSecret() + "|" + session.getDbSecret(); String result = strToken + "|" + session.getSecret() + "|" + session.getDbSecret();
@@ -58,8 +58,7 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
builder.setFromUser(request.getTargetUid()); builder.setFromUser(request.getTargetUid());
builder.setConversation(WFCMessage.Conversation.newBuilder().setTarget(fromUser).setLine(0).setType(ProtoConstants.ConversationType.ConversationType_Private).build()); builder.setConversation(WFCMessage.Conversation.newBuilder().setTarget(fromUser).setLine(0).setType(ProtoConstants.ConversationType.ConversationType_Private).build());
builder.setContent(contentBuilder); builder.setContent(contentBuilder);
timestamp = System.currentTimeMillis(); builder.setServerTimestamp(++timestamp);
builder.setServerTimestamp(timestamp);
messageId = MessageShardingUtil.generateId(); messageId = MessageShardingUtil.generateId();
builder.setMessageId(messageId); builder.setMessageId(messageId);
@@ -74,10 +73,8 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
builder.setContent(contentBuilder); builder.setContent(contentBuilder);
messageId = MessageShardingUtil.generateId(); messageId = MessageShardingUtil.generateId();
builder.setMessageId(messageId); builder.setMessageId(messageId);
timestamp = System.currentTimeMillis(); builder.setServerTimestamp(++timestamp);
builder.setServerTimestamp(timestamp);
saveAndPublish(request.getTargetUid(), null, builder.build()); saveAndPublish(request.getTargetUid(), null, builder.build());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -38,6 +38,7 @@ import java.util.*;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_OVER_FREQUENCY; import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_OVER_FREQUENCY;
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS; import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
import static io.moquette.BrokerConstants.CLIENT_REQUEST_RATE_LIMIT;
/** /**
* 请求处理接口<br> * 请求处理接口<br>
@@ -52,7 +53,7 @@ abstract public class IMHandler<T> {
protected static Server mServer = null; protected static Server mServer = null;
protected static MessagesPublisher publisher; protected static MessagesPublisher publisher;
private static ThreadPoolExecutorWrapper m_imBusinessExecutor; private static ThreadPoolExecutorWrapper m_imBusinessExecutor;
private static final RateLimiter mLimitCounter = new RateLimiter(5, 100); private static RateLimiter mLimitCounter;
private Method parseDataMethod; private Method parseDataMethod;
private Class dataCls; private Class dataCls;
@@ -147,12 +148,24 @@ abstract public class IMHandler<T> {
publisher = p; publisher = p;
m_imBusinessExecutor = businessExecutor; m_imBusinessExecutor = businessExecutor;
mServer = server; mServer = server;
int clientRateLimit = 100;
try {
clientRateLimit = Integer.parseInt(server.getConfig().getProperty(CLIENT_REQUEST_RATE_LIMIT, "100"));
} catch (Exception e) {
}
if(clientRateLimit == 0) {
clientRateLimit = 100;
}
mLimitCounter = new RateLimiter(5, clientRateLimit);
} }
public ErrorCode preAction(String clientID, String fromUser, String topic, Qos1PublishHandler.IMCallback callback) { public ErrorCode preAction(String clientID, String fromUser, String topic, Qos1PublishHandler.IMCallback callback, boolean isAdmin, boolean isRobotOrChannel) {
LOG.info("imHandler fromUser={}, clientId={}, topic={}", fromUser, clientID, topic); LOG.info("imHandler fromUser={}, clientId={}, topic={}", fromUser, clientID, topic);
if(!mLimitCounter.isGranted(clientID + fromUser + topic)) { if(!isAdmin && !isRobotOrChannel && !mLimitCounter.isGranted(clientID + fromUser + topic)) {
ByteBuf ackPayload = Unpooled.buffer(); ByteBuf ackPayload = Unpooled.buffer();
ackPayload.ensureWritable(1).writeByte(ERROR_CODE_OVER_FREQUENCY.getCode()); ackPayload.ensureWritable(1).writeByte(ERROR_CODE_OVER_FREQUENCY.getCode());
try { try {
@@ -166,7 +179,7 @@ abstract public class IMHandler<T> {
return ErrorCode.ERROR_CODE_SUCCESS; return ErrorCode.ERROR_CODE_SUCCESS;
} }
public void doHandler(String clientID, String fromUser, String topic, byte[] payloadContent, Qos1PublishHandler.IMCallback callback, boolean isAdmin) { public void doHandler(String clientID, String fromUser, String topic, byte[] payloadContent, Qos1PublishHandler.IMCallback callback, boolean isAdmin, boolean isRobotOrChannel) {
m_imBusinessExecutor.execute(() -> { m_imBusinessExecutor.execute(() -> {
Qos1PublishHandler.IMCallback callbackWrapper = new Qos1PublishHandler.IMCallback() { Qos1PublishHandler.IMCallback callbackWrapper = new Qos1PublishHandler.IMCallback() {
@Override @Override
@@ -177,7 +190,7 @@ abstract public class IMHandler<T> {
} }
}; };
ErrorCode preActionCode = preAction(clientID, fromUser, topic, callbackWrapper); ErrorCode preActionCode = preAction(clientID, fromUser, topic, callbackWrapper, isAdmin, isRobotOrChannel);
if (preActionCode == ErrorCode.ERROR_CODE_SUCCESS) { if (preActionCode == ErrorCode.ERROR_CODE_SUCCESS) {
ByteBuf ackPayload = Unpooled.buffer(1); ByteBuf ackPayload = Unpooled.buffer(1);
@@ -2819,6 +2819,10 @@ public class MemoryMessagesStore implements IMessagesStore {
return ErrorCode.ERROR_CODE_IN_BLACK_LIST; return ErrorCode.ERROR_CODE_IN_BLACK_LIST;
} }
if (friendData1 != null && friendData1.getState() == 0) {
return ErrorCode.ERROR_CODE_ALREADY_FRIENDS;
}
WFCMessage.FriendRequest newRequest = WFCMessage.FriendRequest WFCMessage.FriendRequest newRequest = WFCMessage.FriendRequest
.newBuilder() .newBuilder()
.setFromUid(userId) .setFromUid(userId)
@@ -24,6 +24,7 @@ import com.hazelcast.config.FileSystemXmlConfig;
import com.hazelcast.core.*; import com.hazelcast.core.*;
import com.xiaoleilu.loServer.LoServer; import com.xiaoleilu.loServer.LoServer;
import com.xiaoleilu.loServer.ServerSetting; import com.xiaoleilu.loServer.ServerSetting;
import com.xiaoleilu.loServer.action.Action;
import com.xiaoleilu.loServer.action.admin.AdminAction; import com.xiaoleilu.loServer.action.admin.AdminAction;
import io.moquette.BrokerConstants; import io.moquette.BrokerConstants;
import io.moquette.persistence.*; import io.moquette.persistence.*;
@@ -257,6 +258,7 @@ public class Server {
initMediaServerConfig(config); initMediaServerConfig(config);
Action.init(config);
String monitorEventAddress = config.getProperty(MONITOR_Exception_Event_Address); String monitorEventAddress = config.getProperty(MONITOR_Exception_Event_Address);
Utility.setMonitorEventAddress(monitorEventAddress); Utility.setMonitorEventAddress(monitorEventAddress);
@@ -69,7 +69,6 @@ public class Qos1PublishHandler extends QosPublishHandler {
private final MessagesPublisher publisher; private final MessagesPublisher publisher;
private final ISessionsStore m_sessionStore; private final ISessionsStore m_sessionStore;
private final ThreadPoolExecutorWrapper m_imBusinessExecutor; private final ThreadPoolExecutorWrapper m_imBusinessExecutor;
private final RateLimiter mLimitCounter = new RateLimiter(5, 100);
private HashMap<String, IMHandler> m_imHandlers = new HashMap<>(); private HashMap<String, IMHandler> m_imHandlers = new HashMap<>();
@@ -148,19 +147,6 @@ public class Qos1PublishHandler extends QosPublishHandler {
void imHandler(String clientID, String fromUser, String topic, byte[] payloadContent, IMCallback callback, boolean isAdmin, boolean isRobotOrChannel) { void imHandler(String clientID, String fromUser, String topic, byte[] payloadContent, IMCallback callback, boolean isAdmin, boolean isRobotOrChannel) {
LOG.info("imHandler fromUser={}, topic={}", fromUser, topic); LOG.info("imHandler fromUser={}, topic={}", fromUser, topic);
if(!isAdmin && !isRobotOrChannel && !mLimitCounter.isGranted(clientID + fromUser + topic)) {
ByteBuf ackPayload = Unpooled.buffer();
ackPayload.ensureWritable(1).writeByte(ERROR_CODE_OVER_FREQUENCY.getCode());
try {
callback.onIMHandled(ERROR_CODE_OVER_FREQUENCY, ackPayload);
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
}
LOG.warn("user {} request over frequency", fromUser);
return;
}
IMCallback wrapper = (errorcode, ackPayload) -> { IMCallback wrapper = (errorcode, ackPayload) -> {
ackPayload.resetReaderIndex(); ackPayload.resetReaderIndex();
byte code = ackPayload.readByte(); byte code = ackPayload.readByte();
@@ -215,7 +201,7 @@ public class Qos1PublishHandler extends QosPublishHandler {
IMHandler handler = m_imHandlers.get(topic); IMHandler handler = m_imHandlers.get(topic);
if (handler != null) { if (handler != null) {
handler.doHandler(clientID, fromUser, topic, payloadContent, wrapper, isAdmin); handler.doHandler(clientID, fromUser, topic, payloadContent, wrapper, isAdmin, isRobotOrChannel);
} else { } else {
LOG.error("imHandler unknown topic={}", topic); LOG.error("imHandler unknown topic={}", topic);
ByteBuf ackPayload = Unpooled.buffer(); ByteBuf ackPayload = Unpooled.buffer();
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>wildfirechat-parent</artifactId> <artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId> <groupId>cn.wildfirechat</groupId>
<version>0.73</version> <version>0.75</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -43,6 +43,9 @@ public enum ErrorCode {
ERROR_CODE_ALREADY_FRIENDS(23, "already friends"), ERROR_CODE_ALREADY_FRIENDS(23, "already friends"),
ERROR_CODE_RECALL_TIME_EXPIRED(24, "time expired"), ERROR_CODE_RECALL_TIME_EXPIRED(24, "time expired"),
ERROR_CODE_LOCK_ALREADY_LOCKED(25, "already locked"),
ERROR_CODE_NOT_YOUR_LOCKED(26, "unload failure, not your lock"),
ERROR_CODE_ROBOT_NO_TOKEN(27, "robot no token"),
ERROR_CODE_CONFERENCE_ROOM_NOT_EXIST(60, "conference room not exist"), ERROR_CODE_CONFERENCE_ROOM_NOT_EXIST(60, "conference room not exist"),
ERROR_CODE_USER_NOT_PREPARED(238, "user not prepared"), ERROR_CODE_USER_NOT_PREPARED(238, "user not prepared"),
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>--> <!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId> <artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId> <groupId>cn.wildfirechat</groupId>
<version>0.73</version> <version>0.75</version>
</parent> </parent>
<artifactId>distribution</artifactId> <artifactId>distribution</artifactId>
@@ -106,7 +106,7 @@ friend.disable_search false
##禁止按照昵称搜索用户。 ##禁止按照昵称搜索用户。
friend.disable_nick_name_search false friend.disable_nick_name_search false
##禁止发送好友邀请,通过server api添加好友不受此限制 ##禁止发送好友邀请,通过server api添加好友不受此限制(force参数需要为true)
friend.disable_friend_request false friend.disable_friend_request false
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制 ##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制
@@ -150,6 +150,20 @@ group.visible_quit_or_kickoff_notification 0
# 因此需要分段多次同步,此开关定义了每次同步的数据的条数。此需要客户端支持,客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。 # 因此需要分段多次同步,此开关定义了每次同步的数据的条数。此需要客户端支持,客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。
#sync.data_part_size 1000 #sync.data_part_size 1000
#*********************************************************************
# 限频配置
#*********************************************************************
##API接口限频设置,时间是10秒内允许的请求次数。
##管理api频率限制,默认是10秒10000次。
http.admin.rate_limit 10000
##机器人api频率限制,默认是10秒1000次,按照机器人ID区分。
http.robot.rate_limit 1000
##频道api频率限制,默认是10秒1000次,按照频道ID区分。
http.channel.rate_limit 1000
##客户端请求频率限制,默认是5秒100次。通常情况下不要修改这个值。
client.request_rate_limit 100
#********************************************************************* #*********************************************************************
# hazelcase configuration # hazelcase configuration
#********************************************************************* #*********************************************************************
@@ -159,7 +173,8 @@ hazelcast.configuration config/hazelcast.xml
# Media server configuration # Media server configuration
#********************************************************************* #*********************************************************************
##是否使用七牛云存储。1使用七牛;0使用内存文件服务器。默认的七牛账户信息不可用,请在七牛官网申请账户并配置 ##是否使用七牛云存储。1使用七牛;0使用内存文件服务器。默认的七牛账户信息不可用,请在七牛官网申请账户并配置
##配置使用七牛请参考:https://docs.wildfirechat.cn/server/media_server.html ##专业版另外支持阿里云存储和野火私有存储,关于野火私有存储请参考:https://github.com/wildfirechat/WF-minio
##关于对象存储的详细信息请参考:https://docs.wildfirechat.cn/server/oss.html
media.server.use_qiniu 0 media.server.use_qiniu 0
##媒体类型分类 ##媒体类型分类
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId> <artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>0.73</version> <version>0.75</version>
<name>Wildfire Chat</name> <name>Wildfire Chat</name>
<description>Wildfire Chat Server</description> <description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear> <inceptionYear>2019</inceptionYear>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>wildfirechat-parent</artifactId> <artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId> <groupId>cn.wildfirechat</groupId>
<version>0.73</version> <version>0.75</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -292,7 +292,7 @@ public class Main {
} }
IMResult<Void> result = RelationAdmin.sendFriendRequest("ff1", "ff2", "hello", true); IMResult<Void> result = RelationAdmin.sendFriendRequest("ff1", "ff2", "hello", true);
if (result != null && result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { if (result != null && (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || result.getErrorCode() == ErrorCode.ERROR_CODE_ALREADY_FRIENDS)) {
System.out.println("send friend request success"); System.out.println("send friend request success");
} else { } else {
System.out.println("failure"); System.out.println("failure");
@@ -308,7 +308,7 @@ public class Main {
} }
result = RelationAdmin.sendFriendRequest("ff1", "ff2", "hello3", true); result = RelationAdmin.sendFriendRequest("ff1", "ff2", "hello3", true);
if (result != null && result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { if (result != null && (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || result.getErrorCode() == ErrorCode.ERROR_CODE_ALREADY_FRIENDS)) {
System.out.println("success"); System.out.println("success");
} else { } else {
System.out.println("send friend request success"); System.out.println("send friend request success");