Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c74cddc387 | ||
|
|
b2e4fd9546 | ||
|
|
9e8c364642 | ||
|
|
8127ec03ad | ||
|
|
c02e9066be | ||
|
|
ffd1492ea2 | ||
|
|
5e9bbcb1e9 | ||
|
|
63770c75fa | ||
|
|
bf0eb5b8aa | ||
|
|
8cbf66930f | ||
|
|
ce48f67b04 |
@@ -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
@@ -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
@@ -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"),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
##媒体类型分类
|
##媒体类型分类
|
||||||
|
|||||||
@@ -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
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user