Compare commits

...
13 Commits
40 changed files with 624 additions and 37 deletions
+6
View File
@@ -90,6 +90,12 @@
<map name="user_chatroom">
</map>
<multimap name="chatroom_black">
</multimap>
<multimap name="chatroom_manager">
</multimap>
<map name="robots">
<!-- 7 days -->
<time-to-live-seconds>604800</time-to-live-seconds>
+18 -2
View File
@@ -67,10 +67,19 @@ message.max_queue 1024
##是否禁止陌生人聊天
message.disable_stranger_chat false
##黑名单处理策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃;
##黑名单处理策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃;2 敏感词替换为***;3 不处理。
##所有命中敏感词的消息都会被记录在敏感词消息表中
message.blacklist.strategy 0
##禁止搜索用户
friend.disable_search false
##禁止按照昵称搜索用户。
friend.disable_nick_name_search false
##禁止发送好友邀请,通过server api添加好友不受此限制
friend.disable_friend_request false
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制
friend.repeat_request_duration 604800000
@@ -120,6 +129,10 @@ qiniu.bucket_video_name media
qiniu.bucket_video_domain http://pghnpyzos.bkt.clouddn.com
qiniu.bucket_file_name media
qiniu.bucket_file_domain http://pghnpyzos.bkt.clouddn.com
qiniu.bucket_sticker_name media
qiniu.bucket_sticker_domain http://pghnpyzos.bkt.clouddn.com
qiniu.bucket_moments_name media
qiniu.bucket_moments_domain http://pghnpyzos.bkt.clouddn.com
qiniu.bucket_portrait_name storage
qiniu.bucket_portrait_domain http://cdn2.wildfirechat.cn
qiniu.bucket_favorite_name storage
@@ -133,6 +146,9 @@ local.media.storage.root media
# 是否支持多端登陆
server.multi_endpoint false
# 多平台连接状态通知(仅当multi_endpoint为false时有效)
server.multi_platform_notification false
#*********************************************************************
# Push server configuration
#*********************************************************************
@@ -0,0 +1,22 @@
DROP TABLE IF EXISTS `t_chatroom_blacklist`;
CREATE TABLE `t_chatroom_blacklist` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`_cid` varchar(64) NOT NULL,
`_uid` varchar(64) NOT NULL,
`_state` tinyint NOT NULL DEFAULT 0,
`_expired_time` bigint(20) NOT NULL,
`_dt` bigint(20) NOT NULL,
UNIQUE INDEX `cr_bl_uid_index` (`_cid`,_uid)
);
DROP TABLE IF EXISTS `t_chatroom_manager`;
CREATE TABLE `t_chatroom_manager` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`_cid` varchar(64) NOT NULL,
`_uid` varchar(64) NOT NULL,
`_state` tinyint NOT NULL DEFAULT 0,
`_dt` bigint(20) NOT NULL,
UNIQUE INDEX `cr_man_uid_index` (`_cid`,_uid)
);
@@ -0,0 +1,30 @@
DROP TABLE IF EXISTS `t_chatroom_blacklist`;
CREATE TABLE `t_chatroom_blacklist` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`_cid` varchar(64) NOT NULL,
`_uid` varchar(64) NOT NULL,
`_state` tinyint NOT NULL DEFAULT 0,
`_expired_time` bigint(20) NOT NULL,
`_dt` bigint(20) NOT NULL,
UNIQUE INDEX `cr_bl_uid_index` (`_cid`,_uid)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `t_chatroom_manager`;
CREATE TABLE `t_chatroom_manager` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`_cid` varchar(64) NOT NULL,
`_uid` varchar(64) NOT NULL,
`_state` tinyint NOT NULL DEFAULT 0,
`_dt` bigint(20) NOT NULL,
UNIQUE INDEX `cr_man_uid_index` (`_cid`,_uid)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
+2 -2
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.39</version>
<version>0.40</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -48,7 +48,7 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
<version>8.0.19</version>
</dependency>
<dependency>
@@ -77,6 +77,10 @@ public final class BrokerConstants {
public static final String QINIU_BUCKET_VIDEO_DOMAIN = "qiniu.bucket_video_domain";
public static final String QINIU_BUCKET_FILE_NAME= "qiniu.bucket_file_name";
public static final String QINIU_BUCKET_FILE_DOMAIN = "qiniu.bucket_file_domain";
public static final String QINIU_BUCKET_STICKER_NAME= "qiniu.bucket_sticker_name";
public static final String QINIU_BUCKET_STICKER_DOMAIN = "qiniu.bucket_sticker_domain";
public static final String QINIU_BUCKET_MOMENTS_NAME= "qiniu.bucket_moments_name";
public static final String QINIU_BUCKET_MOMENTS_DOMAIN = "qiniu.bucket_moments_domain";
public static final String QINIU_BUCKET_PORTRAIT_NAME= "qiniu.bucket_portrait_name";
public static final String QINIU_BUCKET_PORTRAIT_DOMAIN = "qiniu.bucket_portrait_domain";
public static final String QINIU_BUCKET_FAVORITE_NAME= "qiniu.bucket_favorite_name";
@@ -110,6 +114,7 @@ public final class BrokerConstants {
public static final String MESSAGE_Forward_Url = "message.forward.url";
public static final String SERVER_MULTI_ENDPOINT = "server.multi_endpoint";
public static final String SERVER_MULTI_PLATFROM_NOTIFICATION = "server.multi_platform_notification";
public static final String MONGODB_Client_URI = "mongodb.client_uri";
public static final String MONGODB_Database = "mongodb.database";
@@ -123,6 +128,10 @@ public final class BrokerConstants {
public static final String MESSAGE_Disable_Stranger_Chat = "message.disable_stranger_chat";
public static final String MESSAGE_Blacklist_Strategy = "message.blacklist.strategy";
public static final String FRIEND_Disable_Search = "friend.disable_search";
public static final String FRIEND_Disable_NickName_Search = "friend.disable_nick_name_search";
public static final String FRIEND_Disable_Friend_Request = "friend.disable_friend_request";
public static final String FRIEND_Repeat_Request_Duration = "friend.repeat_request_duration";
public static final String FRIEND_Reject_Request_Duration = "friend.reject_request_duration";
public static final String FRIEND_Request_Expiration_Duration = "friend.request_expiration_duration";
@@ -60,6 +60,14 @@ public class GetMediaUploadTokenHandler extends IMHandler<WFCMessage.GetUploadTo
bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;
break;
case 7:
bucketName = MediaServerConfig.QINIU_BUCKET_STICKER_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN;
break;
case 8:
bucketName = MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN;
break;
default:
bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;
@@ -67,6 +67,14 @@ public class GetQiniuUploadTokenHandler extends IMHandler<Byte> {
bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;
break;
case 7:
bucketName = MediaServerConfig.QINIU_BUCKET_STICKER_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN;
break;
case 8:
bucketName = MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN;
break;
default:
bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;
bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;
@@ -31,7 +31,7 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
ErrorCode errorCode = m_messagesStore.handleFriendRequest(fromUser, request, builder, heads, isAdmin);
if (errorCode == ERROR_CODE_SUCCESS) {
if (!isAdmin && builder.getConversation() != null) {
if (!isAdmin && builder.getConversation() != null && request.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Accepted) {
long messageId = MessageShardingUtil.generateId();
long timestamp = System.currentTimeMillis();
builder.setMessageId(messageId);
@@ -64,9 +64,9 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
builder.setServerTimestamp(timestamp);
saveAndPublish(request.getTargetUid(), null, builder.build(), false);
publisher.publishNotification(IMTopic.NotifyFriendTopic, request.getTargetUid(), heads[0]);
publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, heads[1]);
}
publisher.publishNotification(IMTopic.NotifyFriendTopic, request.getTargetUid(), heads[0]);
publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, heads[1]);
}
return errorCode;
}
@@ -65,6 +65,9 @@ abstract public class IMHandler<T> {
protected static String actionName;
public static MessagesPublisher getPublisher() {
return publisher;
}
public IMHandler() {
try {
@@ -18,8 +18,7 @@ import win.liyufan.im.IMTopic;
public class PutUserSettingHandler extends IMHandler<WFCMessage.ModifyUserSettingReq> {
@Override
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.ModifyUserSettingReq request, Qos1PublishHandler.IMCallback callback) {
long timestamp = m_messagesStore.updateUserSettings(fromUser, request);
publisher.publishNotification(IMTopic.NotifyUserSettingTopic, fromUser, timestamp);
m_messagesStore.updateUserSettings(fromUser, request);
return ErrorCode.ERROR_CODE_SUCCESS;
}
}
@@ -21,13 +21,12 @@ import java.util.Set;
public class RecallMessageHandler extends IMHandler<WFCMessage.INT64Buf> {
@Override
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.INT64Buf int64Buf, Qos1PublishHandler.IMCallback callback) {
ErrorCode errorCode = m_messagesStore.recallMessage(int64Buf.getId(), fromUser, isAdmin);
ErrorCode errorCode = m_messagesStore.recallMessage(int64Buf.getId(), fromUser, clientID, isAdmin);
if(errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
return errorCode;
}
Set<String> notifyReceivers = new LinkedHashSet<>();
WFCMessage.Message message = m_messagesStore.getMessage(int64Buf.getId());
if (message == null) {
return ErrorCode.ERROR_CODE_NOT_EXIST;
@@ -35,11 +34,6 @@ public class RecallMessageHandler extends IMHandler<WFCMessage.INT64Buf> {
publish(fromUser, clientID, message);
//等待客户端实现根据撤回消息更新内容,之后可以删掉这段代码
m_messagesStore.getNotifyReceivers(fromUser, message.toBuilder(), notifyReceivers, false);
this.publisher.publishRecall2Receivers(int64Buf.getId(), fromUser, notifyReceivers, clientID);
return errorCode;
}
@@ -26,6 +26,7 @@ import com.xiaoleilu.loServer.model.FriendData;
import cn.wildfirechat.pojos.InputOutputUserBlockStatus;
import cn.wildfirechat.common.ErrorCode;
import io.moquette.BrokerConstants;
import io.moquette.imhandler.IMHandler;
import io.moquette.server.Constants;
import io.moquette.server.Server;
import io.moquette.spi.IMatchingCondition;
@@ -55,10 +56,12 @@ import static cn.wildfirechat.proto.ProtoConstants.GroupMemberType.*;
import static cn.wildfirechat.proto.ProtoConstants.ModifyChannelInfoType.*;
import static cn.wildfirechat.proto.ProtoConstants.ModifyGroupInfoType.*;
import static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;
import static cn.wildfirechat.proto.ProtoConstants.Platform.*;
import static io.moquette.BrokerConstants.*;
import static io.moquette.server.Constants.MAX_CHATROOM_MESSAGE_QUEUE;
import static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;
import static win.liyufan.im.MyInfoType.*;
import static win.liyufan.im.UserSettingScope.kUserSettingPCOnline;
public class MemoryMessagesStore implements IMessagesStore {
private static final String MESSAGES_MAP = "messages_map";
@@ -118,10 +121,14 @@ public class MemoryMessagesStore implements IMessagesStore {
private ConcurrentHashMap<String, Boolean> userPushHiddenDetail = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Boolean> userConvSlientMap = new ConcurrentHashMap<>();
private boolean mDisableSearch = false;
private boolean mDisableNicknameSearch = false;
private boolean mDisableFriendRequest = false;
private long mFriendRequestDuration = 7 * 24 * 60 * 60 * 1000;
private long mFriendRejectDuration = 30 * 24 * 60 * 60 * 1000;
private long mFriendRequestExpiration = 7 * 24 * 60 * 60 * 1000;
private boolean mMultiPlatformNotification = false;
private boolean mDisableStrangerChat = false;
private long mChatroomParticipantIdleTime = 900000;
@@ -130,6 +137,7 @@ public class MemoryMessagesStore implements IMessagesStore {
MemoryMessagesStore(Server server, DatabaseStore databaseStore) {
m_Server = server;
this.databaseStore = databaseStore;
IS_MESSAGE_ROAMING = "1".equals(m_Server.getConfig().getProperty(MESSAGE_ROAMING));
IS_MESSAGE_REMOTE_HISTORY_MESSAGE = "1".equals(m_Server.getConfig().getProperty(MESSAGE_Remote_History_Message));
Constants.MAX_MESSAGE_QUEUE = Integer.parseInt(m_Server.getConfig().getProperty(MESSAGE_Max_Queue));
@@ -139,6 +147,37 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(MESSAGE_Disable_Stranger_Chat, mDisableStrangerChat + "");
}
try {
mMultiPlatformNotification = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_PLATFROM_NOTIFICATION, "false"));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(SERVER_MULTI_PLATFROM_NOTIFICATION, mDisableStrangerChat + "");
}
try {
mDisableSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_Search));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(FRIEND_Disable_Search, mDisableSearch + "");
}
try {
mDisableNicknameSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_NickName_Search));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(FRIEND_Disable_NickName_Search, mDisableNicknameSearch + "");
}
try {
mDisableFriendRequest = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_Friend_Request));
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(FRIEND_Disable_Friend_Request, mDisableFriendRequest + "");
}
try {
@@ -146,6 +185,7 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(FRIEND_Repeat_Request_Duration, mFriendRequestDuration + "");
}
try {
@@ -153,6 +193,7 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(FRIEND_Reject_Request_Duration, mFriendRejectDuration + "");
}
try {
@@ -160,6 +201,7 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(FRIEND_Request_Expiration_Duration, mFriendRequestExpiration + "");
}
try {
@@ -167,6 +209,7 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(CHATROOM_Rejoin_When_Active, mChatroomRejoinWhenActive + "");
}
try {
@@ -174,9 +217,14 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
printMissConfigLog(CHATROOM_Participant_Idle_Time, mChatroomParticipantIdleTime + "");
}
}
private void printMissConfigLog(String config, String defaultValue) {
LOG.info("配置文件中缺少配置项目 {}, 缺省值为 {},可以忽略本提醒,或者更新配置项", config, defaultValue);
}
@Override
public void initStore() {
updateSensitiveWord();
@@ -1322,7 +1370,7 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public ErrorCode recallMessage(long messageUid, String operatorId, boolean isAdmin) {
public ErrorCode recallMessage(long messageUid, String operatorId, String clientId, boolean isAdmin) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);
@@ -1373,8 +1421,14 @@ public class MemoryMessagesStore implements IMessagesStore {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
message = message.toBuilder().setContent(message.getContent().toBuilder().setContent(operatorId).setType(80).clearSearchableContent().setData(ByteString.copyFrom(new StringBuffer().append(messageUid).toString().getBytes())).build()).build();
String searchContent = message.getContent().getSearchableContent() == null ? "" : message.getContent().getSearchableContent();
String cont = message.getContent().getContent() == null ? "" : message.getContent().getContent();
String extra = message.getContent().getExtra() == null ? "" : message.getContent().getExtra();
String recalledContent = "{\"s\":\"" + message.getFromUser() + "\",\"ts\":" + message.getServerTimestamp() + ",\"t\":" + message.getContent().getType() + ",\"sc\":\"" + searchContent + "\",\"c\":\"" + cont + "\",\"e\":\"" + extra + "\"}";
message = message.toBuilder().setContent(message.getContent().toBuilder().setContent(operatorId).setType(80).clearSearchableContent().setData(ByteString.copyFrom(String.valueOf(messageUid).getBytes())).setExtra(recalledContent).build()).build();
messageBundle.setMessage(message);
messageBundle.setFromClientId(clientId);
databaseStore.deleteMessage(messageUid);
@@ -1524,6 +1578,56 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public void updateUserOnlineSetting(MemorySessionStore.Session session, boolean online) {
if(!mMultiPlatformNotification) {
return;
}
if (m_Server.getStore().sessionsStore().isMultiEndpointSupported()) {
return;
}
if (m_Server.isShutdowning()) {
return;
}
if (session.getPlatform() == Platform_Linux || session.getPlatform() == Platform_Windows || session.getPlatform() == Platform_OSX) {
updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey("PC").setValue(online ? (System.currentTimeMillis() + "|" + session.getPlatform() + "|" + session.getClientID() + "|" + session.getPhoneName()) : "").build());
} else {
String value = null;
for (MemorySessionStore.Session s : m_Server.getStore().sessionsStore().sessionForUser(session.username)) {
if (s.getDeleted() != 0 || !m_Server.getConnectionsManager().isConnected(s.getClientID())) {
continue;
}
switch (s.getPlatform()) {
case Platform_Linux:
case Platform_Windows:
case Platform_OSX:
value = System.currentTimeMillis() + "|" + s.getPlatform() + "|" + s.getClientID() + "|" + s.getPhoneName();
break;
default:
break;
}
if (value != null) {
break;
}
}
WFCMessage.UserSettingEntry pcentry = getUserSetting(session.getUsername(), kUserSettingPCOnline, "PC");
if (value != null) {
if (pcentry == null || StringUtil.isNullOrEmpty(pcentry.getValue())) {
updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey("PC").setValue(value).build());
}
} else {
if (pcentry != null && !StringUtil.isNullOrEmpty(pcentry.getValue())) {
updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey("PC").setValue("").build());
}
}
}
}
@Override
public ErrorCode modifyUserStatus(String userId, int status) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
@@ -1612,6 +1716,14 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public List<WFCMessage.User> searchUser(String keyword, int searchType, int page) {
if (mDisableSearch) {
return new ArrayList<>();
}
if (mDisableNicknameSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_General) {
searchType = ProtoConstants.SearchUserType.SearchUserType_Name_Mobile;
}
return databaseStore.searchUserFromDB(keyword, searchType, page);
}
@@ -1945,6 +2057,10 @@ public class MemoryMessagesStore implements IMessagesStore {
@Override
public ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head) {
if (mDisableFriendRequest) {
return ErrorCode.ERROR_CODE_NOT_RIGHT;
}
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);
Collection<WFCMessage.FriendRequest> requests = requestMap.get(userId);
@@ -2454,6 +2570,7 @@ public class MemoryMessagesStore implements IMessagesStore {
userGlobalSlientMap.remove(userId);
userConvSlientMap.remove(userId);
userPushHiddenDetail.remove(userId);
IMHandler.getPublisher().publishNotification(IMTopic.NotifyUserSettingTopic, userId, updateDt);
return updateDt;
}
@@ -680,4 +680,8 @@ public class MemorySessionStore implements ISessionsStore {
// TODO this missing last step breaks the junit test
sessions.remove(clientID);
}
@Override
public boolean isMultiEndpointSupported() {
return supportMultiEndpoint;
}
}
@@ -82,6 +82,8 @@ public class Server {
private ServerAcceptor m_acceptor;
private boolean m_shutdowning = false;
public volatile boolean m_initialized;
private ProtocolProcessor m_processor;
@@ -317,6 +319,12 @@ public class Server {
MediaServerConfig.QINIU_BUCKET_FILE_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_FILE_NAME);
MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_FILE_DOMAIN);
MediaServerConfig.QINIU_BUCKET_STICKER_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_STICKER_NAME);
MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_STICKER_DOMAIN);
MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_MOMENTS_NAME);
MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_MOMENTS_DOMAIN);
MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_PORTRAIT_NAME);
MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_PORTRAIT_DOMAIN);
@@ -415,9 +423,15 @@ public class Server {
m_processor.onRpcMsg(fromUser, clientId, message, messageId, from, request, isAdmin);
}
public boolean isShutdowning() {
return m_shutdowning;
}
public void stopServer() {
System.out.println("Server will flush data to db before shutting down, please wait 5 seconds!");
LOG.info("Unbinding server from the configured ports");
m_shutdowning = true;
m_acceptor.close();
LOG.trace("Stopping MQTT protocol processor");
m_processorBootstrapper.shutdown();
@@ -15,6 +15,10 @@ public class MediaServerConfig {
public static String QINIU_BUCKET_VIDEO_DOMAIN;
public static String QINIU_BUCKET_FILE_NAME;
public static String QINIU_BUCKET_FILE_DOMAIN;
public static String QINIU_BUCKET_STICKER_NAME;
public static String QINIU_BUCKET_STICKER_DOMAIN;
public static String QINIU_BUCKET_MOMENTS_NAME;
public static String QINIU_BUCKET_MOMENTS_DOMAIN;
public static String QINIU_BUCKET_PORTRAIT_NAME;
public static String QINIU_BUCKET_PORTRAIT_DOMAIN;
public static String QINIU_BUCKET_FAVORITE_NAME;
@@ -122,7 +122,7 @@ public interface IMessagesStore {
boolean isMemberInGroup(String member, String groupId);
ErrorCode canSendMessageInGroup(String member, String groupId);
ErrorCode recallMessage(long messageUid, String operatorId, boolean isAdmin);
ErrorCode recallMessage(long messageUid, String operatorId, String clientId, boolean isAdmin);
void clearUserMessages(String userId);
@@ -131,6 +131,8 @@ public interface IMessagesStore {
ErrorCode getUserInfo(List<WFCMessage.UserRequest> requestList, WFCMessage.PullUserResult.Builder builder);
ErrorCode modifyUserInfo(String userId, WFCMessage.ModifyMyInfoRequest request) throws Exception;
void updateUserOnlineSetting(MemorySessionStore.Session session, boolean online);
ErrorCode modifyUserStatus(String userId, int status);
int getUserStatus(String userId);
List<InputOutputUserBlockStatus> getUserStatusList();
@@ -149,4 +149,6 @@ public interface ISessionsStore {
int getSecondPhaseAckPendingMessages(String clientID);
void cleanSession(String clientID);
boolean isMultiEndpointSupported();
}
@@ -244,6 +244,7 @@ public class ProtocolProcessor {
if(session != null) {
session.refreshLastActiveTime();
forwardOnlineStatusEvent(payload.userName(), clientId, session.getPlatform(), UserOnlineStatus.ONLINE);
m_messagesStore.updateUserOnlineSetting(session, true);
} else {
forwardOnlineStatusEvent(payload.userName(), clientId, ProtoConstants.Platform.Platform_UNSET, UserOnlineStatus.ONLINE);
}
@@ -559,6 +560,9 @@ public class ProtocolProcessor {
String username = NettyUtils.userName(channel);
MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);
if(session != null) {
m_messagesStore.updateUserOnlineSetting(session, false);
}
if(session != null) {
forwardOnlineStatusEvent(username, clientID, session.getPlatform(), UserOnlineStatus.LOGOUT);
}
@@ -605,6 +609,7 @@ public class ProtocolProcessor {
if(session != null) {
session.refreshLastActiveTime();
forwardOnlineStatusEvent(username, clientID, session.getPlatform(), clearSession ? UserOnlineStatus.LOGOUT : UserOnlineStatus.OFFLINE);
m_messagesStore.updateUserOnlineSetting(session, false);
}
ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);
@@ -80,12 +80,10 @@ public class DBUtil {
comboPooledDataSource = new ComboPooledDataSource("mysql");
try {
String url01 = comboPooledDataSource.getJdbcUrl().substring(0,comboPooledDataSource.getJdbcUrl().indexOf("?"));
String url02 = url01.substring(0,url01.lastIndexOf("/"));
String datasourceName = url01.substring(url01.lastIndexOf("/")+1);
// 连接已经存在的数据库,如:mysql
Connection connection = DriverManager.getConnection(url02, comboPooledDataSource.getUser(), comboPooledDataSource.getPassword());
String jdbc = comboPooledDataSource.getJdbcUrl().replace(datasourceName, "");
Connection connection = DriverManager.getConnection(jdbc, comboPooledDataSource.getUser(), comboPooledDataSource.getPassword());
Statement statement = connection.createStatement();
// 创建数据库
@@ -64,6 +64,10 @@ public class MessageBundle implements Serializable {
return message;
}
public void setFromClientId(String fromClientId) {
this.fromClientId = fromClientId;
}
public void setMessage(WFCMessage.Message message) {
this.fromUser = message.getFromUser();
this.type = message.getConversation().getType();
@@ -11,6 +11,7 @@ public interface UserSettingScope {
int kUserSettingConversationSync = 7;
int kUserSettingMyChannels = 8;
int kUserSettingListenedChannels = 9;
int kUserSettingPCOnline = 10;
int kUserSettingCustomBegin = 1000;
}
+1 -1
View File
@@ -18,7 +18,7 @@
<!--MySQL数据库驱动程序-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!--MySQL数据库地址-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?verifyServerCertificate=false&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=UTF-8</property>
<!--MySQL数据库用户名-->
<property name="user">root</property>
<!--MySQL数据库密码-->
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.39</version>
<version>0.40</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,6 +5,11 @@ public interface APIPath {
String Chatroom_Destroy = "/admin/chatroom/del";
String Chatroom_Info = "/admin/chatroom/info";
String Chatroom_GetMembers = "/admin/chatroom/members";
String Chatroom_SetBlacklist = "/admin/chatroom/set_black_status";
String Chatroom_GetBlacklist = "/admin/chatroom/get_black_status";
String Chatroom_SetManager = "/admin/chatroom/set_manager";
String Chatroom_GetManagerList = "/admin/chatroom/get_manager_list";
String Chatroom_MuteAll = "/admin/chatroom/mute_all";
String Sensitive_Add = "/admin/sensitive/add";
@@ -0,0 +1,12 @@
package cn.wildfirechat.pojos;
public class InputChatroomId {
public String chatroomId;
public InputChatroomId() {
}
public InputChatroomId(String chatroomId) {
this.chatroomId = chatroomId;
}
}
@@ -0,0 +1,36 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
public class InputChatroomMute {
private String chatroomId;
private int status;
public InputChatroomMute(String chatroomId, int status) {
this.chatroomId = chatroomId;
this.status = status;
}
public String getChatroomId() {
return chatroomId;
}
public void setChatroomId(String chatroomId) {
this.chatroomId = chatroomId;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
@@ -0,0 +1,58 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
public class InputSetChatroomBlacklist {
private String chatroomId;
private String userId;
private int status;
private long expiredTime;
public InputSetChatroomBlacklist() {
}
public InputSetChatroomBlacklist(String chatroomId, String userId, int status, long expiredTime) {
this.chatroomId = chatroomId;
this.userId = userId;
this.status = status;
this.expiredTime = expiredTime;
}
public String getChatroomId() {
return chatroomId;
}
public void setChatroomId(String chatroomId) {
this.chatroomId = chatroomId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public long getExpiredTime() {
return expiredTime;
}
public void setExpiredTime(long expiredTime) {
this.expiredTime = expiredTime;
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
public class InputSetChatroomManager {
private String chatroomId;
private String userId;
private int status;
public InputSetChatroomManager() {
}
public InputSetChatroomManager(String chatroomId, String userId, int status) {
this.chatroomId = chatroomId;
this.userId = userId;
this.status = status;
}
public String getChatroomId() {
return chatroomId;
}
public void setChatroomId(String chatroomId) {
this.chatroomId = chatroomId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
@@ -0,0 +1,25 @@
package cn.wildfirechat.pojos;
import java.util.ArrayList;
import java.util.List;
public class OutputChatroomBlackInfos {
public static class OutputChatroomBlackInfo {
public String userId;
public int state;
public long expiredTime;
public OutputChatroomBlackInfo() {
}
public OutputChatroomBlackInfo(String userId, int state, long expiredTime) {
this.userId = userId;
this.state = state;
this.expiredTime = expiredTime;
}
}
public List<OutputChatroomBlackInfo> infos = new ArrayList<>();
public void addBlackInfo(String userId, int state, long expiredTime) {
infos.add(new OutputChatroomBlackInfo(userId, state, expiredTime));
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.39</version>
<version>0.40</version>
</parent>
<artifactId>distribution</artifactId>
@@ -15,7 +15,7 @@
<!--MySQL数据库驱动程序-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!--MySQL数据库地址-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=UTF-8</property>
<!--MySQL数据库用户名-->
<property name="user">root</property>
<!--MySQL数据库密码-->
@@ -84,6 +84,12 @@
<map name="user_chatroom">
</map>
<multimap name="chatroom_black">
</multimap>
<multimap name="chatroom_manager">
</multimap>
<map name="robots">
<!-- 7 days -->
<time-to-live-seconds>604800</time-to-live-seconds>
@@ -58,9 +58,19 @@ message.max_queue 1024
##是否禁止陌生人聊天
message.disable_stranger_chat false
##黑名单处理策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃;
##黑名单处理策略,0 发送失败,返回被拉黑的错误码;1 发送成功但消息被服务器直接丢弃;2 敏感词替换为***;3 不处理。
##所有命中敏感词的消息都会被记录在敏感词消息表中
message.blacklist.strategy 0
##禁止搜索用户
friend.disable_search false
##禁止按照昵称搜索用户。
friend.disable_nick_name_search false
##禁止发送好友邀请,通过server api添加好友不受此限制
friend.disable_friend_request false
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制
friend.repeat_request_duration 604800000
@@ -112,6 +122,10 @@ qiniu.bucket_video_name media
qiniu.bucket_video_domain http://cdn.wildfirechat.cn
qiniu.bucket_file_name media
qiniu.bucket_file_domain http://cdn.wildfirechat.cn
qiniu.bucket_sticker_name media
qiniu.bucket_sticker_domain http://cdn.wildfirechat.cn
qiniu.bucket_moments_name media
qiniu.bucket_moments_domain http://cdn.wildfirechat.cn
qiniu.bucket_portrait_name storage
qiniu.bucket_portrait_domain http://cdn2.wildfirechat.cn
qiniu.bucket_favorite_name storage
@@ -126,6 +140,9 @@ local.media.storage.root ./media
# 是否支持多端登陆
server.multi_endpoint false
# 多平台连接状态通知(仅当multi_endpoint为false时有效)
server.multi_platform_notification false
#*********************************************************************
# Push server configuration
#*********************************************************************
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>0.39</version>
<version>0.40</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.39</version>
<version>0.40</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -37,6 +37,37 @@ public class ChatroomAdmin {
return AdminHttpUtils.httpJsonPost(path, input, OutputStringList.class);
}
//仅专业版支持
//status:0,正常;1,禁言;2,禁止加入
public static IMResult<Void> setChatroomBlacklist(String chatroomId, String userId, int status) throws Exception {
String path = APIPath.Chatroom_SetBlacklist;
InputSetChatroomBlacklist input = new InputSetChatroomBlacklist(chatroomId, userId, status, 0);
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
public static IMResult<OutputChatroomBlackInfos> getChatroomBlacklist(String chatroomId) throws Exception {
String path = APIPath.Chatroom_GetBlacklist;
InputChatroomId input = new InputChatroomId(chatroomId);
return AdminHttpUtils.httpJsonPost(path, input, OutputChatroomBlackInfos.class);
}
//status: 1 set; 0 unset
public static IMResult<Void> setChatroomManager(String chatroomId, String userId, int status) throws Exception {
String path = APIPath.Chatroom_SetManager;
InputSetChatroomManager input = new InputSetChatroomManager(chatroomId, userId, status);
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
public static IMResult<OutputStringList> getChatroomManagerList(String chatroomId) throws Exception {
String path = APIPath.Chatroom_GetManagerList;
InputChatroomId input = new InputChatroomId(chatroomId);
return AdminHttpUtils.httpJsonPost(path, input, OutputStringList.class);
}
public static IMResult<Void> setChatroomMute(String chatroomId, boolean mute) throws Exception {
String path = APIPath.Chatroom_MuteAll;
InputChatroomMute input = new InputChatroomMute(chatroomId, mute ? 1 : 0);
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
}
+101 -2
View File
@@ -258,8 +258,8 @@ public class Main {
System.exit(-1);
}
updateFriendStatusResult = RelationAdmin.setUserBlacklist("ff1", "ff2", true);
if (updateFriendStatusResult != null && updateFriendStatusResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
IMResult<Void> updateBlacklistStatusResult = RelationAdmin.setUserBlacklist("ff1", "ff2", true);
if (updateBlacklistStatusResult != null && updateBlacklistStatusResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
System.out.println("update blacklist status success");
} else {
System.out.println("update blacklist status failure");
@@ -575,6 +575,105 @@ public class Main {
System.out.println("chatroom not destroyed!");
System.exit(-1);
}
//下面仅专业版支持
/*
//设置用户聊天室黑名单。0正常;1禁言;2禁止加入。
IMResult<Void> voidIMResult1 = ChatroomAdmin.setChatroomBlacklist("chatroom1", "oto9o9__", 1);
if (voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
System.out.println("add chatroom black success");
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}
//获取聊天室黑名单
IMResult<OutputChatroomBlackInfos> blackInfos = ChatroomAdmin.getChatroomBlacklist("chatroom1");
if (blackInfos != null && blackInfos.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !blackInfos.getResult().infos.isEmpty()) {
boolean success = false;
for (OutputChatroomBlackInfos.OutputChatroomBlackInfo info : blackInfos.getResult().infos) {
if (info.userId.equals("oto9o9__")) {
success = true;
break;
}
}
if (success) {
System.out.println("add chatroom black success");
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}
//取消用户聊天室黑名单。0正常;1禁言;2禁止加入。
voidIMResult1 = ChatroomAdmin.setChatroomBlacklist("chatroom1", "oto9o9__", 0);
if (voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
System.out.println("remove chatroom black success");
} else {
System.out.println("remove chatroom black failure");
System.exit(-1);
}
//获取聊天室黑名单
blackInfos = ChatroomAdmin.getChatroomBlacklist("chatroom1");
if (blackInfos != null && blackInfos.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
boolean success = true;
for (OutputChatroomBlackInfos.OutputChatroomBlackInfo info : blackInfos.getResult().infos) {
if (info.userId.equals("oto9o9__")) {
success = false;
break;
}
}
if (success) {
System.out.println("remove chatroom black success");
} else {
System.out.println("remove chatroom black failure");
System.exit(-1);
}
} else {
System.out.println("remove chatroom black failure");
System.exit(-1);
}
//设置聊天室管理员
IMResult<Void> voidIMResult2 = ChatroomAdmin.setChatroomManager("chatroom1", "UserId1", 1);
if (voidIMResult2 != null && voidIMResult2.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
System.out.println("add chatroom manager success");
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}
//获取聊天室管理员
IMResult<OutputStringList> managers = ChatroomAdmin.getChatroomManagerList("chatroom1");
if (managers != null && managers.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !managers.getResult().getList().isEmpty() && managers.getResult().getList().contains("UserId1")) {
System.out.println("add chatroom black success");
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}
//取消聊天室管理员
IMResult<Void> voidIMResult3 = ChatroomAdmin.setChatroomManager("chatroom1", "UserId1", 0);
if (voidIMResult3 != null && voidIMResult3.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
System.out.println("add chatroom manager success");
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}
//获取聊天室管理员
IMResult<OutputStringList> managers2 = ChatroomAdmin.getChatroomManagerList("chatroom1");
if (managers2 != null && managers2.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !managers2.getResult().getList().contains("UserId1")) {
System.out.println("add chatroom black success");
} else {
System.out.println("add chatroom black failure");
System.exit(-1);
}*/
}
static void testRobot() throws Exception {
@@ -28,7 +28,7 @@ public class RelationAdmin {
InputBlacklistRequest input = new InputBlacklistRequest();
input.setUserId(userId);
input.setTargetUid(targetId);
input.setStatus(isBlacklist ? 1 : 0);
input.setStatus(isBlacklist ? 2 : 1);
return AdminHttpUtils.httpJsonPost(path, input, Void.class);
}
@@ -31,9 +31,13 @@ public class AdminHttpUtils {
}
public static <T> IMResult<T> httpJsonPost(String path, Object object, Class<T> clazz) throws Exception{
if (isNullOrEmpty(adminUrl) || isNullOrEmpty(path)) {
LOG.error("Not init IM SDK correctly. Do you forget init it?");
throw new Exception("SDK url or secret lack!");
if (isNullOrEmpty(adminUrl) || isNullOrEmpty(adminSecret)) {
LOG.error("野火IM Server SDK必须先初始化才能使用,是不是忘记初始化了!!!!");
throw new Exception("SDK没有初始化");
}
if (isNullOrEmpty(path)) {
throw new Exception("路径缺失");
}
String url = adminUrl + path;