Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61dc1e2c2d | ||
|
|
2458782c73 | ||
|
|
0f05d63a3b | ||
|
|
b82f7dea3d | ||
|
|
6df626afd3 | ||
|
|
ac2d2a530a | ||
|
|
99a0590c7e | ||
|
|
58c98bbbfa | ||
|
|
9560b9c202 | ||
|
|
24ebe429cc | ||
|
|
8ef92d0c1b | ||
|
|
e3e122edc4 | ||
|
|
ab0e51feac |
@@ -47,3 +47,7 @@ broker/nbactions-Server.xml
|
||||
maven-metadata.xml
|
||||
/.gradle/
|
||||
/bin/
|
||||
broker/config/git.properties
|
||||
distribution/src/main/resources/git.properties
|
||||
broker/h2db
|
||||
broker/media
|
||||
|
||||
@@ -53,51 +53,3 @@ Except for the limited purpose of indicating to the public that the Work is lice
|
||||
|
||||
Creative Commons may be contacted at http://creativecommons.org/.
|
||||
|
||||
|
||||
Copyright (c) <2019> <wildfirechat>
|
||||
|
||||
996 License Version 1.0 (Draft)
|
||||
|
||||
Permission is hereby granted to any individual or legal entity
|
||||
obtaining a copy of this licensed work (including the source code,
|
||||
documentation and/or related items, hereinafter collectively referred
|
||||
to as the "licensed work"), free of charge, to deal with the licensed
|
||||
work for any purpose, including without limitation, the rights to use,
|
||||
reproduce, prepare derivative works of, distribute and sublicense the
|
||||
licensed work, subject to the following conditions:
|
||||
|
||||
1. The individual or the legal entity must conspicuously display,
|
||||
without modification, this License on each redistributed or derivative
|
||||
copy of the Licensed Work.
|
||||
|
||||
2. The individual or the legal entity must strictly comply with all
|
||||
applicable laws, regulations, rules and standards of the jurisdiction
|
||||
relating to labor and employment where the individual is physically
|
||||
located or where the individual was born or naturalized; or where the
|
||||
legal entity is registered or is operating (whichever is stricter). In
|
||||
case that the jurisdiction has no such laws, regulations, rules and
|
||||
standards or its laws, regulations, rules and standards are
|
||||
unenforceable, the individual or the legal entity are required to
|
||||
comply with Core International Labor Standards.
|
||||
|
||||
3. The individual or the legal entity shall not induce or force its
|
||||
employee(s), whether full-time or part-time, or its independent
|
||||
contractor(s), in any methods, to agree in oral or written form, to
|
||||
directly or indirectly restrict, weaken or relinquish his or her
|
||||
rights or remedies under such laws, regulations, rules and standards
|
||||
relating to labor and employment as mentioned above, no matter whether
|
||||
such written or oral agreement are enforceable under the laws of the
|
||||
said jurisdiction, nor shall such individual or the legal entity
|
||||
limit, in any methods, the rights of its employee(s) or independent
|
||||
contractor(s) from reporting or complaining to the copyright holder or
|
||||
relevant authorities monitoring the compliance of the license about
|
||||
its violation(s) of the said license.
|
||||
|
||||
THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE
|
||||
LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK.
|
||||
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
Copyright (c) <2019> <wildfirechat>
|
||||
|
||||
Anti 996 License Version 1.0 (Draft)
|
||||
|
||||
Permission is hereby granted to any individual or legal entity
|
||||
obtaining a copy of this licensed work (including the source code,
|
||||
documentation and/or related items, hereinafter collectively referred
|
||||
to as the "licensed work"), free of charge, to deal with the licensed
|
||||
work for any purpose, including without limitation, the rights to use,
|
||||
reproduce, modify, prepare derivative works of, distribute, publish
|
||||
and sublicense the licensed work, subject to the following conditions:
|
||||
|
||||
1. The individual or the legal entity must conspicuously display,
|
||||
without modification, this License and the notice on each redistributed
|
||||
or derivative copy of the Licensed Work.
|
||||
|
||||
2. The individual or the legal entity must strictly comply with all
|
||||
applicable laws, regulations, rules and standards of the jurisdiction
|
||||
relating to labor and employment where the individual is physically
|
||||
located or where the individual was born or naturalized; or where the
|
||||
legal entity is registered or is operating (whichever is stricter). In
|
||||
case that the jurisdiction has no such laws, regulations, rules and
|
||||
standards or its laws, regulations, rules and standards are
|
||||
unenforceable, the individual or the legal entity are required to
|
||||
comply with Core International Labor Standards.
|
||||
|
||||
3. The individual or the legal entity shall not induce or force its
|
||||
employee(s), whether full-time or part-time, or its independent
|
||||
contractor(s), in any methods, to agree in oral or written form, to
|
||||
directly or indirectly restrict, weaken or relinquish his or her
|
||||
rights or remedies under such laws, regulations, rules and standards
|
||||
relating to labor and employment as mentioned above, no matter whether
|
||||
such written or oral agreement are enforceable under the laws of the
|
||||
said jurisdiction, nor shall such individual or the legal entity
|
||||
limit, in any methods, the rights of its employee(s) or independent
|
||||
contractor(s) from reporting or complaining to the copyright holder or
|
||||
relevant authorities monitoring the compliance of the license about
|
||||
its violation(s) of the said license.
|
||||
|
||||
THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE
|
||||
LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK.
|
||||
@@ -2,20 +2,20 @@
|
||||
|
||||
野火IM是一套跨平台、全开源的即时通讯解决方案,主要包含以下内容。
|
||||
|
||||
| 仓库 | 说明 | 备注 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------- | ---- |
|
||||
| [android-chat](https://github.com/wildfirechat/android-chat) | Android平台的SDK和Demo | |
|
||||
| [ios-chat](https://github.com/wildfirechat/ios-chat) | iOS平台的SDK和Demo | |
|
||||
| [pc-chat](https://github.com/wildfirechat/pc-chat) | 基于[Electron](https://electronjs.org/)开发的PC平台Demo | |
|
||||
| [proto](https://github.com/wildfirechat/proto) | 野火IM的协议栈实现 | |
|
||||
| [server](https://github.com/wildfirechat/server) | IM server | |
|
||||
| [app server](https://github.com/wildfirechat/app_server) | 应用服务端Demo | |
|
||||
| [robot_server](https://github.com/wildfirechat/robot_server) | 机器人服务端Demo | |
|
||||
| [push_server](https://github.com/wildfirechat/push_server) | 推送服务器 | |
|
||||
| [docs](https://github.com/wildfirechat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明 | |
|
||||
| 仓库 | 说明 | 备注 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------- |
|
||||
| [android-chat](https://github.com/wildfirechat/android-chat) | 野火IM Android App | 可以很方便地进行二次开发,或集成到现有应用当中 |
|
||||
| [ios-chat](https://github.com/wildfirechat/ios-chat) | 野火IM iOS App | 可以很方便地进行二次开发,或集成到现有应用当中 |
|
||||
| [pc-chat](https://github.com/wildfirechat/pc-chat) | 基于[Electron](https://electronjs.org/)开发的PC平台应用 | |
|
||||
| [proto](https://github.com/wildfirechat/proto) | 野火IM的协议栈实现 | |
|
||||
| [server](https://github.com/wildfirechat/server) | IM server | |
|
||||
| [app server](https://github.com/wildfirechat/app_server) | 应用服务端 | |
|
||||
| [robot_server](https://github.com/wildfirechat/robot_server) | 机器人服务端 | |
|
||||
| [push_server](https://github.com/wildfirechat/push_server) | 推送服务器 | |
|
||||
| [docs](https://github.com/wildfirechat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明 | |
|
||||
|
||||
# server
|
||||
本工程为野火IM 社区版IM服务软件。野火IM作为一个通用的即时通讯SDK,可以集成到各种应用中。请阅读[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)
|
||||
|
||||
|
||||
开发一套IM系统真的很艰辛,请路过的朋友们给点个star,支持我们坚持下去🙏🙏🙏🙏🙏
|
||||
@@ -53,3 +53,10 @@
|
||||
<img src="http://static.wildfirechat.cn/ios-location-view.png" width = 50% height = 50% />
|
||||
|
||||
<img src="http://static.wildfirechat.cn/ios-voip-view.png" width = 50% height = 50% />
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
1. Under the Creative Commons Attribution-NoDerivs 3.0 Unported license. See the [LICENSE](https://github.com/wildfirechat/server/blob/wildfirechat/LICENSE) file for details.
|
||||
2. Under the Anti 996 License. See the [Anti 996 LICENSE](https://github.com/wildfirechat/server/blob/wildfirechat/LICENSE_996) file for details.
|
||||
@@ -1,15 +0,0 @@
|
||||
#Generated by Git-Commit-Id-Plugin
|
||||
#Wed Apr 03 15:25:25 CST 2019
|
||||
git.commit.id.abbrev=cc82c5b
|
||||
git.commit.user.email=[email protected]
|
||||
git.commit.message.full=update version to 0.1.1\n
|
||||
git.commit.id=cc82c5b420061994bc0621e807bb6c961370aef2
|
||||
git.commit.message.short=update version to 0.1.1
|
||||
git.commit.user.name=heavyrain2012
|
||||
git.build.user.name=heavyrain2012
|
||||
git.commit.id.describe=0.1.1-dirty
|
||||
git.build.user.email=[email protected]
|
||||
git.branch=wildfirechat
|
||||
git.commit.time=20190403134707
|
||||
git.build.time=20190403152525
|
||||
git.remote.origin.url=https\://github.com/wildfirechat/server.git
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.11</version>
|
||||
<version>0.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>moquette-broker</artifactId>
|
||||
|
||||
@@ -41,7 +41,7 @@ public class VersionAction extends Action {
|
||||
response.setContent(new Gson().toJson(GitRepositoryState.getGitRepositoryState()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
response.setContent("No version info!");
|
||||
response.setContent("{\"version\":\"unknown\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract public class RobotAction extends Action {
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (mLimitCounter.isGranted(rid)) {
|
||||
if (!mLimitCounter.isGranted(rid)) {
|
||||
return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,10 +76,12 @@ public class GetQiniuUploadTokenHandler extends IMHandler<Byte> {
|
||||
token = auth.uploadToken(bucketName);
|
||||
resultBuilder.setDomain(bucketDomain)
|
||||
.setServer(MediaServerConfig.QINIU_SERVER_URL);
|
||||
resultBuilder.setPort(80);
|
||||
} else {
|
||||
token = UploadFileAction.getToken(type);
|
||||
resultBuilder.setDomain("http://" + MediaServerConfig.SERVER_IP + ":" + MediaServerConfig.HTTP_SERVER_PORT)
|
||||
.setServer(MediaServerConfig.SERVER_IP);
|
||||
resultBuilder.setPort(MediaServerConfig.HTTP_SERVER_PORT);
|
||||
}
|
||||
|
||||
resultBuilder.setToken(token);
|
||||
|
||||
@@ -26,13 +26,13 @@ abstract public class GroupHandler<T> extends IMHandler<T> {
|
||||
}
|
||||
|
||||
for (int line : lines) {
|
||||
WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder().setContent(content);
|
||||
builder.setConversation(builder.getConversationBuilder().setType(ProtoConstants.ConversationType.ConversationType_Group).setTarget(targetId).setLine(line));
|
||||
long timestamp = System.currentTimeMillis();
|
||||
WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder().setContent(content).setServerTimestamp(timestamp);
|
||||
builder.setConversation(builder.getConversationBuilder().setType(ProtoConstants.ConversationType.ConversationType_Group).setTarget(targetId).setLine(line));
|
||||
builder.setFromUser(fromUser);
|
||||
long messageId = MessageShardingUtil.generateId();
|
||||
builder.setMessageId(messageId);
|
||||
saveAndPublish(fromUser, null, builder.build(), timestamp);
|
||||
saveAndPublish(fromUser, null, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
|
||||
long timestamp = System.currentTimeMillis();
|
||||
builder.setMessageId(messageId);
|
||||
builder.setServerTimestamp(timestamp);
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build(), timestamp);
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build());
|
||||
|
||||
WFCMessage.MessageContent.Builder contentBuilder = WFCMessage.MessageContent.newBuilder().setType(90).setContent("以上是打招呼信息");
|
||||
builder = WFCMessage.Message.newBuilder();
|
||||
@@ -44,7 +44,7 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
|
||||
|
||||
messageId = MessageShardingUtil.generateId();
|
||||
builder.setMessageId(messageId);
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build(), timestamp);
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build());
|
||||
|
||||
contentBuilder.setContent("你们已经成为好友了,现在可以开始聊天了");
|
||||
builder.setContent(contentBuilder);
|
||||
@@ -52,7 +52,7 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
|
||||
builder.setMessageId(messageId);
|
||||
timestamp = System.currentTimeMillis();
|
||||
builder.setServerTimestamp(timestamp);
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build(), System.currentTimeMillis());
|
||||
saveAndPublish(request.getTargetUid(), null, builder.build());
|
||||
|
||||
publisher.publishNotification(IMTopic.NotifyFriendTopic, request.getTargetUid(), heads[0]);
|
||||
publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, heads[1]);
|
||||
|
||||
@@ -240,10 +240,10 @@ abstract public class IMHandler<T> {
|
||||
|
||||
}
|
||||
|
||||
protected long saveAndPublish(String username, String clientID, WFCMessage.Message message, long timestamp) {
|
||||
protected long saveAndPublish(String username, String clientID, WFCMessage.Message message) {
|
||||
Set<String> notifyReceivers = new LinkedHashSet<>();
|
||||
|
||||
message = m_messagesStore.storeMessage(username, clientID, message, timestamp);
|
||||
message = m_messagesStore.storeMessage(username, clientID, message);
|
||||
int pullType = m_messagesStore.getNotifyReceivers(username, message, notifyReceivers);
|
||||
this.publisher.publish2Receivers(message, notifyReceivers, clientID, pullType);
|
||||
return message.getMessageId();
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package io.moquette.imhandler;
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
@Handler(value = IMTopic.LoadRemoteMessagesTopic)
|
||||
public class LoadRemoteMessagesHandler extends IMHandler<WFCMessage.LoadRemoteMessages> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, WFCMessage.LoadRemoteMessages request, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
WFCMessage.PullMessageResult result = m_messagesStore.loadRemoteMessages(fromUser, request.getConversation(), request.getBeforeUid(), request.getCount());
|
||||
byte[] data = result.toByteArray();
|
||||
LOG.info("User {} load message with count({}), payload size({})", fromUser, result.getMessageCount(), data.length);
|
||||
ackPayload.ensureWritable(data.length).writeBytes(data);
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
if (!ignoreMsg) {
|
||||
saveAndPublish(fromUser, clientID, message, timestamp);
|
||||
saveAndPublish(fromUser, clientID, message);
|
||||
}
|
||||
ackPayload = ackPayload.capacity(20);
|
||||
ackPayload.writeLong(messageId);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package io.moquette.persistence;
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import cn.wildfirechat.server.ThreadPoolExecutorWrapper;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
@@ -532,6 +533,74 @@ public class DatabaseStore {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<WFCMessage.Message> loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count) {
|
||||
List<WFCMessage.Message> messages = loadRemoteMessagesFromTable(user, conversation, beforeUid, count, MessageShardingUtil.getMessageTable(beforeUid));
|
||||
if (messages != null && messages.size() < count) {
|
||||
String nexTable = MessageShardingUtil.getPreviousMessageTable(beforeUid);
|
||||
List<WFCMessage.Message> nextMessages = loadRemoteMessagesFromTable(user, conversation, beforeUid, count-messages.size(), nexTable);
|
||||
if (nextMessages != null) {
|
||||
messages.addAll(nextMessages);
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
List<WFCMessage.Message> loadRemoteMessagesFromTable(String user, WFCMessage.Conversation conversation, long beforeUid, int count, String table) {
|
||||
String sql = "select `_from`, `_type`, `_target`, `_line`, `_data`, `_dt` from " + table +" where";
|
||||
if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
sql += " _type = ? and _line = ? and _mid > ? and ((_target = ? and _from = ?) or (_target = ? and _from = ?)";
|
||||
} else {
|
||||
sql += " _type = ? and _line = ? and _mid > ? and _target = ?";
|
||||
}
|
||||
|
||||
sql += " limit ?";
|
||||
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
List<WFCMessage.Message> out = new ArrayList<>();
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
statement = connection.prepareStatement(sql);
|
||||
int index = 1;
|
||||
statement.setInt(index++, conversation.getType());
|
||||
statement.setInt(index++, conversation.getLine());
|
||||
statement.setLong(index++, beforeUid);
|
||||
statement.setString(index++, conversation.getTarget());
|
||||
if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
statement.setString(index++, user);
|
||||
statement.setString(index++, user);
|
||||
statement.setString(index++, conversation.getTarget());
|
||||
}
|
||||
statement.setInt(index++, count);
|
||||
resultSet = statement.executeQuery();
|
||||
while (resultSet.next()) {
|
||||
WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder();
|
||||
index = 1;
|
||||
builder.setMessageId(resultSet.getLong(index++));
|
||||
builder.setFromUser(resultSet.getString(index++));
|
||||
WFCMessage.Conversation.Builder cb = WFCMessage.Conversation.newBuilder();
|
||||
cb.setType(resultSet.getInt(index++));
|
||||
cb.setTarget(resultSet.getString(index++));
|
||||
cb.setLine(resultSet.getInt(index++));
|
||||
builder.setConversation(cb.build());
|
||||
Blob blob = resultSet.getBlob(index++);
|
||||
|
||||
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(blob.getBinaryStream());
|
||||
builder.setContent(messageContent);
|
||||
builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());
|
||||
WFCMessage.Message message = builder.build();
|
||||
out.add(message);
|
||||
}
|
||||
} catch (SQLException | IOException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, statement, resultSet);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void persistUserMessage(final String userId, final long messageId, final long messageSeq) {
|
||||
mScheduler.execute(()->{
|
||||
Connection connection = null;
|
||||
@@ -663,12 +732,31 @@ public class DatabaseStore {
|
||||
", `_extra`" +
|
||||
", `_dt`" +
|
||||
", `_member_count`" +
|
||||
", `_member_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
", `_member_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)" +
|
||||
" ON DUPLICATE KEY UPDATE " +
|
||||
"`_name` = ?," +
|
||||
"`_portrait` = ?," +
|
||||
"`_owner` = ?," +
|
||||
"`_type` = ?," +
|
||||
"`_extra` = ?," +
|
||||
"`_dt` = ?," +
|
||||
"`_member_count` = ?," +
|
||||
"`_member_dt` = ?";
|
||||
|
||||
|
||||
statement = connection.prepareStatement(sql);
|
||||
|
||||
int index = 1;
|
||||
statement.setString(index++, groupInfo.getTargetId());
|
||||
statement.setString(index++, groupInfo.getName());
|
||||
statement.setString(index++, groupInfo.getPortrait());
|
||||
statement.setString(index++, groupInfo.getOwner());
|
||||
statement.setInt(index++, groupInfo.getType());
|
||||
statement.setString(index++, groupInfo.getExtra());
|
||||
statement.setLong(index++, groupInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());
|
||||
statement.setInt(index++, groupInfo.getMemberCount());
|
||||
statement.setLong(index++, groupInfo.getMemberUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());
|
||||
|
||||
statement.setString(index++, groupInfo.getName());
|
||||
statement.setString(index++, groupInfo.getPortrait());
|
||||
statement.setString(index++, groupInfo.getOwner());
|
||||
|
||||
@@ -10,12 +10,13 @@ package io.moquette.persistence;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.hazelcast.core.MapLoader;
|
||||
import com.hazelcast.core.MapStore;
|
||||
import io.moquette.server.Server;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public class GroupLoader implements MapLoader<String, WFCMessage.GroupInfo> {
|
||||
public class GroupLoader implements MapStore<String, WFCMessage.GroupInfo> {
|
||||
private DatabaseStore getDatabaseStore() {
|
||||
return Server.getServer().getStore().messagesStore().getDatabaseStore();
|
||||
}
|
||||
@@ -51,18 +52,31 @@ public class GroupLoader implements MapLoader<String, WFCMessage.GroupInfo> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all of the keys from the store. The returned {@link Iterable} may return the keys lazily
|
||||
* by loading them in batches. The {@link Iterator} of this {@link Iterable} may implement the
|
||||
* {@link Closeable} interface in which case it will be closed once iteration is over.
|
||||
* This is intended for releasing resources such as closing a JDBC result set.
|
||||
* <p>
|
||||
* The returned Iterable should not contain any <code>null</code> keys.
|
||||
*
|
||||
* @return all the keys. Keys inside the Iterable cannot be null.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Iterable<String> loadAllKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(String key, WFCMessage.GroupInfo value) {
|
||||
getDatabaseStore().persistGroupInfo(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeAll(Map<String, WFCMessage.GroupInfo> map) {
|
||||
for (WFCMessage.GroupInfo value : map.values()) {
|
||||
getDatabaseStore().persistGroupInfo(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
getDatabaseStore().removeGroupInfoFromDB(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(Collection<String> keys) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,12 +150,11 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message, long timestamp) {
|
||||
public WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message) {
|
||||
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
|
||||
IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);
|
||||
|
||||
|
||||
|
||||
MessageBundle messageBundle = new MessageBundle(message.getMessageId(), fromUser, fromClientId, message);
|
||||
if (message.getContent().getPersistFlag() == Transparent) {
|
||||
mIMap.put(message.getMessageId(), messageBundle, 10, TimeUnit.SECONDS);
|
||||
@@ -181,6 +180,8 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(message.getToUser())) {
|
||||
notifyReceivers.add(message.getToUser());
|
||||
} else if(!message.getToList().isEmpty()) {
|
||||
notifyReceivers.addAll(message.getToList());
|
||||
} else {
|
||||
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);
|
||||
Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());
|
||||
@@ -345,6 +346,17 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WFCMessage.PullMessageResult loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count) {
|
||||
WFCMessage.PullMessageResult.Builder builder = WFCMessage.PullMessageResult.newBuilder();
|
||||
List<WFCMessage.Message> messages = databaseStore.loadRemoteMessages(user, conversation, beforeUid, count);
|
||||
builder.setCurrent(0).setHead(0);
|
||||
if(messages != null) {
|
||||
builder.addAllMessage(messages);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<UserClientEntry> getChatroomMembers(String chatroomId) {
|
||||
MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);
|
||||
@@ -579,7 +591,6 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
.build();
|
||||
|
||||
mIMap.put(groupId, groupInfo);
|
||||
databaseStore.persistGroupInfo(groupInfo);
|
||||
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);
|
||||
|
||||
for (WFCMessage.GroupMember member : memberList) {
|
||||
@@ -756,7 +767,6 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
groupMembers.remove(groupId);
|
||||
mIMap.remove(groupId);
|
||||
|
||||
databaseStore.removeGroupInfoFromDB(groupId);
|
||||
databaseStore.removeGroupMemberFromDB(groupId);
|
||||
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
@@ -1480,9 +1490,10 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
}
|
||||
}
|
||||
|
||||
if (existRequest != null) {
|
||||
if (existRequest != null && existRequest.getStatus() != ProtoConstants.FriendRequestStatus.RequestStatus_Accepted) {
|
||||
if (System.currentTimeMillis() - existRequest.getUpdateDt() > 7 * 24 * 60 * 60 * 1000) {
|
||||
if (existRequest.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Rejected) {
|
||||
if (existRequest.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Rejected
|
||||
&& System.currentTimeMillis() - existRequest.getUpdateDt() < 30 * 24 * 60 * 60 * 1000) {
|
||||
return ErrorCode.ERROR_CODE_FRIEND_REQUEST_BLOCKED;
|
||||
}
|
||||
requestMap.remove(userId, existRequest);
|
||||
@@ -1761,6 +1772,7 @@ public class MemoryMessagesStore implements IMessagesStore {
|
||||
userSettingMap.put(userId, settingEntry);
|
||||
userGlobalSlientMap.remove(userId);
|
||||
userConvSlientMap.remove(userId);
|
||||
userPushHiddenDetail.remove(userId);
|
||||
return updateDt;
|
||||
}
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ public class Server {
|
||||
|
||||
MediaServerConfig.SERVER_IP = getServerIp(config);
|
||||
|
||||
MediaServerConfig.HTTP_SERVER_PORT = config.getProperty(BrokerConstants.HTTP_SERVER_PORT);
|
||||
MediaServerConfig.HTTP_SERVER_PORT = Integer.parseInt(config.getProperty(BrokerConstants.HTTP_SERVER_PORT));
|
||||
|
||||
MediaServerConfig.FILE_STROAGE_ROOT = config.getProperty(BrokerConstants.FILE_STORAGE_ROOT, MediaServerConfig.FILE_STROAGE_ROOT);
|
||||
File file = new File(MediaServerConfig.FILE_STROAGE_ROOT);
|
||||
|
||||
@@ -21,7 +21,7 @@ public class MediaServerConfig {
|
||||
public static String QINIU_BUCKET_FAVORITE_DOMAIN;
|
||||
|
||||
public static String SERVER_IP = "localhost";
|
||||
public static String HTTP_SERVER_PORT = "8090";
|
||||
public static int HTTP_SERVER_PORT = 8080;
|
||||
public static String FILE_STROAGE_ROOT = "fs";
|
||||
public static boolean USER_QINIU = false;
|
||||
|
||||
|
||||
@@ -97,9 +97,10 @@ public interface IMessagesStore {
|
||||
}
|
||||
|
||||
DatabaseStore getDatabaseStore();
|
||||
WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message, long timestamp);
|
||||
WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message);
|
||||
int getNotifyReceivers(String fromUser, WFCMessage.Message message, Set<String> notifyReceivers);
|
||||
WFCMessage.PullMessageResult fetchMessage(String user, String exceptClientId, long fromMessageId, int pullType);
|
||||
WFCMessage.PullMessageResult loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count);
|
||||
long insertUserMessages(String sender, int conversationType, String target, int line, int messageContentType, String userId, long messageId);
|
||||
WFCMessage.GroupInfo createGroup(String operator, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList);
|
||||
ErrorCode addGroupMembers(String operator, String groupId, List<WFCMessage.GroupMember> memberList);
|
||||
|
||||
@@ -227,21 +227,25 @@ public class MessagesPublisher {
|
||||
isSlient = true;
|
||||
} else {
|
||||
isSlient = false;
|
||||
WFCMessage.Conversation conversation;
|
||||
if (conversationType == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(sender).build();
|
||||
} else {
|
||||
conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(target).build();
|
||||
}
|
||||
|
||||
if (m_messagesStore.getUserConversationSlient(user, conversation)) {
|
||||
LOG.info("The conversation {}-{}-{} is slient", conversation.getType(), conversation.getTarget(), conversation.getLine());
|
||||
isSlient = true;
|
||||
}
|
||||
if (!user.equals(sender)) {
|
||||
WFCMessage.Conversation conversation;
|
||||
if (conversationType == ProtoConstants.ConversationType.ConversationType_Private) {
|
||||
conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(sender).build();
|
||||
} else {
|
||||
conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(target).build();
|
||||
}
|
||||
|
||||
if (m_messagesStore.getUserGlobalSlient(user)) {
|
||||
LOG.info("The user {} is global sliented", user);
|
||||
isSlient = true;
|
||||
|
||||
if (m_messagesStore.getUserConversationSlient(user, conversation)) {
|
||||
LOG.info("The conversation {}-{}-{} is slient", conversation.getType(), conversation.getTarget(), conversation.getLine());
|
||||
isSlient = true;
|
||||
}
|
||||
|
||||
if (m_messagesStore.getUserGlobalSlient(user)) {
|
||||
LOG.info("The user {} is global sliented", user);
|
||||
isSlient = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(pushContent) || messageContentType == 400 || messageContentType == 402) {
|
||||
|
||||
@@ -67,4 +67,6 @@ public interface IMTopic {
|
||||
String ChannelPullTopic = "CHP";
|
||||
|
||||
String GetTokenTopic = "GETTOKEN";
|
||||
|
||||
String LoadRemoteMessagesTopic = "LRM";
|
||||
}
|
||||
|
||||
@@ -60,4 +60,22 @@ public class MessageShardingUtil {
|
||||
year %= 3;
|
||||
return "t_messages_" + (year * 12 + month);
|
||||
}
|
||||
|
||||
public static String getPreviousMessageTable(long mid) {
|
||||
if (DBUtil.IsEmbedDB) {
|
||||
return null;
|
||||
}
|
||||
|
||||
mid >>= (nodeIdWidth + rotateIdWidth);
|
||||
Date date = new Date(mid + T201801010000);
|
||||
int month = date.getMonth();
|
||||
int year = date.getYear();
|
||||
year %= 3;
|
||||
month = month + 1;
|
||||
if (month == 12) {
|
||||
month = 0;
|
||||
year = (year + 3 -1)%3;
|
||||
}
|
||||
return "t_messages_" + (year * 12 + month);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<!--MySQL数据库用户名-->
|
||||
<property name="user">root</property>
|
||||
<!--MySQL数据库密码-->
|
||||
<property name="password">lt123456</property>
|
||||
<property name="password">123456</property>
|
||||
<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
|
||||
<property name="initialPoolSize">10</property>
|
||||
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.11</version>
|
||||
<version>0.12</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
<!--<relativePath>../pom.xml</relativePath>-->
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.11</version>
|
||||
<version>0.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>distribution</artifactId>
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>src/main/scripts/machinecode.sh</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>src/main/resources/log4j.properties</source>
|
||||
<outputDirectory>config/</outputDirectory>
|
||||
@@ -76,10 +71,6 @@
|
||||
<outputDirectory>config/</outputDirectory>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>src/main/resources/register.py</source>
|
||||
<outputDirectory>tools/</outputDirectory>
|
||||
</file>
|
||||
|
||||
<file>
|
||||
<source>../broker/h2/create_table.sql</source>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# -- coding: utf-8 --
|
||||
|
||||
import time
|
||||
import hashlib
|
||||
import random
|
||||
import requests
|
||||
|
||||
|
||||
|
||||
# 签名方法说明
|
||||
# 注册用户需要签名,需要在header中加入nonce,timestamp, sign。
|
||||
# 值如下所示。
|
||||
# 服务器会检查时间戳,2个小时内有效。注意测试使用时避免过期
|
||||
# 请注意需要与wildfirechat.conf中的SECRET_KEY保持一致
|
||||
|
||||
#需要用到requests库,首先要安装pip
|
||||
#sudo easy_install pip
|
||||
|
||||
#然后在安装requests module
|
||||
#sudo pip install requests
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print 'Usage: python gettoken.py userid'
|
||||
sys.exit()
|
||||
|
||||
user = sys.argv[1]
|
||||
|
||||
SECRET_KEY = '123456'
|
||||
URL = 'http://localhost:18080/admin/user/token'
|
||||
|
||||
ts = (int(round(time.time() * 1000)))
|
||||
random.seed(time.time())
|
||||
nonce = (int(round(random.random() * 100000)))
|
||||
orignSign = bytes(nonce) + '|' + SECRET_KEY + '|' + bytes(ts)
|
||||
sign = hashlib.sha1(orignSign).hexdigest()
|
||||
|
||||
headers = {'nonce': bytes(nonce), 'timestamp':bytes(ts), 'sign':sign, 'Content-Type':'application/json'}
|
||||
|
||||
payload = {'userId':user}
|
||||
|
||||
print 'headers:'
|
||||
print headers
|
||||
print
|
||||
print 'payload:'
|
||||
print payload
|
||||
print
|
||||
|
||||
r = requests.post(URL, headers = headers, json = payload)
|
||||
print 'response:'
|
||||
print(r.status_code)
|
||||
print r.content
|
||||
@@ -1,53 +0,0 @@
|
||||
# -- coding: utf-8 --
|
||||
|
||||
import time
|
||||
import hashlib
|
||||
import random
|
||||
import requests
|
||||
|
||||
|
||||
|
||||
# 签名方法说明
|
||||
# 注册用户需要签名,需要在header中加入nonce,timestamp, sign。
|
||||
# 值如下所示。
|
||||
# 服务器会检查时间戳,2个小时内有效。注意测试使用时避免过期
|
||||
# 请注意需要与wildfirechat.conf中的SECRET_KEY保持一致
|
||||
|
||||
#需要用到requests库,首先要安装pip
|
||||
#sudo easy_install pip
|
||||
|
||||
#然后在安装requests module
|
||||
#sudo pip install requests
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print 'Usage: python getuserinfo.py userid'
|
||||
sys.exit()
|
||||
|
||||
user = sys.argv[1]
|
||||
|
||||
SECRET_KEY = '123456'
|
||||
URL = 'http://localhost/admin/user/info'
|
||||
|
||||
ts = (int(round(time.time() * 1000)))
|
||||
random.seed(time.time())
|
||||
nonce = (int(round(random.random() * 100000)))
|
||||
orignSign = bytes(nonce) + '|' + SECRET_KEY + '|' + bytes(ts)
|
||||
sign = hashlib.sha1(orignSign).hexdigest()
|
||||
|
||||
headers = {'nonce': bytes(nonce), 'timestamp':bytes(ts), 'sign':sign, 'Content-Type':'application/json'}
|
||||
|
||||
payload = {'userId':user}
|
||||
|
||||
print 'headers:'
|
||||
print headers
|
||||
print
|
||||
print 'payload:'
|
||||
print payload
|
||||
print
|
||||
|
||||
r = requests.post(URL, headers = headers, json = payload)
|
||||
print 'response:'
|
||||
print(r.status_code)
|
||||
print r.content
|
||||
@@ -1,15 +0,0 @@
|
||||
#Generated by Git-Commit-Id-Plugin
|
||||
#Wed Apr 03 15:25:29 CST 2019
|
||||
git.commit.id.abbrev=cc82c5b
|
||||
git.commit.user.email=[email protected]
|
||||
git.commit.message.full=update version to 0.1.1\n
|
||||
git.commit.id=cc82c5b420061994bc0621e807bb6c961370aef2
|
||||
git.commit.message.short=update version to 0.1.1
|
||||
git.commit.user.name=heavyrain2012
|
||||
git.build.user.name=heavyrain2012
|
||||
git.commit.id.describe=0.1.1-dirty
|
||||
git.build.user.email=[email protected]
|
||||
git.branch=wildfirechat
|
||||
git.commit.time=20190403134707
|
||||
git.build.time=20190403152529
|
||||
git.remote.origin.url=https\://github.com/wildfirechat/server.git
|
||||
@@ -1,55 +0,0 @@
|
||||
# -- coding: utf-8 --
|
||||
|
||||
import time
|
||||
import hashlib
|
||||
import random
|
||||
import requests
|
||||
|
||||
|
||||
|
||||
# 签名方法说明
|
||||
# 注册用户需要签名,需要在header中加入nonce,timestamp, sign。
|
||||
# 值如下所示。
|
||||
# 服务器会检查时间戳,2个小时内有效。注意测试使用时避免过期
|
||||
# 请注意需要与wildfirechat.conf中的SECRET_KEY保持一致
|
||||
|
||||
#需要用到requests库,首先要安装pip
|
||||
#sudo easy_install pip
|
||||
|
||||
#然后在安装requests module
|
||||
#sudo pip install requests
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 4:
|
||||
print 'Usage: python register.py username password displayname'
|
||||
sys.exit()
|
||||
|
||||
user = sys.argv[1]
|
||||
pwd = sys.argv[2]
|
||||
displayname = sys.argv[3]
|
||||
|
||||
SECRET_KEY = '123456'
|
||||
URL = 'http://localhost:18080/admin/user/create'
|
||||
|
||||
ts = (int(round(time.time() * 1000)))
|
||||
random.seed(time.time())
|
||||
nonce = (int(round(random.random() * 100000)))
|
||||
orignSign = bytes(nonce) + '|' + SECRET_KEY + '|' + bytes(ts)
|
||||
sign = hashlib.sha1(orignSign).hexdigest()
|
||||
|
||||
headers = {'nonce': bytes(nonce), 'timestamp':bytes(ts), 'sign':sign, 'Content-Type':'application/json'}
|
||||
|
||||
payload = {'name':user, 'password':pwd, 'displayName':displayname}
|
||||
|
||||
print 'headers:'
|
||||
print headers
|
||||
print
|
||||
print 'payload:'
|
||||
print payload
|
||||
print
|
||||
|
||||
r = requests.post(URL, headers = headers, json = payload)
|
||||
print 'response:'
|
||||
print(r.status_code)
|
||||
print r.content
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# resolve links - $0 may be a softlink
|
||||
PRG="$0"
|
||||
|
||||
while [ -h "$PRG" ]; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`/"$link"
|
||||
fi
|
||||
done
|
||||
|
||||
PRGDIR=`dirname "$PRG"`
|
||||
cd ..
|
||||
WILDFIRECHAT_HOME=`pwd`
|
||||
|
||||
|
||||
export WILDFIRECHAT_HOME
|
||||
|
||||
if [ -f "${JAVA_HOME}/bin/java" ]; then
|
||||
JAVA=${JAVA_HOME}/bin/java
|
||||
else
|
||||
JAVA=java
|
||||
fi
|
||||
export JAVA
|
||||
|
||||
|
||||
WILDFIRECHAT_PATH=$WILDFIRECHAT_HOME/
|
||||
|
||||
|
||||
$JAVA -cp "$WILDFIRECHAT_HOME/lib/*" cn.wildfirechat.server.MechineCode $1 $2
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
# MySQL 调优
|
||||
|
||||
### 1,所有的表都必须有primary key.
|
||||
因为需要用primary key来表示每一行,最好用自增的整形
|
||||
|
||||
### 2, 使用in代替or
|
||||
SELECT * FROM t WHERE LOC_IN IN (10,20,30);
|
||||
|
||||
### 3, 不使用子查询
|
||||
使用join
|
||||
|
||||
### 4. 足够大的 innodb_buffer_pool_size
|
||||
|
||||
最大内存数在总的innoDB内存数据160%就行,比如数据大小5G,buffer size设置为8G就行,有个命令来获取应当设置的大小
|
||||
```
|
||||
SELECT CEILING(Total_InnoDB_Bytes*1.6/POWER(1024,3)) RIBPS FROM
|
||||
(SELECT SUM(data_length+index_length) Total_InnoDB_Bytes
|
||||
FROM information_schema.tables WHERE engine='InnoDB') A;
|
||||
```
|
||||
|
||||
> 需要注意这个系统刚开始允许,无法计算出实际使用量。一般需要系统实际允许几个月,或者设置成机器物理内存的一半。
|
||||
|
||||
---
|
||||
### 5. 配置 innodb_log_file_size
|
||||
使用足够大的写入缓存 innodb_log_file_size
|
||||
|
||||
可是须要注意假设用 1G 的 innodb_log_file_size 。假如server当机。须要 10 分钟来恢复。
|
||||
|
||||
推荐 innodb_log_file_size 设置为 0.25 * innodb_buffer_pool_size
|
||||
|
||||
---
|
||||
### 6. 配置 innodb_flush_log_at_trx_commit
|
||||
|
||||
innodb_flush_log_at_trx_commit = 1 则每次改动写入磁盘
|
||||
|
||||
innodb_flush_log_at_trx_commit = 0/2 每秒写入磁盘
|
||||
|
||||
假设你的应用不涉及非常高的安全性 (金融系统),或者基础架构足够安全,或者 事务都非常小,都能够用 0 或者 2 来减少磁盘操作。
|
||||
|
||||
---
|
||||
### 7. 避免双写入缓冲
|
||||
|
||||
innodb_flush_method=O_DIRECT
|
||||
|
||||
---
|
||||
|
||||
### 8. innodb_write_io_threads
|
||||
|
||||
写IO线程,默认4,最大可设置成64.每个线程可以处理256个pending io request.需要根据您的cpu数和读写比例调整,在当前项目中可设置为物理核数的2倍
|
||||
|
||||
---
|
||||
|
||||
### 9. innodb_read_io_threads
|
||||
|
||||
读IO线程,默认4,最大可设置成64.每个线程可以处理256个pending io request.需要根据您的cpu数和读写比例调整,在当前项目中保持4就可以了
|
||||
|
||||
---
|
||||
|
||||
### 10. innodb_thread_concurrency
|
||||
|
||||
线程并发数,0是不限制。如果设置最大是1000,可以设置成cpu核数的8倍
|
||||
|
||||
---
|
||||
### 11. 关闭swap
|
||||
|
||||
对于单独的数据库服务器,在内存足够大的情况下,可以关闭swap
|
||||
```
|
||||
sync # 先执行下同步
|
||||
swapoff -a # 关闭swap分区
|
||||
swapon -a # 开启swap分区
|
||||
swapoff -a && swapon -a # 刷新swap空间,即将SWAP里的数据转储回内存,并清空SWAP里的数据。刷新原理就是把swap关闭后再重启。
|
||||
```
|
||||
|
||||
---
|
||||
### 12. DB连接数
|
||||
show global variables like "max_connections"; 显示最大连接数
|
||||
SET GLOBAL max_connections = 2000; 设置最大连接数
|
||||
|
||||
### 13. c3p0连接池
|
||||
修改最大连接数,注意需要确保DB能撑得起集群的最大连接数
|
||||
|
||||
### 14. 示例
|
||||
mysqld.cnf配置
|
||||
```
|
||||
[mysqld]
|
||||
# Uncomment the following if you are using InnoDB tables
|
||||
#innodb_data_home_dir = /usr/local/mysql/data
|
||||
#innodb_data_file_path = ibdata1:10M:autoextend
|
||||
#innodb_log_group_home_dir = /usr/local/mysql/data
|
||||
# You can set .._buffer_pool_size up to 50 - 80 %
|
||||
# of RAM but beware of setting memory usage too high
|
||||
innodb_buffer_pool_size = 2G
|
||||
# Set .._log_file_size to 25 % of buffer pool size
|
||||
innodb_log_file_size = 512M
|
||||
innodb_log_buffer_size = 64M
|
||||
innodb_flush_log_at_trx_commit = 2
|
||||
innodb_flush_method=O_DIRECT
|
||||
#innodb_lock_wait_timeout = 50
|
||||
```
|
||||
|
||||
> 以上信息来源于
|
||||
|
||||
> https://www.cnblogs.com/jxldjsn/p/6010720.html
|
||||
|
||||
> https://www.percona.com/blog/2016/10/12/mysql-5-7-performance-tuning-immediately-after-installation/
|
||||
|
||||
> https://www.cnblogs.com/claireyuancy/p/7258314.html
|
||||
|
||||
> http://www.codingpedia.org/ama/optimizing-mysql-server-settings/
|
||||
@@ -12,7 +12,7 @@
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<version>0.11</version>
|
||||
<version>0.12</version>
|
||||
<name>Wildfire Chat</name>
|
||||
<description>Wildfire Chat Server</description>
|
||||
<inceptionYear>2018</inceptionYear>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
protoc -odata.pb wfcmessage.proto
|
||||
g++ -o convert convert.cpp
|
||||
./convert
|
||||
mv pbdata.h ../../../ios-workspace/mars/mars/proto/src/Proto/
|
||||
rm convert data.pb
|
||||
protoc --java_out=./ wfcmessage.proto
|
||||
mv ./cn/wildfirechat/proto/WFCMessage.java ../../client/src/main/java/cn/wildfirechat/proto/
|
||||
@@ -1,36 +0,0 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
int main () {
|
||||
ofstream out("pbdata.h");
|
||||
ifstream in("data.pb", ios::in | ios::binary);
|
||||
if (out.is_open() && in.is_open())
|
||||
{
|
||||
|
||||
out << "static unsigned char pbdata[] = { ";
|
||||
|
||||
int flag = 0;
|
||||
int preCh;
|
||||
while (!in.eof()) {
|
||||
unsigned char ch = 0;
|
||||
in.read((char *)&ch, 1);
|
||||
|
||||
if (flag == 1) {
|
||||
out << preCh;
|
||||
} else if (flag > 1) {
|
||||
out << ",";
|
||||
out << preCh;
|
||||
}
|
||||
preCh = ch;
|
||||
|
||||
flag += 1;
|
||||
}
|
||||
|
||||
out << "};\n";
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
syntax = "proto2";
|
||||
//package mars.stn;
|
||||
|
||||
|
||||
option java_package = "cn.wildfirechat.proto";
|
||||
option java_outer_classname = "WFCMessage";
|
||||
//option optimize_for = LITE_RUNTIME;
|
||||
|
||||
|
||||
message AddFriendRequest {
|
||||
required string target_uid = 1;
|
||||
required string reason = 2;
|
||||
}
|
||||
|
||||
message Conversation {
|
||||
required int32 type = 1;
|
||||
required string target = 2;
|
||||
required int32 line = 3;
|
||||
}
|
||||
|
||||
message GroupInfo {
|
||||
optional string target_id = 1;
|
||||
required string name = 2;
|
||||
optional string portrait = 3;
|
||||
optional string owner = 4;
|
||||
required int32 type = 5;
|
||||
optional int32 member_count = 6;
|
||||
optional string extra = 7;
|
||||
optional int64 update_dt = 8;
|
||||
optional int64 member_update_dt = 9;
|
||||
}
|
||||
|
||||
|
||||
message GroupMember {
|
||||
required string member_id = 1;
|
||||
optional string alias = 2;
|
||||
required int32 type = 3;
|
||||
optional int64 update_dt = 4;
|
||||
}
|
||||
|
||||
message Group {
|
||||
required GroupInfo group_info = 1;
|
||||
repeated GroupMember members = 2;
|
||||
}
|
||||
|
||||
message ChannelInfo {
|
||||
optional string target_id = 1;
|
||||
required string name = 2;
|
||||
optional string portrait = 3;
|
||||
optional string owner = 4;
|
||||
//0, public; 1, private; 2 closed;
|
||||
optional int32 status = 5;
|
||||
optional string desc = 6;
|
||||
optional string extra = 7;
|
||||
optional int64 update_dt = 8;
|
||||
optional string secret = 9;
|
||||
optional string callback = 10;
|
||||
optional int32 automatic = 11;
|
||||
}
|
||||
|
||||
message ModifyChannelInfo {
|
||||
required string channel_id = 1;
|
||||
required int32 type = 2;
|
||||
required string value = 3;
|
||||
}
|
||||
|
||||
message TransferChannel {
|
||||
required string channel_id = 1;
|
||||
required string new_owner = 2;
|
||||
}
|
||||
|
||||
message PullChannelInfo {
|
||||
required string channel_id = 1;
|
||||
required int64 head = 2;
|
||||
}
|
||||
|
||||
message PullChannelListener {
|
||||
required string channel_id = 1;
|
||||
required int32 offset = 2;
|
||||
required int32 count = 3;
|
||||
}
|
||||
|
||||
message PullChannelListenerResult {
|
||||
required int32 total_count = 1;
|
||||
required int32 offset = 2;
|
||||
repeated string listener = 3;
|
||||
}
|
||||
|
||||
message ListenChannel {
|
||||
required string channel_id = 1;
|
||||
required int32 listen = 2;
|
||||
}
|
||||
|
||||
message SearchChannelResult {
|
||||
repeated ChannelInfo channel = 1;
|
||||
required string keyword = 2;
|
||||
}
|
||||
|
||||
message MessageContent {
|
||||
required int32 type = 1;
|
||||
optional string searchable_content = 2;
|
||||
optional string push_content = 3;
|
||||
optional string content = 4;
|
||||
optional bytes data = 5;
|
||||
optional int32 mediaType = 6;
|
||||
optional string remoteMediaUrl = 7;
|
||||
optional int32 persist_flag= 8;
|
||||
optional int32 expire_duration= 9;
|
||||
optional int32 mentioned_type= 10;
|
||||
repeated string mentioned_target= 11;
|
||||
}
|
||||
|
||||
message AddGroupMemberRequest {
|
||||
required string group_id = 1;
|
||||
repeated GroupMember added_member = 2;
|
||||
repeated int32 to_line = 3;
|
||||
optional MessageContent notify_content = 4;
|
||||
}
|
||||
|
||||
message CreateGroupRequest {
|
||||
required Group group = 1;
|
||||
repeated int32 to_line = 2;
|
||||
optional MessageContent notify_content = 3;
|
||||
}
|
||||
|
||||
message DismissGroupRequest {
|
||||
required string group_id = 1;
|
||||
repeated int32 to_line = 2;
|
||||
optional MessageContent notify_content = 3;
|
||||
}
|
||||
|
||||
message FriendRequest {
|
||||
optional string from_uid = 1;
|
||||
required string to_uid = 2;
|
||||
required string reason = 3;
|
||||
optional int32 status = 4;
|
||||
optional int64 update_dt = 5;
|
||||
optional bool from_read_status = 6;
|
||||
optional bool to_read_status = 7;
|
||||
}
|
||||
|
||||
message GeneralResult {
|
||||
required int32 error_code = 1;
|
||||
}
|
||||
|
||||
message GetUploadTokenResult {
|
||||
required string domain = 1;
|
||||
required string token = 2;
|
||||
required string server = 3;
|
||||
}
|
||||
|
||||
message HandleFriendRequest {
|
||||
required string target_uid = 1;
|
||||
required int32 status = 2;
|
||||
}
|
||||
|
||||
message IDBuf {
|
||||
required string id = 1;
|
||||
}
|
||||
|
||||
message IDListBuf {
|
||||
repeated string id = 1;
|
||||
}
|
||||
|
||||
message Message {
|
||||
required Conversation conversation = 1;
|
||||
required string from_user = 2;
|
||||
required MessageContent content = 3;
|
||||
optional int64 message_id = 4;
|
||||
optional int64 server_timestamp = 5;
|
||||
optional string to_user = 6;
|
||||
}
|
||||
|
||||
message User {
|
||||
required string uid = 1;
|
||||
optional string name = 2;
|
||||
optional string display_name = 3;
|
||||
optional string portrait = 4;
|
||||
optional string mobile = 5;
|
||||
optional string email = 6;
|
||||
optional string address = 7;
|
||||
optional string company = 8;
|
||||
optional string extra = 9;
|
||||
optional int64 update_dt = 10;
|
||||
optional int32 gender = 11;
|
||||
optional string social = 12;
|
||||
//0 normal user; 1 robot
|
||||
optional int32 type = 13;
|
||||
}
|
||||
|
||||
message Robot {
|
||||
required string uid = 1;
|
||||
//0 normal; 1 deleted;
|
||||
required int32 state = 2;
|
||||
optional string owner = 3;
|
||||
optional string secret = 4;
|
||||
optional string callback = 5;
|
||||
optional string extra = 6;
|
||||
}
|
||||
|
||||
message GetRobotsResult {
|
||||
repeated Robot entry = 1;
|
||||
}
|
||||
|
||||
message Thing {
|
||||
required string uid = 1;
|
||||
//0 normal; 1 deleted;
|
||||
required int32 state = 2;
|
||||
required string token = 3;
|
||||
optional string owner = 4;
|
||||
optional string extra = 5;
|
||||
}
|
||||
|
||||
message GetThingsResult {
|
||||
repeated Thing entry = 1;
|
||||
}
|
||||
|
||||
message UploadDeviceTokenRequest {
|
||||
required int32 platform = 1;
|
||||
required string app_name = 2;
|
||||
required string device_token = 3;
|
||||
required int32 push_type = 4;
|
||||
}
|
||||
|
||||
message ModifyGroupInfoRequest {
|
||||
required string group_id = 1;
|
||||
required int32 type = 2;
|
||||
required string value = 3;
|
||||
repeated int32 to_line = 4;
|
||||
optional MessageContent notify_content = 5;
|
||||
}
|
||||
|
||||
message InfoEntry {
|
||||
required int32 type = 1;
|
||||
required string value = 2;
|
||||
}
|
||||
|
||||
message ModifyMyInfoRequest {
|
||||
repeated InfoEntry entry = 1;
|
||||
}
|
||||
|
||||
message NotifyMessage {
|
||||
required int32 type = 1;
|
||||
required int64 head = 2;
|
||||
optional string target = 3;
|
||||
}
|
||||
|
||||
message PullMessageRequest {
|
||||
required int64 id = 1;
|
||||
required int32 type = 2;
|
||||
optional int64 delay = 3;
|
||||
}
|
||||
|
||||
message PullMessageResult {
|
||||
repeated Message message = 1;
|
||||
required int64 current = 2;
|
||||
required int64 head = 3;
|
||||
}
|
||||
|
||||
message PullGroupInfoResult {
|
||||
repeated GroupInfo info = 1;
|
||||
}
|
||||
|
||||
message PullGroupMemberRequest {
|
||||
required string target = 1;
|
||||
required int64 head = 2;
|
||||
}
|
||||
|
||||
message PullGroupMemberResult {
|
||||
repeated GroupMember member = 1;
|
||||
}
|
||||
|
||||
message UserRequest {
|
||||
required string uid = 1;
|
||||
optional int64 update_dt = 2;
|
||||
}
|
||||
|
||||
message PullUserRequest {
|
||||
repeated UserRequest request = 1;
|
||||
}
|
||||
|
||||
message UserResult {
|
||||
required User user = 1;
|
||||
required int32 code = 2;
|
||||
}
|
||||
|
||||
|
||||
message PullUserResult {
|
||||
repeated UserResult result = 1;
|
||||
}
|
||||
|
||||
message QuitGroupRequest {
|
||||
required string group_id = 1;
|
||||
repeated int32 to_line = 2;
|
||||
optional MessageContent notify_content = 3;
|
||||
}
|
||||
|
||||
message RemoveGroupMemberRequest {
|
||||
required string group_id = 1;
|
||||
repeated string removed_member = 2;
|
||||
repeated int32 to_line = 3;
|
||||
optional MessageContent notify_content = 4;
|
||||
}
|
||||
|
||||
message TransferGroupRequest {
|
||||
required string group_id = 1;
|
||||
required string new_owner = 2;
|
||||
repeated int32 to_line = 3;
|
||||
optional MessageContent notify_content = 4;
|
||||
}
|
||||
|
||||
message ModifyGroupMemberAlias {
|
||||
required string group_id = 1;
|
||||
required string alias = 2;
|
||||
repeated int32 to_line = 3;
|
||||
optional MessageContent notify_content = 4;
|
||||
}
|
||||
|
||||
message UserSettingEntry {
|
||||
required int32 scope = 1;
|
||||
required string key = 2;
|
||||
required string value = 3;
|
||||
required int64 update_dt = 4;
|
||||
}
|
||||
|
||||
message ModifyUserSettingReq {
|
||||
required int32 scope = 1;
|
||||
required string key = 2;
|
||||
required string value = 3;
|
||||
}
|
||||
|
||||
message Version {
|
||||
required int64 version = 1;
|
||||
}
|
||||
|
||||
message GetUserSettingResult {
|
||||
repeated UserSettingEntry entry = 1;
|
||||
}
|
||||
|
||||
message Friend {
|
||||
required string uid = 1;
|
||||
required int32 state = 2;
|
||||
required int64 update_dt = 3;
|
||||
}
|
||||
|
||||
message GetFriendsResult {
|
||||
repeated Friend entry = 1;
|
||||
}
|
||||
|
||||
message GetFriendRequestResult {
|
||||
repeated FriendRequest entry = 1;
|
||||
}
|
||||
|
||||
message ConnectAckPayload {
|
||||
optional int64 msg_head = 1;
|
||||
optional int64 friend_head = 2;
|
||||
optional int64 friend_rq_head = 3;
|
||||
optional int64 setting_head = 4;
|
||||
optional string node_addr = 5;
|
||||
optional int32 node_port = 6;
|
||||
optional int64 server_time = 7;
|
||||
}
|
||||
|
||||
message IMHttpWrapper {
|
||||
required string token = 1;
|
||||
required string client_id = 2;
|
||||
required string request = 3;
|
||||
optional bytes data = 4;
|
||||
}
|
||||
|
||||
message SearchUserRequest {
|
||||
required string keyword = 1;
|
||||
optional int32 fuzzy = 2;
|
||||
optional int32 page = 3;
|
||||
}
|
||||
|
||||
message SearchUserResult {
|
||||
repeated User entry = 1;
|
||||
}
|
||||
|
||||
message GetChatroomInfoRequest {
|
||||
required string chatroom_id = 1;
|
||||
optional int64 update_dt = 2;
|
||||
}
|
||||
|
||||
message ChatroomInfo {
|
||||
required string title = 1;
|
||||
optional string desc = 2;
|
||||
optional string portrait = 3;
|
||||
optional int32 member_count = 4;
|
||||
optional int64 create_dt = 5;
|
||||
optional int64 update_dt = 6;
|
||||
optional string extra = 7;
|
||||
optional int32 state = 8;
|
||||
}
|
||||
|
||||
message GetChatroomMemberInfoRequest {
|
||||
required string chatroom_id = 1;
|
||||
optional int32 max_count = 2;
|
||||
}
|
||||
|
||||
message ChatroomMemberInfo {
|
||||
optional int32 member_count = 1;
|
||||
repeated string members = 2;
|
||||
}
|
||||
|
||||
message INT64Buf {
|
||||
required int64 id = 1;
|
||||
}
|
||||
|
||||
message NotifyRecallMessage {
|
||||
required int64 id = 1;
|
||||
required string from_user = 2;
|
||||
}
|
||||
|
||||
message BlackUserRequest {
|
||||
required string uid = 1;
|
||||
required int32 status = 2;
|
||||
}
|
||||
|
||||
message RouteRequest {
|
||||
optional string app = 1;
|
||||
optional int32 platform = 2;
|
||||
optional int32 push_type = 3;
|
||||
optional string device_name = 4;
|
||||
optional string device_version = 5;
|
||||
optional string phone_name = 6;
|
||||
optional string language = 7;
|
||||
optional string carrier_name = 8;
|
||||
optional string app_version = 9;
|
||||
optional string sdk_version = 10;
|
||||
}
|
||||
|
||||
message RouteResponse {
|
||||
required string host = 1;
|
||||
required int32 long_port = 2;
|
||||
required int32 short_port = 3;
|
||||
}
|
||||
|
||||
message GetTokenRequest {
|
||||
required string user_id = 1;
|
||||
required string client_id = 2;
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
dest=$1
|
||||
mvn clean install -Dmaven.test.skip=true
|
||||
if [ -n "$dest" ];then
|
||||
scp distribution/target/distribution-0.10-bundle-tar.tar.gz ${dest}:~/wildfirechat/
|
||||
ssh ${dest} 'cd ~/wildfirechat; bash deploy.sh'
|
||||
|
||||
sleep 20s
|
||||
curl im.liyufan.win:8080/api/version
|
||||
|
||||
echo ""
|
||||
echo "curl wildfirechat.cn/api/version"
|
||||
fi
|
||||
@@ -5,7 +5,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.11</version>
|
||||
<version>0.12</version>
|
||||
</parent>
|
||||
|
||||
<groupId>net.xmeter</groupId>
|
||||
|
||||
Reference in New Issue
Block a user