Compare commits

...
15 Commits
Author SHA1 Message Date
heavyrain2012 e72ae59e49 update version to 0.33 2019-11-28 17:33:35 +08:00
heavyrain2012 f0c2fd82ca 调整部分文件包名 2019-11-28 14:20:34 +08:00
heavyrain2012 5a588c8268 update 2019-11-27 12:57:07 +08:00
heavyrain2012 2adc030d6f 修改日志缺陷 2019-11-27 11:09:07 +08:00
heavyrain2012 b0ca8ed2b7 update 2019-11-27 10:39:32 +08:00
heavyrain2012 f9d5c861ce 优化用户session 2019-11-27 10:30:39 +08:00
heavyrain2012 9aaaa71ce9 清除掉重复token 2019-11-26 14:44:25 +08:00
heavyrain2012 73a971bde3 同步已读设置时,如果是排除掉已经解散的群组和销毁的频道 2019-11-25 18:50:00 +08:00
heavyrain2012 5942eb7b15 update version to 0.32 2019-11-25 12:12:06 +08:00
heavyrain2012 b97fea1841 添加索引 2019-11-25 11:22:36 +08:00
heavyrain2012 33637229d6 限制多端登陆 2019-11-25 11:19:53 +08:00
heavyrain2012 af366fcdb2 update proto 2019-11-25 11:19:44 +08:00
heavyrain2012 c9089c5d51 性能优化 2019-11-25 11:18:44 +08:00
imndx 3afc6a2da9 update readme 2019-11-24 20:37:45 +08:00
heavyrain2012 12d22e78bf 根据devicetoken进行排重 2019-11-21 20:51:52 +08:00
86 changed files with 566 additions and 103 deletions
+12 -10
View File
@@ -2,16 +2,18 @@
野火IM是一套跨平台、核心功能开源的即时通讯解决方案,主要包含以下内容。 野火IM是一套跨平台、核心功能开源的即时通讯解决方案,主要包含以下内容。
| 仓库 | 说明 | 备注 | | 仓库 | 说明 | 备注 |
| ------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------- | | ------------------------------------------------------------ | ------------------------------------------------------- | ---- |
| [android-chat](https://github.com/wildfirechat/android-chat) | 野火IM Android SDK源码和App源码 | 可以很方便地进行二次开发,或集成到现有应用当中 | | [android-chat](https://github.com/wildfirechat/android-chat) | 野火IM Android SDK源码和App源码 |可以很方便地进行二次开发,或集成到现有应用当中 |
| [ios-chat](https://github.com/wildfirechat/ios-chat) | 野火IM iOS SDK源码和App源码 | 可以很方便地进行二次开发,或集成到现有应用当中 | | [ios-chat](https://github.com/wildfirechat/ios-chat) | 野火IM iOS SDK源码和App源码 |可以很方便地进行二次开发,或集成到现有应用当中 |
| [pc-chat](https://github.com/wildfirechat/pc-chat) | 基于[Electron](https://electronjs.org/)开发的PC平台应用 | | | [pc-chat](https://github.com/wildfirechat/pc-chat) | 基于[Electron](https://electronjs.org/)开发的PC平台应用 | |
| [server](https://github.com/wildfirechat/server) | IM server | | | [web-chat](https://github.com/wildfirechat/web-chat) | Web平台的Demo, [体验地址](http://web.wildfirechat.cn) | |
| [app server](https://github.com/wildfirechat/app_server) | 应用服务端 | | | [wx-chat](https://github.com/wildfirechat/wx-chat) | 微信小程序平台的Demo | |
| [robot_server](https://github.com/wildfirechat/robot_server) | 机器人服务端 | | | [server](https://github.com/wildfirechat/server) | IM server | |
| [push_server](https://github.com/wildfirechat/push_server) | 推送服务器 | | | [app server](https://github.com/wildfirechat/app_server) | 应用服务端 | |
| [docs](https://github.com/wildfirechat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明 | | | [robot_server](https://github.com/wildfirechat/robot_server) | 机器人服务端 | |
| [push_server](https://github.com/wildfirechat/push_server) | 推送服务器 | |
| [docs](https://github.com/wildfirechat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明 | | | |
# server # server
本工程为野火IM 社区版IM服务软件。野火IM作为一个通用的即时通讯解决方案,可以集成到各种应用中。请阅读[docs](http://docs.wildfirechat.cn)或下载服务器[发布版本](https://github.com/wildfirechat/server/releases) 本工程为野火IM 社区版IM服务软件。野火IM作为一个通用的即时通讯解决方案,可以集成到各种应用中。请阅读[docs](http://docs.wildfirechat.cn)或下载服务器[发布版本](https://github.com/wildfirechat/server/releases)
+3
View File
@@ -102,6 +102,9 @@ qiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn
# 本地媒体服务器配置。 # 本地媒体服务器配置。
local.media.storage.root media local.media.storage.root media
# 是否支持多端登陆
server.multi_endpoint false
#********************************************************************* #*********************************************************************
# Push server configuration # Push server configuration
#********************************************************************* #*********************************************************************
+1
View File
@@ -0,0 +1 @@
alter table `t_user_session` ADD INDEX `session_token_index` ( `_token` );
+1
View File
@@ -0,0 +1 @@
alter table t_friend_request add index `friend_request_uid_index` (`_friend_uid`);
+1
View File
@@ -0,0 +1 @@
alter table `t_user_session` ADD INDEX `session_uid_index` ( `_uid` );
+1
View File
@@ -0,0 +1 @@
alter table `t_user_session` add column `_deleted` tinyint DEFAULT 0;
@@ -0,0 +1 @@
alter table `t_user_session` ADD INDEX `session_token_index` ( `_token` );
+1
View File
@@ -0,0 +1 @@
alter table t_friend_request add index `friend_request_uid_index` (`_friend_uid`);
+1
View File
@@ -0,0 +1 @@
alter table `t_user_session` ADD INDEX `session_uid_index` ( `_uid` );
+1
View File
@@ -0,0 +1 @@
alter table `t_user_session` add column `_deleted` tinyint DEFAULT 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.31</version> <version>0.33</version>
</parent> </parent>
<artifactId>moquette-broker</artifactId> <artifactId>moquette-broker</artifactId>
@@ -57,7 +57,7 @@ public class PushServer {
} }
public void pushMessage(PushMessage pushMessage, String deviceId, String pushContent) { public void pushMessage(PushMessage pushMessage, String deviceId, String pushContent) {
LOG.info("try to delivery push diviceId = {}, pushContent", deviceId, pushContent); LOG.info("try to delivery push diviceId = {}, pushContent = {}", deviceId, pushContent);
executorService.execute(() ->{ executorService.execute(() ->{
try { try {
pushMessageInternel(pushMessage, deviceId, pushContent); pushMessageInternel(pushMessage, deviceId, pushContent);
@@ -82,7 +82,7 @@ public class RouteAction extends Action {
MemorySessionStore.Session session = sessionsStore.sessionForClientAndUser(uid, cid); MemorySessionStore.Session session = sessionsStore.sessionForClientAndUser(uid, cid);
if (session == null) { if (session == null) {
ErrorCode errorCode = sessionsStore.createNewSession(uid, cid, true, true); ErrorCode errorCode = sessionsStore.loadActiveSession(uid, cid);
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) { if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
sendResponse(response, errorCode, null, base64Response); sendResponse(response, errorCode, null, base64Response);
return true; return true;
@@ -41,7 +41,7 @@ public class GetIMTokenAction extends AdminAction {
String userId = input.getUserId(); String userId = input.getUserId();
WFCMessage.GetTokenRequest getTokenRequest = WFCMessage.GetTokenRequest.newBuilder().setUserId(userId).setClientId(input.getClientId()).build(); WFCMessage.GetTokenRequest getTokenRequest = WFCMessage.GetTokenRequest.newBuilder().setUserId(userId).setClientId(input.getClientId()).setPlatform(input.getPlatform() == null ? 0 : input.getPlatform()).build();
RPCCenter.getInstance().sendRequest(userId, input.getClientId(), IMTopic.GetTokenTopic, getTokenRequest.toByteArray(), userId, TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() { RPCCenter.getInstance().sendRequest(userId, input.getClientId(), IMTopic.GetTokenTopic, getTokenRequest.toByteArray(), userId, TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
@Override @Override
public void onSuccess(byte[] result) { public void onSuccess(byte[] result) {
@@ -106,6 +106,8 @@ public final class BrokerConstants {
public static final String MESSAGE_Forward_Url = "message.forward.url"; public static final String MESSAGE_Forward_Url = "message.forward.url";
public static final String SERVER_MULTI_ENDPOINT = "server.multi_endpoint";
public static final String MONGODB_Client_URI = "mongodb.client_uri"; public static final String MONGODB_Client_URI = "mongodb.client_uri";
public static final String MONGODB_Database = "mongodb.database"; public static final String MONGODB_Database = "mongodb.database";
public static final String MONGODB_Data_Expire_Days = "mongodb.data_expire_days"; public static final String MONGODB_Data_Expire_Days = "mongodb.data_expire_days";
@@ -20,7 +20,7 @@ import win.liyufan.im.IMTopic;
public class GetTokenHandler extends IMHandler<WFCMessage.GetTokenRequest> { 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.createUserSession(fromUser, clientID); MemorySessionStore.Session session = m_sessionsStore.createUserSession(fromUser, clientID, request.getPlatform());
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();
@@ -240,7 +240,7 @@ abstract public class IMHandler<T> {
WFCMessage.Message.Builder messageBuilder = message.toBuilder(); WFCMessage.Message.Builder messageBuilder = message.toBuilder();
int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers); int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers);
this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType); mServer.getImBusinessScheduler().execute(() -> this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType));
return notifyReceivers.size(); return notifyReceivers.size();
} }
@@ -250,7 +250,7 @@ abstract public class IMHandler<T> {
message = m_messagesStore.storeMessage(username, clientID, message); message = m_messagesStore.storeMessage(username, clientID, message);
WFCMessage.Message.Builder messageBuilder = message.toBuilder(); WFCMessage.Message.Builder messageBuilder = message.toBuilder();
int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers); int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers);
this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType); mServer.getImBusinessScheduler().execute(() -> this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType));
return notifyReceivers.size(); return notifyReceivers.size();
} }
@@ -32,7 +32,7 @@ public class RouteHandler extends IMHandler<WFCMessage.RouteRequest> {
ClientSession clientSession = m_sessionsStore.sessionForClient(clientID); ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);
boolean isSessionAlreadyStored = clientSession != null; boolean isSessionAlreadyStored = clientSession != null;
if (!isSessionAlreadyStored) { if (!isSessionAlreadyStored) {
m_sessionsStore.createNewSession(fromUser, clientID, true, true); m_sessionsStore.loadActiveSession(fromUser, clientID);
} else { } else {
m_sessionsStore.updateExistSession(fromUser, clientID, request, true); m_sessionsStore.updateExistSession(fromUser, clientID, request, true);
} }
@@ -26,12 +26,12 @@ public class UploadDeviceTokenHandler extends IMHandler<WFCMessage.UploadDeviceT
session.setAppName(request.getAppName()); session.setAppName(request.getAppName());
if (request.getPlatform() == ProtoConstants.Platform.Platform_iOS && request.getPushType() == 2) { if (request.getPlatform() == ProtoConstants.Platform.Platform_iOS && request.getPushType() == 2) {
session.setVoipDeviceToken(request.getDeviceToken()); session.setVoipDeviceToken(request.getDeviceToken());
// session.setPushType(0);//如果有voip token,肯定是生产环境的推送
m_sessionsStore.updateSessionToken(session, true); m_sessionsStore.updateSessionToken(session, true);
} else { } else {
session.setDeviceToken(request.getDeviceToken()); session.setDeviceToken(request.getDeviceToken());
session.setPushType(request.getPushType()); session.setPushType(request.getPushType());
m_sessionsStore.updateSessionToken(session, false); m_sessionsStore.updateSessionToken(session, false);
m_sessionsStore.cleanDuplatedToken(session.getClientID(), session.getPushType(), session.getDeviceToken(), false);
} }
return ErrorCode.ERROR_CODE_SUCCESS; return ErrorCode.ERROR_CODE_SUCCESS;
@@ -16,6 +16,7 @@ import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.MultiMap; import com.hazelcast.core.MultiMap;
import com.hazelcast.util.StringUtil; import com.hazelcast.util.StringUtil;
import com.xiaoleilu.loServer.model.FriendData; import com.xiaoleilu.loServer.model.FriendData;
import io.moquette.server.Server;
import io.moquette.spi.ClientSession; import io.moquette.spi.ClientSession;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -30,6 +31,7 @@ import java.sql.*;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent; import static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;
import static io.moquette.persistence.MemoryMessagesStore.USER_STATUS; import static io.moquette.persistence.MemoryMessagesStore.USER_STATUS;
import static io.moquette.server.Constants.MAX_MESSAGE_QUEUE; import static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;
@@ -638,11 +640,12 @@ public class DatabaseStore {
String sql = "select `_from`, `_type`, `_target`, `_line`, `_data`, `_dt` from " + MessageShardingUtil.getMessageTable(messageId) +" where _mid = ? limit 1"; String sql = "select `_from`, `_type`, `_target`, `_line`, `_data`, `_dt` from " + MessageShardingUtil.getMessageTable(messageId) +" where _mid = ? limit 1";
Connection connection = null; Connection connection = null;
PreparedStatement statement = null; PreparedStatement statement = null;
ResultSet resultSet = null;
try { try {
connection = DBUtil.getConnection(); connection = DBUtil.getConnection();
statement = connection.prepareStatement(sql); statement = connection.prepareStatement(sql);
statement.setLong(1, messageId); statement.setLong(1, messageId);
ResultSet resultSet = statement.executeQuery(); resultSet = statement.executeQuery();
if (resultSet.next()) { if (resultSet.next()) {
WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder(); WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder();
builder.setMessageId(messageId); builder.setMessageId(messageId);
@@ -661,12 +664,11 @@ public class DatabaseStore {
WFCMessage.Message message = builder.build(); WFCMessage.Message message = builder.build();
return new MessageBundle(messageId, message.getFromUser(), null, message); return new MessageBundle(messageId, message.getFromUser(), null, message);
} }
resultSet.close();
} catch (SQLException | IOException e) { } catch (SQLException | IOException e) {
e.printStackTrace(); e.printStackTrace();
Utility.printExecption(LOG, e); Utility.printExecption(LOG, e);
} finally { } finally {
DBUtil.closeDB(connection, statement); DBUtil.closeDB(connection, statement, resultSet);
} }
return null; return null;
} }
@@ -1024,16 +1026,61 @@ public class DatabaseStore {
}); });
} }
MemorySessionStore.Session getSession(String uid, String clientId, ClientSession clientSession) { List<MemorySessionStore.Session> getUserActivedSessions(String uid) {
String sql = "select `_package_name`,`_token`,`_voip_token`,`_secret`,`_db_secret`,`_platform`,`_push_type`,`_device_name`,`_device_version`,`_phone_name`,`_language`,`_carrier_name`, `_dt` from t_user_session where `_uid` = ? and `_cid` = ? limit 1"; String sql = "select `_cid`, `_package_name`,`_token`,`_voip_token`,`_secret`,`_db_secret`,`_platform`,`_push_type`,`_device_name`,`_device_version`,`_phone_name`,`_language`,`_carrier_name`, `_dt` from t_user_session where `_uid` = ? and `_deleted` = 0";
Connection connection = null; Connection connection = null;
PreparedStatement statement = null; PreparedStatement statement = null;
List<MemorySessionStore.Session> result = new ArrayList<>();
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
statement = connection.prepareStatement(sql);
statement.setString(1, uid);
resultSet = statement.executeQuery();
while (resultSet.next()) {
int index = 1;
String cid = resultSet.getString(index++);
ClientSession clientSession = new ClientSession(cid, Server.getServer().getStore().sessionsStore());
MemorySessionStore.Session session = new MemorySessionStore.Session(uid, cid, clientSession);
session.setAppName(resultSet.getString(index++));
session.setDeviceToken(resultSet.getString(index++));
session.setVoipDeviceToken(resultSet.getString(index++));
session.setSecret(resultSet.getString(index++));
session.setDbSecret(resultSet.getString(index++));
session.setPlatform(resultSet.getInt(index++));
session.setPushType(resultSet.getInt(index++));
session.setDeviceName(resultSet.getString(index++));
session.setDeviceVersion(resultSet.getString(index++));
session.setPhoneName(resultSet.getString(index++));
session.setLanguage(resultSet.getString(index++));
session.setCarrierName(resultSet.getString(index++));
session.setUpdateDt(resultSet.getLong(index++));
result.add(session);
}
} catch (SQLException e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement, resultSet);
}
return result;
}
MemorySessionStore.Session getSession(String uid, String clientId, ClientSession clientSession) {
String sql = "select `_package_name`,`_token`,`_voip_token`,`_secret`,`_db_secret`,`_platform`,`_push_type`,`_device_name`,`_device_version`,`_phone_name`,`_language`,`_carrier_name`, `_dt`, `_deleted` from t_user_session where `_uid` = ? and `_cid` = ? limit 1";
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try { try {
connection = DBUtil.getConnection(); connection = DBUtil.getConnection();
statement = connection.prepareStatement(sql); statement = connection.prepareStatement(sql);
statement.setString(1, uid); statement.setString(1, uid);
statement.setString(2, clientId); statement.setString(2, clientId);
ResultSet resultSet = statement.executeQuery(); resultSet = statement.executeQuery();
if (resultSet.next()) { if (resultSet.next()) {
MemorySessionStore.Session session = new MemorySessionStore.Session(uid, clientId, clientSession); MemorySessionStore.Session session = new MemorySessionStore.Session(uid, clientId, clientSession);
@@ -1051,23 +1098,58 @@ public class DatabaseStore {
session.setPhoneName(resultSet.getString(index++)); session.setPhoneName(resultSet.getString(index++));
session.setLanguage(resultSet.getString(index++)); session.setLanguage(resultSet.getString(index++));
session.setCarrierName(resultSet.getString(index++)); session.setCarrierName(resultSet.getString(index++));
session.setUpdateDt(resultSet.getLong(index)); session.setUpdateDt(resultSet.getLong(index++));
session.setDeleted(resultSet.getInt(index));
return session; return session;
} }
resultSet.close();
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
Utility.printExecption(LOG, e); Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement, resultSet);
}
return null;
}
void clearOtherSessionToken(String cid, String token, int pushType, boolean voipToken) {
if (voipToken) {
return;
}
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "update t_user_session set `_token` = ?, `_dt` = ? where `_token` = ? and `_push_type` = ? and `_cid` <> ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setString(index++, "");
statement.setLong(index++, System.currentTimeMillis());
statement.setString(index++, token);
statement.setInt(index++, pushType);
statement.setString(index++, cid);
int c = statement.executeUpdate();
LOG.info("Update rows {}", c);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally { } finally {
DBUtil.closeDB(connection, statement); DBUtil.closeDB(connection, statement);
} }
return null;
} }
void updateSessionToken(String uid, String cid, String token, boolean voipToken) {
void updateSessionToken(String uid, String cid, String token, int pushType, boolean voipToken) {
mScheduler.execute(()->{ mScheduler.execute(()->{
Connection connection = null; Connection connection = null;
PreparedStatement statement = null; PreparedStatement statement = null;
clearOtherSessionToken(cid, token, pushType, voipToken);
try { try {
connection = DBUtil.getConnection(); connection = DBUtil.getConnection();
@@ -1076,12 +1158,15 @@ public class DatabaseStore {
if (voipToken) { if (voipToken) {
sql = "update t_user_session set `_voip_token` = ?, `_dt` = ? where `_uid` = ? and `_cid` = ?"; sql = "update t_user_session set `_voip_token` = ?, `_dt` = ? where `_uid` = ? and `_cid` = ?";
} else { } else {
sql = "update t_user_session set `_token` = ?, `_dt` = ? where `_uid` = ? and `_cid` = ?"; sql = "update t_user_session set `_token` = ?, `_push_type` = ?, `_dt` = ? where `_uid` = ? and `_cid` = ?";
} }
statement = connection.prepareStatement(sql); statement = connection.prepareStatement(sql);
int index = 1; int index = 1;
statement.setString(index++, token); statement.setString(index++, token);
if (!voipToken) {
statement.setInt(index++, pushType);
}
statement.setLong(index++, System.currentTimeMillis()); statement.setLong(index++, System.currentTimeMillis());
statement.setString(index++, uid); statement.setString(index++, uid);
statement.setString(index++, cid); statement.setString(index++, cid);
@@ -1098,6 +1183,64 @@ public class DatabaseStore {
}); });
} }
void updateSessionDeleted(String uid, String cid, int deleted) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "update t_user_session set `_deleted` = ? where `_uid` = ? and `_cid` = ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setInt(index++, deleted);
statement.setString(index++, uid);
statement.setString(index++, cid);
int c = statement.executeUpdate();
LOG.info("Update rows {}", c);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
void updateSessionPlatform(String uid, String cid, int platform) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "update t_user_session set `_platform` = ? where `_uid` = ? and `_cid` = ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setInt(index++, platform);
statement.setString(index++, uid);
statement.setString(index++, cid);
int c = statement.executeUpdate();
LOG.info("Update rows {}", c);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
private boolean strEqual(String left, String right) { private boolean strEqual(String left, String right) {
if (left == right) if (left == right)
return true; return true;
@@ -1190,23 +1333,71 @@ public class DatabaseStore {
}); });
} }
MemorySessionStore.Session createSession(String uid, String clientId, ClientSession clientSession) { void clearMultiEndpoint(String uid, String clientId, int platform) {
LOG.info("clearMultiEndpoint {}, {}", uid, clientId);
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql;
if (platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_OSX
|| platform == ProtoConstants.Platform.Platform_iOS || platform == ProtoConstants.Platform.Platform_Android) {
sql = "update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ? where `_uid`=? and (`_platform` = ? or `_platform` = ?) and `_cid` <> ? and `_deleted` = 0";
} else {
sql = "update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ? where `_uid`=? and `_platform` = ? and `_cid` <> ? and `_deleted` = 0";
}
statement = connection.prepareStatement(sql);
int index = 1;
statement.setInt(index++, 1);
statement.setString(index++, "");
statement.setString(index++, "");
statement.setLong(index++, System.currentTimeMillis());
statement.setString(index++, uid);
if (platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_OSX) {
statement.setInt(index++, ProtoConstants.Platform.Platform_Windows);
statement.setInt(index++, ProtoConstants.Platform.Platform_OSX);
} else if(platform == ProtoConstants.Platform.Platform_iOS || platform == ProtoConstants.Platform.Platform_Android) {
statement.setInt(index++, ProtoConstants.Platform.Platform_iOS);
statement.setInt(index++, ProtoConstants.Platform.Platform_Android);
} else {
statement.setInt(index++, platform);
}
statement.setString(index++, clientId);
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
}
MemorySessionStore.Session createSession(String uid, String clientId, ClientSession clientSession, int platform) {
Connection connection = null; Connection connection = null;
PreparedStatement statement = null; PreparedStatement statement = null;
LOG.info("Database create session {},{}", uid, clientId); LOG.info("Database create session {},{}", uid, clientId);
try { try {
connection = DBUtil.getConnection(); connection = DBUtil.getConnection();
String sql = "insert into t_user_session (`_uid`,`_cid`,`_secret`,`_db_secret`, `_dt`) values (?,?,?,?,?)"; String sql = "insert into t_user_session (`_uid`,`_cid`,`_platform`,`_secret`,`_db_secret`, `_dt`) values (?,?,?,?,?,?)";
statement = connection.prepareStatement(sql); statement = connection.prepareStatement(sql);
int index = 1; int index = 1;
MemorySessionStore.Session session = new MemorySessionStore.Session(uid, clientId, clientSession); MemorySessionStore.Session session = new MemorySessionStore.Session(uid, clientId, clientSession);
session.setPlatform(platform);
statement.setString(index++, uid); statement.setString(index++, uid);
statement.setString(index++, clientId); statement.setString(index++, clientId);
statement.setInt(index++, platform);
session.setSecret(UUID.randomUUID().toString()); session.setSecret(UUID.randomUUID().toString());
@@ -2115,7 +2306,7 @@ public class DatabaseStore {
ResultSet rs = null; ResultSet rs = null;
try { try {
connection = DBUtil.getConnection(); connection = DBUtil.getConnection();
String sql = "select distinct(`_uid`) from t_user_session"; String sql = "select distinct(`_uid`) from t_user_session where `_deleted` = 0";
statement = connection.prepareStatement(sql); statement = connection.prepareStatement(sql);
@@ -2179,13 +2370,20 @@ public class DatabaseStore {
ResultSet rs = null; ResultSet rs = null;
try { try {
connection = DBUtil.getConnection(); connection = DBUtil.getConnection();
String sql = "select `_uid`" + String sql = "select `_uid`" +
", `_friend_uid`" + ", `_friend_uid`" +
", `_reason`" + ", `_reason`" +
", `_status`" + ", `_status`" +
", `_dt`" + ", `_dt`" +
", `_from_read_status`" + ", `_from_read_status`" +
", `_to_read_status` from t_friend_request where `_uid` = ? or `_friend_uid` = ?"; ", `_to_read_status` from t_friend_request where `_uid` = ? UNION ALL " +
"select `_uid`" +
", `_friend_uid`" +
", `_reason`" +
", `_status`" +
", `_dt`" +
", `_from_read_status`" +
", `_to_read_status` from t_friend_request where `_friend_uid` = ?";
statement = connection.prepareStatement(sql); statement = connection.prepareStatement(sql);
int index = 1; int index = 1;
@@ -2040,6 +2040,8 @@ public class MemoryMessagesStore implements IMessagesStore {
public ErrorCode getUserSettings(String userId, long version, WFCMessage.GetUserSettingResult.Builder builder) { public ErrorCode getUserSettings(String userId, long version, WFCMessage.GetUserSettingResult.Builder builder) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance(); HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING); MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);
IMap<String, WFCMessage.GroupInfo> mGroups = hzInstance.getMap(GROUPS_MAP);
IMap<String, WFCMessage.ChannelInfo> mChannels = hzInstance.getMap(CHANNELS);
Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId); Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);
if (entries == null || entries.size() == 0) { if (entries == null || entries.size() == 0) {
@@ -2047,12 +2049,51 @@ public class MemoryMessagesStore implements IMessagesStore {
} }
ErrorCode ec = ErrorCode.ERROR_CODE_NOT_MODIFIED; ErrorCode ec = ErrorCode.ERROR_CODE_NOT_MODIFIED;
Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.add(Calendar.MONTH, -1);
long monthAgo = c.getTimeInMillis();
if (entries != null) { if (entries != null) {
for (WFCMessage.UserSettingEntry entry : entries for (WFCMessage.UserSettingEntry entry : entries
) { ) {
if (entry.getUpdateDt() > version) { if (entry.getUpdateDt() > version) {
ec = ErrorCode.ERROR_CODE_SUCCESS; ec = ErrorCode.ERROR_CODE_SUCCESS;
builder.addEntry(entry); boolean skip = false;
if (version == 0 && entry.getUpdateDt() > monthAgo) {
if (entry.getScope() == UserSettingScope.kUserSettingConversationSync) {
try {
String key = entry.getKey();
int pos1 = key.indexOf('-');
String typeStr = key.substring(0, pos1);
int type = Integer.parseInt(typeStr);
if (type == ProtoConstants.ConversationType.ConversationType_Group
|| type == ProtoConstants.ConversationType.ConversationType_Channel) {
int pos2 = key.indexOf('-', pos1 + 1);
String target = key.substring(pos2 + 1);
if (type == ProtoConstants.ConversationType.ConversationType_Group) {
WFCMessage.GroupInfo groupInfo = mGroups.get(target);
if (groupInfo == null) {
skip = true;
}
} else {
WFCMessage.ChannelInfo channelInfo = mChannels.get(target);
if (channelInfo == null) {
skip = true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!skip) {
builder.addEntry(entry);
}
} }
} }
} }
@@ -16,7 +16,11 @@
package io.moquette.persistence; package io.moquette.persistence;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage; import cn.wildfirechat.proto.WFCMessage;
import com.hazelcast.util.StringUtil;
import io.moquette.BrokerConstants;
import io.moquette.server.Constants; import io.moquette.server.Constants;
import io.moquette.server.Server; import io.moquette.server.Server;
import io.moquette.spi.ClientSession; import io.moquette.spi.ClientSession;
@@ -26,7 +30,6 @@ import io.moquette.spi.ISessionsStore;
import io.netty.handler.codec.mqtt.MqttVersion; import io.netty.handler.codec.mqtt.MqttVersion;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import cn.wildfirechat.common.ErrorCode;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
@@ -35,6 +38,8 @@ public class MemorySessionStore implements ISessionsStore {
private static int dumy = 1; private static int dumy = 1;
private static final Logger LOG = LoggerFactory.getLogger(MemorySessionStore.class); private static final Logger LOG = LoggerFactory.getLogger(MemorySessionStore.class);
private boolean supportMultiEndpoint = false;
public static class Session implements Comparable<Session>{ public static class Session implements Comparable<Session>{
final String clientID; final String clientID;
String username; String username;
@@ -50,6 +55,16 @@ public class MemorySessionStore implements ISessionsStore {
private volatile int unReceivedMsgs; private volatile int unReceivedMsgs;
private int deleted;
public int getDeleted() {
return deleted;
}
public void setDeleted(int deleted) {
this.deleted = deleted;
}
private MqttVersion mqttVersion = MqttVersion.MQTT_3_1_1; private MqttVersion mqttVersion = MqttVersion.MQTT_3_1_1;
public long getLastActiveTime() { public long getLastActiveTime() {
@@ -130,6 +145,9 @@ public class MemorySessionStore implements ISessionsStore {
public void setUpdateDt(long updateDt) { public void setUpdateDt(long updateDt) {
this.updateDt = updateDt; this.updateDt = updateDt;
if (this.lastActiveTime == 0) {
this.lastActiveTime = updateDt;
}
} }
private int pushType; private int pushType;
@@ -248,8 +266,14 @@ public class MemorySessionStore implements ISessionsStore {
private final Server mServer; private final Server mServer;
private final DatabaseStore databaseStore; private final DatabaseStore databaseStore;
public MemorySessionStore(Server server, DatabaseStore databaseStore) { public MemorySessionStore(Server server, DatabaseStore databaseStore) {
mServer = server; mServer = server;
this.databaseStore = databaseStore; this.databaseStore = databaseStore;
try {
supportMultiEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_ENDPOINT));
} catch (Exception e) {
e.printStackTrace();
}
} }
@Override @Override
@@ -261,6 +285,21 @@ public class MemorySessionStore implements ISessionsStore {
return session; return session;
} }
@Override
public void cleanDuplatedToken(String cid, int pushType, String token, boolean isVoip) {
if (StringUtil.isNullOrEmpty(token) || isVoip) {
return;
}
Iterator<Map.Entry<String, Session>> it = sessions.entrySet().iterator();
while (it.hasNext()) {
Session session = it.next().getValue();
if (!session.getClientID().equals(cid) && (session.pushType == pushType && token.equals(session.deviceToken))) {
session.deviceToken = null;
}
}
}
@Override @Override
public void initStore() { public void initStore() {
} }
@@ -272,18 +311,64 @@ public class MemorySessionStore implements ISessionsStore {
@Override @Override
public void updateSessionToken(Session session, boolean voip) { public void updateSessionToken(Session session, boolean voip) {
databaseStore.updateSessionToken(session.getUsername(), session.getClientID(), voip ? session.getVoipDeviceToken() : session.getDeviceToken(), voip); databaseStore.updateSessionToken(session.getUsername(), session.getClientID(), voip ? session.getVoipDeviceToken() : session.getDeviceToken(), session.getPushType(), voip);
} }
@Override @Override
public Session createUserSession(String username, String clientID) { public Session createUserSession(String username, String clientID, int platform) {
LOG.debug("createUserSession for client <{}>, user <{}>", clientID, username); LOG.debug("createUserSession for client <{}>, user <{}>", clientID, username);
ClientSession clientSession = new ClientSession(clientID, this); ClientSession clientSession = new ClientSession(clientID, this);
Session session = databaseStore.getSession(username, clientID, clientSession); Session session = databaseStore.getSession(username, clientID, clientSession);
if (session == null) { if (session == null) {
session = databaseStore.createSession(username, clientID, clientSession); session = databaseStore.createSession(username, clientID, clientSession, platform);
}
if (session.getDeleted() > 0) {
session.setDeleted(0);
databaseStore.updateSessionDeleted(username, clientID, 0);
}
if (session.getPlatform() != platform) {
session.setPlatform(platform);
databaseStore.updateSessionPlatform(username, clientID, platform);
}
if (!supportMultiEndpoint && platform > 0) {
databaseStore.clearMultiEndpoint(username, clientID, platform);
if (userSessions.get(username) != null) {
Iterator<String> it = userSessions.get(username).iterator();
while (it.hasNext()) {
String c = it.next();
if (!clientID.equals(c)) {
Session s = sessions.get(c);
boolean remove = false;
if (platform == ProtoConstants.Platform.Platform_Android || platform == ProtoConstants.Platform.Platform_iOS) {
if (s.getPlatform() == ProtoConstants.Platform.Platform_Android || s.getPlatform() == ProtoConstants.Platform.Platform_iOS) {
remove = true;
}
} else if(platform == ProtoConstants.Platform.Platform_OSX || platform == ProtoConstants.Platform.Platform_Windows) {
if (s.getPlatform() == ProtoConstants.Platform.Platform_OSX || s.getPlatform() == ProtoConstants.Platform.Platform_Windows) {
remove = true;
}
} else {
if (s.getPlatform() ==platform) {
remove = true;
}
}
if (remove) {
sessions.remove(c);
mServer.getProcessor().kickoffSession(s);
it.remove();
}
}
}
}
} }
return session; return session;
@@ -291,34 +376,29 @@ public class MemorySessionStore implements ISessionsStore {
@Override @Override
public ErrorCode createNewSession(String username, String clientID, boolean cleanSession, boolean createWhenNoExist) { public ErrorCode loadActiveSession(String username, String clientID) {
LOG.debug("createNewSession for client <{}>", clientID); LOG.debug("createNewSession for client <{}>", clientID);
Session session = sessions.get(clientID); Session session = sessions.get(clientID);
if (session != null) {
if (session != null && session.getDeleted() == 0) {
LOG.error("already exists a session for client <{}>, bad condition", clientID); LOG.error("already exists a session for client <{}>, bad condition", clientID);
throw new IllegalArgumentException("Can't create a session with the ID of an already existing" + clientID); throw new IllegalArgumentException("Can't create a session with the ID of an already existing" + clientID);
} }
if (session != null && session.getDeleted() > 0) {
return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;
}
ClientSession clientSession = new ClientSession(clientID, this); ClientSession clientSession = new ClientSession(clientID, this);
session = databaseStore.getSession(username, clientID, clientSession); session = databaseStore.getSession(username, clientID, clientSession);
if (session == null) { if (session == null || session.getDeleted() > 0) {
if (!createWhenNoExist) { return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;
return ErrorCode.ERROR_CODE_NOT_EXIST;
}
session = databaseStore.createSession(username, clientID, clientSession);
} }
sessions.put(clientID, session); sessions.put(clientID, session);
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username); ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
if (sessionSet == null) {
sessionSet = new ConcurrentSkipListSet<>();
userSessions.put(username, sessionSet);
}
sessionSet = userSessions.get(username);
sessionSet.add(clientID); sessionSet.add(clientID);
return ErrorCode.ERROR_CODE_SUCCESS; return ErrorCode.ERROR_CODE_SUCCESS;
@@ -342,12 +422,7 @@ public class MemorySessionStore implements ISessionsStore {
session.setUsername(username); session.setUsername(username);
sessions.put(clientID, session); sessions.put(clientID, session);
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username); ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
if (sessionSet == null) {
sessionSet = new ConcurrentSkipListSet<>();
userSessions.put(username, sessionSet);
}
sessionSet = userSessions.get(username);
sessionSet.add(clientID); sessionSet.add(clientID);
if (endpoint != null) { if (endpoint != null) {
@@ -393,14 +468,26 @@ public class MemorySessionStore implements ISessionsStore {
} }
} }
private ConcurrentSkipListSet<String> getUserSessionSet(String username) {
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username);
if (sessionSet == null) {
sessionSet = new ConcurrentSkipListSet<String>();
List<Session> ss = databaseStore.getUserActivedSessions(username);
for (Session s : ss) {
sessionSet.add(s.getClientID());
sessions.put(s.getClientID(), s);
}
userSessions.put(username, sessionSet);
}
sessionSet = userSessions.get(username);
return sessionSet;
}
@Override @Override
public Collection<Session> sessionForUser(String username) { public Collection<Session> sessionForUser(String username) {
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username); ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
if (sessionSet == null) {
sessionSet = new ConcurrentSkipListSet<String>();
userSessions.put(username, sessionSet);
}
sessionSet = userSessions.get(username);
ArrayList<Session> out = new ArrayList<>(); ArrayList<Session> out = new ArrayList<>();
for (String clientId : sessionSet for (String clientId : sessionSet
) { ) {
@@ -466,7 +553,9 @@ public class MemorySessionStore implements ISessionsStore {
@Override @Override
public void dropQueue(String clientID) { public void dropQueue(String clientID) {
sessions.get(clientID).queue.clear(); if (sessions.get(clientID) != null) {
sessions.get(clientID).queue.clear();
}
} }
@Override @Override
@@ -542,12 +631,7 @@ public class MemorySessionStore implements ISessionsStore {
LOG.error("Can't find the session for client <{}>", clientID); LOG.error("Can't find the session for client <{}>", clientID);
return; return;
} }
ConcurrentSkipListSet<String> sessionSet = userSessions.get(session.username); ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);
if (sessionSet == null) {
sessionSet = new ConcurrentSkipListSet<>();
userSessions.put(session.username, sessionSet);
}
sessionSet = userSessions.get(session.username);
sessionSet.remove(clientID); sessionSet.remove(clientID);
// remove also the messages stored of type QoS1/2 // remove also the messages stored of type QoS1/2
@@ -38,14 +38,16 @@ public interface ISessionsStore {
*/ */
boolean contains(String clientID); boolean contains(String clientID);
Session createUserSession(String username, String clientID); Session createUserSession(String username, String clientID, int platform);
ErrorCode createNewSession(String username, String clientID, boolean cleanSession, boolean createNoExist); ErrorCode loadActiveSession(String username, String clientID);
ClientSession updateExistSession(String username, String clientID, WFCMessage.RouteRequest endpoint, boolean cleanSession); ClientSession updateExistSession(String username, String clientID, WFCMessage.RouteRequest endpoint, boolean cleanSession);
Session getSession(String clientID); Session getSession(String clientID);
void cleanDuplatedToken(String cid, int pushType, String token, boolean isVoip);
void updateSessionToken(Session session, boolean voip); void updateSessionToken(Session session, boolean voip);
/** /**
* @param clientID * @param clientID
@@ -16,6 +16,7 @@
package io.moquette.spi.impl; package io.moquette.spi.impl;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.proto.WFCMessage; import cn.wildfirechat.proto.WFCMessage;
import io.moquette.persistence.RPCCenter; import io.moquette.persistence.RPCCenter;
import io.moquette.interception.InterceptHandler; import io.moquette.interception.InterceptHandler;
@@ -55,7 +56,24 @@ import static io.moquette.server.ConnectionDescriptor.ConnectionState.*;
* *
* Used by the front facing class ProtocolProcessorBootstrapper. * Used by the front facing class ProtocolProcessorBootstrapper.
*/ */
public class ProtocolProcessor { public class ProtocolProcessor {
public void kickoffSession(final MemorySessionStore.Session session) {
mServer.getImBusinessScheduler().execute(()->{
ConnectionDescriptor descriptor = connectionDescriptors.getConnection(session.getClientID());
try {
if (descriptor != null) {
processDisconnect(descriptor.getChannel(), true);
}
} catch (InterruptedException e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
}
});
}
private void handleTargetRemovedFromCurrentNode(TargetEntry target) { private void handleTargetRemovedFromCurrentNode(TargetEntry target) {
System.out.println("kickof user " + target); System.out.println("kickof user " + target);
if (target.type == TargetEntry.Type.TARGET_TYPE_USER) { if (target.type == TargetEntry.Type.TARGET_TYPE_USER) {
@@ -164,7 +182,11 @@ public class ProtocolProcessor {
MqttVersion mqttVersion = MqttVersion.fromProtocolLevel(msg.variableHeader().version()); MqttVersion mqttVersion = MqttVersion.fromProtocolLevel(msg.variableHeader().version());
if (!login(channel, msg, clientId, mqttVersion)) { if (!login(channel, msg, clientId, mqttVersion)) {
MqttConnAckMessage badId = connAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD);
channel.writeAndFlush(badId);
channel.close(); channel.close();
LOG.error("The MQTT login failure. Username={}", payload.userName());
return; return;
} }
if (!mServer.m_initialized) { if (!mServer.m_initialized) {
@@ -253,9 +275,16 @@ public class ProtocolProcessor {
MemorySessionStore.Session session = m_sessionsStore.getSession(clientId); MemorySessionStore.Session session = m_sessionsStore.getSession(clientId);
if (session == null) { if (session == null) {
m_sessionsStore.createNewSession(msg.payload().userName(), clientId, true, false); ErrorCode errorCode = m_sessionsStore.loadActiveSession(msg.payload().userName(), clientId);
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
return false;
}
session = m_sessionsStore.getSession(clientId); session = m_sessionsStore.getSession(clientId);
} }
if (session.getDeleted() != 0) {
return false;
}
if (session != null && session.getUsername().equals(msg.payload().userName())) { if (session != null && session.getUsername().equals(msg.payload().userName())) {
pwd = AES.AESDecrypt(pwd, session.getSecret(), true); pwd = AES.AESDecrypt(pwd, session.getSecret(), true);
@@ -501,15 +530,12 @@ public class ProtocolProcessor {
return; return;
} }
boolean stillPresent = this.connectionDescriptors.removeConnection(existingDescriptor); this.connectionDescriptors.removeConnection(existingDescriptor);
if (!stillPresent) {
// another descriptor was inserted
LOG.warn("Another descriptor has been inserted. CId={}", clientID);
return;
}
LOG.info("The DISCONNECT message has been processed. CId={}", clientID); LOG.info("The DISCONNECT message has been processed. CId={}", clientID);
channel.closeFuture();
//disconnect the session //disconnect the session
m_sessionsStore.sessionForClient(clientID).disconnect(clearSession); m_sessionsStore.sessionForClient(clientID).disconnect(clearSession);
} }
@@ -52,7 +52,7 @@ public class HttpUtils {
@Override @Override
public void onResponse(Call call, Response response) throws IOException { public void onResponse(Call call, Response response) throws IOException {
LOG.info("POST to {} success with response", url, response.body().string()); LOG.info("POST to {} success with response: {}", url, response.body());
} }
}); });
} }
+1 -1
View File
@@ -22,7 +22,7 @@
<!--MySQL数据库用户名--> <!--MySQL数据库用户名-->
<property name="user">root</property> <property name="user">root</property>
<!--MySQL数据库密码--> <!--MySQL数据库密码-->
<property name="password">lt123456</property> <property name="password">123456</property>
<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3--> <!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
<property name="initialPoolSize">10</property> <property name="initialPoolSize">10</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 --> <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->
+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.31</version> <version>0.33</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -3,10 +3,20 @@ package cn.wildfirechat.pojos;
public class InputGetToken { public class InputGetToken {
private String userId; private String userId;
private String clientId; private String clientId;
private Integer platform;
public InputGetToken(String userId, String clientId) { public InputGetToken(String userId, String clientId, int platform) {
this.userId = userId; this.userId = userId;
this.clientId = clientId; this.clientId = clientId;
this.platform = platform;
}
public Integer getPlatform() {
return platform;
}
public void setPlatform(Integer platform) {
this.platform = platform;
} }
public String getUserId() { public String getUserId() {
@@ -57571,6 +57571,16 @@ public final class WFCMessage {
*/ */
com.google.protobuf.ByteString com.google.protobuf.ByteString
getClientIdBytes(); getClientIdBytes();
// optional int32 platform = 3;
/**
* <code>optional int32 platform = 3;</code>
*/
boolean hasPlatform();
/**
* <code>optional int32 platform = 3;</code>
*/
int getPlatform();
} }
/** /**
* Protobuf type {@code GetTokenRequest} * Protobuf type {@code GetTokenRequest}
@@ -57633,6 +57643,11 @@ public final class WFCMessage {
clientId_ = input.readBytes(); clientId_ = input.readBytes();
break; break;
} }
case 24: {
bitField0_ |= 0x00000004;
platform_ = input.readInt32();
break;
}
} }
} }
} catch (com.google.protobuf.InvalidProtocolBufferException e) { } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -57759,9 +57774,26 @@ public final class WFCMessage {
} }
} }
// optional int32 platform = 3;
public static final int PLATFORM_FIELD_NUMBER = 3;
private int platform_;
/**
* <code>optional int32 platform = 3;</code>
*/
public boolean hasPlatform() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
/**
* <code>optional int32 platform = 3;</code>
*/
public int getPlatform() {
return platform_;
}
private void initFields() { private void initFields() {
userId_ = ""; userId_ = "";
clientId_ = ""; clientId_ = "";
platform_ = 0;
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@@ -57789,6 +57821,9 @@ public final class WFCMessage {
if (((bitField0_ & 0x00000002) == 0x00000002)) { if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeBytes(2, getClientIdBytes()); output.writeBytes(2, getClientIdBytes());
} }
if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeInt32(3, platform_);
}
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@@ -57806,6 +57841,10 @@ public final class WFCMessage {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeBytesSize(2, getClientIdBytes()); .computeBytesSize(2, getClientIdBytes());
} }
if (((bitField0_ & 0x00000004) == 0x00000004)) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(3, platform_);
}
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@@ -57926,6 +57965,8 @@ public final class WFCMessage {
bitField0_ = (bitField0_ & ~0x00000001); bitField0_ = (bitField0_ & ~0x00000001);
clientId_ = ""; clientId_ = "";
bitField0_ = (bitField0_ & ~0x00000002); bitField0_ = (bitField0_ & ~0x00000002);
platform_ = 0;
bitField0_ = (bitField0_ & ~0x00000004);
return this; return this;
} }
@@ -57962,6 +58003,10 @@ public final class WFCMessage {
to_bitField0_ |= 0x00000002; to_bitField0_ |= 0x00000002;
} }
result.clientId_ = clientId_; result.clientId_ = clientId_;
if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
to_bitField0_ |= 0x00000004;
}
result.platform_ = platform_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
return result; return result;
@@ -57988,6 +58033,9 @@ public final class WFCMessage {
clientId_ = other.clientId_; clientId_ = other.clientId_;
onChanged(); onChanged();
} }
if (other.hasPlatform()) {
setPlatform(other.getPlatform());
}
this.mergeUnknownFields(other.getUnknownFields()); this.mergeUnknownFields(other.getUnknownFields());
return this; return this;
} }
@@ -58171,6 +58219,39 @@ public final class WFCMessage {
return this; return this;
} }
// optional int32 platform = 3;
private int platform_ ;
/**
* <code>optional int32 platform = 3;</code>
*/
public boolean hasPlatform() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
/**
* <code>optional int32 platform = 3;</code>
*/
public int getPlatform() {
return platform_;
}
/**
* <code>optional int32 platform = 3;</code>
*/
public Builder setPlatform(int value) {
bitField0_ |= 0x00000004;
platform_ = value;
onChanged();
return this;
}
/**
* <code>optional int32 platform = 3;</code>
*/
public Builder clearPlatform() {
bitField0_ = (bitField0_ & ~0x00000004);
platform_ = 0;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:GetTokenRequest) // @@protoc_insertion_point(builder_scope:GetTokenRequest)
} }
@@ -60361,14 +60442,15 @@ public final class WFCMessage {
"\001(\t\022\020\n\010language\030\007 \001(\t\022\024\n\014carrier_name\030\010 " + "\001(\t\022\020\n\010language\030\007 \001(\t\022\024\n\014carrier_name\030\010 " +
"\001(\t\022\023\n\013app_version\030\t \001(\t\022\023\n\013sdk_version\030" + "\001(\t\022\023\n\013app_version\030\t \001(\t\022\023\n\013sdk_version\030" +
"\n \001(\t\"D\n\rRouteResponse\022\014\n\004host\030\001 \002(\t\022\021\n\t" + "\n \001(\t\"D\n\rRouteResponse\022\014\n\004host\030\001 \002(\t\022\021\n\t" +
"long_port\030\002 \002(\005\022\022\n\nshort_port\030\003 \002(\005\"5\n\017G" + "long_port\030\002 \002(\005\022\022\n\nshort_port\030\003 \002(\005\"G\n\017G" +
"etTokenRequest\022\017\n\007user_id\030\001 \002(\t\022\021\n\tclien", "etTokenRequest\022\017\n\007user_id\030\001 \002(\t\022\021\n\tclien",
"t_id\030\002 \002(\t\"\\\n\022LoadRemoteMessages\022#\n\014conv" + "t_id\030\002 \002(\t\022\020\n\010platform\030\003 \001(\005\"\\\n\022LoadRemo" +
"ersation\030\001 \002(\0132\r.Conversation\022\022\n\nbefore_" + "teMessages\022#\n\014conversation\030\001 \002(\0132\r.Conve" +
"uid\030\002 \002(\003\022\r\n\005count\030\003 \002(\005\"a\n\020MultiCastMes" + "rsation\022\022\n\nbefore_uid\030\002 \002(\003\022\r\n\005count\030\003 \002" +
"sage\022\021\n\tfrom_user\030\001 \002(\t\022 \n\007content\030\002 \002(\013" + "(\005\"a\n\020MultiCastMessage\022\021\n\tfrom_user\030\001 \002(" +
"2\017.MessageContent\022\n\n\002to\030\003 \003(\t\022\014\n\004line\030\004 " + "\t\022 \n\007content\030\002 \002(\0132\017.MessageContent\022\n\n\002t" +
"\002(\005B#\n\025cn.wildfirechat.protoB\nWFCMessage" "o\030\003 \003(\t\022\014\n\004line\030\004 \002(\005B#\n\025cn.wildfirechat" +
".protoB\nWFCMessage"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -60794,7 +60876,7 @@ public final class WFCMessage {
internal_static_GetTokenRequest_fieldAccessorTable = new internal_static_GetTokenRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_GetTokenRequest_descriptor, internal_static_GetTokenRequest_descriptor,
new java.lang.String[] { "UserId", "ClientId", }); new java.lang.String[] { "UserId", "ClientId", "Platform", });
internal_static_LoadRemoteMessages_descriptor = internal_static_LoadRemoteMessages_descriptor =
getDescriptor().getMessageTypes().get(70); getDescriptor().getMessageTypes().get(70);
internal_static_LoadRemoteMessages_fieldAccessorTable = new internal_static_LoadRemoteMessages_fieldAccessorTable = new
+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.31</version> <version>0.33</version>
</parent> </parent>
<artifactId>distribution</artifactId> <artifactId>distribution</artifactId>
@@ -95,6 +95,10 @@ qiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn
# 本地媒体服务器配置。 # 本地媒体服务器配置。
local.media.storage.root ./media local.media.storage.root ./media
# 是否支持多端登陆
server.multi_endpoint false
#********************************************************************* #*********************************************************************
# Push server configuration # Push server configuration
#********************************************************************* #*********************************************************************
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId> <artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>0.31</version> <version>0.33</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.31</version> <version>0.33</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -98,7 +98,7 @@ public class Main {
System.exit(-1); System.exit(-1);
} }
IMResult<OutputGetIMTokenData> resultGetToken = UserAdmin.getUserToken(userInfo.getUserId(), "client111"); IMResult<OutputGetIMTokenData> resultGetToken = UserAdmin.getUserToken(userInfo.getUserId(), "client111", ProtoConstants.Platform.Platform_Android);
if (resultGetToken != null && resultGetToken.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) { if (resultGetToken != null && resultGetToken.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
System.out.println("get token success: " + resultGetToken.getResult().getToken()); System.out.println("get token success: " + resultGetToken.getResult().getToken());
} else { } else {
@@ -2,6 +2,7 @@ package cn.wildfirechat.sdk;
import cn.wildfirechat.common.APIPath; import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.pojos.*; import cn.wildfirechat.pojos.*;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.sdk.model.IMResult; import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.AdminHttpUtils; import cn.wildfirechat.sdk.utilities.AdminHttpUtils;
@@ -34,9 +35,9 @@ public class UserAdmin {
return AdminHttpUtils.httpJsonPost(path, robot, OutputCreateRobot.class); return AdminHttpUtils.httpJsonPost(path, robot, OutputCreateRobot.class);
} }
public static IMResult<OutputGetIMTokenData> getUserToken(String userId, String clientId) throws Exception { public static IMResult<OutputGetIMTokenData> getUserToken(String userId, String clientId, int platform) throws Exception {
String path = APIPath.User_Get_Token; String path = APIPath.User_Get_Token;
InputGetToken getToken = new InputGetToken(userId, clientId); InputGetToken getToken = new InputGetToken(userId, clientId, platform);
return AdminHttpUtils.httpJsonPost(path, getToken, OutputGetIMTokenData.class); return AdminHttpUtils.httpJsonPost(path, getToken, OutputGetIMTokenData.class);
} }