Compare commits

...
13 Commits
Author SHA1 Message Date
heavyrian2012 304192e303 version 0.87 2022-04-27 18:42:34 +08:00
heavyrian2012 9490226757 update 2022-04-26 20:12:52 +08:00
heavyrian2012 c44062855b 添加获取单条消息的接口 2022-04-26 20:05:35 +08:00
heavyrian2012 9d96fe927f 添加配置,当删除用户时是否保留用户昵称 2022-04-26 19:50:53 +08:00
heavyrian2012 ef21bd6db3 update readme 2022-04-05 15:26:33 +08:00
imndx dc0b718083 Update README.md 2022-04-01 09:12:05 +08:00
heavyrian2012 c0703332d6 在线状态 2022-03-24 09:49:18 +08:00
heavyrian2012 def048836f 在线状态 2022-03-24 08:38:33 +08:00
heavyrian2012 806cd440e3 修正在线状态问题 2022-03-23 21:45:27 +08:00
heavyrian2012 a3f2623d7e 处理disconnect的在线状态 2022-03-23 19:55:58 +08:00
heavyrian2012 4bc5fd6bb9 version 0.86 2022-03-20 20:34:23 +08:00
heavyrian2012 be2979c9a9 获取在线用户结果的变量改成公开的 2022-03-03 14:31:27 +08:00
heavyrian2012 b7a30e1d14 注释 2022-02-24 21:37:05 +08:00
20 changed files with 263 additions and 97 deletions
+82 -43
View File
@@ -1,54 +1,60 @@
## 野火IM解决方案
# 野火IM解决方案
野火IM是专业级的即时通讯和实时音视频整体解决方案,由北京野火无限网络科技有限公司维护和支持。
野火IM是专业级即时通讯和实时音视频整体解决方案,由北京野火无限网络科技有限公司维护和支持。
主要特性有:私有部署安全可靠,性能强大,功能齐全,全平台支持,开源率高,部署运维简单,二次开发友好,方便与第三方系统对接或者嵌入现有系统中。详细情况请参考[在线文档](https://docs.wildfirechat.cn)。
## 功能特性
* 超低硬件配置要求,IM服务最低128M内存即可运行。
* 协议先进,采用MQTT+Protobuf组合,流量和性能极致优化。
* 性能强大,专业版IM服务支持百万在线和集群部署。
* 部署运维简单,依赖服务少,稍加配置一键启动。
* 安全加密。网络连接AES加密。客户端数据库SqlCipher加密。安全无小事。
* 全平台客户端,四端同时在线(移动端,pc端,web端和小程序端),数据和状态多端完美同步。
* 支持国产化。支持国产化操作系统、国产化芯片和国产操作系统。支持国密加密。
* 客户端使用微信[mars](https://github.com/tencent/mars)连接库,野火IM可能是最适应中国网络国情的即时通讯服务。
* 支持加速点加速,即可用于全球应用,也可用于政企内外双网复杂的网络环境。
* 支持阅读回执和在线状态功能,适用于办公环境。
* 音视频多种解决方案,丰俭由人,可自由选择。
* 高级音视频功能强大,支持9人以上的群组视频通话,支持1080P视频,支持会议模式,支持百人以上会议,支持服务器端录制。
* 全私有部署,可不依赖任何第三方服务,完全内网部署。
* 功能齐全,涵盖所有常见即时通讯功能。另外具有强大的可扩展能力。Demo成熟完善,基本可以做到开箱即用,也可把SDK嵌入其它应用。
* API丰富,方便与其它服务系统的对接。
* 拥有机器人和频道功能。
## 野火开源项目
主要包括一下项目:
| [GitHub仓库地址(主站)](https://github.com/wildfirechat) | [码云仓库地址(镜像)](https://gitee.com/wfchat) | 说明 | 备注 |
| ------------------------------------------------------------ | ----------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------- |
| [android-chat](https://github.com/wildfirechat/android-chat) | [android-chat](https://gitee.com/wfchat/android-chat) | 野火IM Android SDK源码和App源码 | 可以很方便地进行二次开发,或集成到现有应用当中 |
| [ios-chat](https://github.com/wildfirechat/ios-chat) | [ios-chat](https://gitee.com/wfchat/ios-chat) | 野火IM iOS SDK源码和App源码 | 可以很方便地进行二次开发,或集成到现有应用当中 |
| [pc-chat](https://github.com/wildfirechat/pc-chat) | [pc-chat](https://gitee.com/wfchat/pc-chat) | 基于[Electron](https://electronjs.org/)开发的PC平台应用 | |
| [web-chat](https://github.com/wildfirechat/web-chat) | [web-chat](https://gitee.com/wfchat/web-chat) | Web平台的Demo, [体验地址](http://web.wildfirechat.cn) | |
| [wx-chat](https://github.com/wildfirechat/wx-chat) | [wx-chat](https://gitee.com/wfchat/wx-chat) | 微信小程序平台的Demo | |
| [server](https://github.com/wildfirechat/server) | [server](https://gitee.com/wfchat/server) | IM server | |
| [app server](https://github.com/wildfirechat/app_server) | [app server](https://gitee.com/wfchat/app_server) | 应用服务端 | |
| [robot_server](https://github.com/wildfirechat/robot_server) | [robot_server](https://gitee.com/wfchat/robot_server) | 机器人服务端 | |
| [push_server](https://github.com/wildfirechat/push_server) | [push_server](https://gitee.com/wfchat/push_server) | 推送服务器 | |
| [docs](https://github.com/wildfirechat/docs) | [docs](https://gitee.com/wfchat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明,[在线查看](https://docs.wildfirechat.cn/) | | |
| [GitHub仓库地址(主站)](https://github.com/wildfirechat) | [码云仓库地址(镜像)](https://gitee.com/wfchat) | 说明
| ------------------------------------------------------------ | ----------------------------------------------------- | --------------------------------------------------------------------------
| [im-server](https://github.com/wildfirechat/im-server) | [im-server](https://gitee.com/wfchat/im-server) | 野火社区版IM服务,野火IM的核心服务,处理所有IM相关业务。 |
| [app_server](https://github.com/wildfirechat/app_server) | [app_server](https://gitee.com/wfchat/app_server) | Demo应用服务,模拟客户的应用服登陆处理逻辑及部分二次开发示例。 |
| [robot_server](https://github.com/wildfirechat/robot_server) | [robot_server](https://gitee.com/wfchat/robot_server) | 机器人服务,演示野火机器人对接其它系统的方法。 |
| [push_server](https://github.com/wildfirechat/push_server) | [push_server](https://gitee.com/wfchat/push_server) | 推送服务器,可以对接所有的系统厂商推送服务或者第三方推送服务。 |
| [wf-minio](https://github.com/wildfirechat/WF-minio) | [wf-minio](https://gitee.com/wfchat/WF-minio) | 私有对象存储服务,用来支持野火IM专业版的文件存储。 |
| [wf-janus](https://github.com/wildfirechat/wf-janus ) | [wf-janus](https://gitee.com/wfchat/wf-janus ) | 高级音视频媒体服务。 |
| [android-chat](https://github.com/wildfirechat/android-chat) | [android-chat](https://gitee.com/wfchat/android-chat) | 野火IM Android SDK源码和App源码。
| [ios-chat](https://github.com/wildfirechat/ios-chat) | [ios-chat](https://gitee.com/wfchat/ios-chat) | 野火IM iOS SDK源码和App源码。
| [pc-chat](https://github.com/wildfirechat/vue-pc-chat) | [pc-chat](https://gitee.com/wfchat/vue-pc-chat) | 基于[Electron](https://electronjs.org/)的PC 端,支持Windows、Mac、Linux(包括国产化linux系统和CPU)。 |
| [web-chat](https://github.com/wildfirechat/vue-chat) | [web-chat](https://gitee.com/wfchat/vue-chat) | 野火IM Web 端, [体验地址](https://web.wildfirechat.cn) |
| [wx-chat](https://github.com/wildfirechat/wx-chat) | [wx-chat](https://gitee.com/wfchat/wx-chat) | 小程序平台的Demo(支持微信、百度、阿里、字节、QQ 等小程序平台) |
| [docs](https://github.com/wildfirechat/docs) | [docs](https://gitee.com/wfchat/docs) | 野火IM相关文档,包含设计、概念、开发、使用说明,[在线查看](https://docs.wildfirechat.cn/) |
## 野火开发文档
[在线文档](https://docs.wildfirechat.cn/)
# server
本工程为野火IM 社区版IM服务软件。野火IM作为一个通用的即时通讯解决方案,既可以直接使用,也可以集成到各种应用中。
开发一套IM系统真的很艰辛,请路过的朋友们给点个star,支持我们坚持下去🙏🙏🙏🙏🙏
### 联系我们
> 商务合作请优先采用邮箱和我们联系。技术问题请到[野火IM论坛](http://bbs.wildfirechat.cn/)发帖交流
1. heavyrain.lee 邮箱: heavyrain.lee@wildfirechat.cn 微信:wildfirechat
2. imndx 邮箱: imndx@wildfirechat.cn 微信:wfchat
### 问题交流
1. 如果大家发现bug,请在GitHub提issue
2. 其他问题,请到[野火IM论坛](http://bbs.wildfirechat.cn/)进行交流学习
3. 微信公众号
<img src="http://static.wildfirechat.cn/wx_wfc_qrcode.jpg" width = 50% height = 50% />
> 强烈建议关注我们的公众号。我们有新版本发布或者有重大更新会通过公众号通知大家,另外我们也会不定期的发布一些关于野火IM的技术介绍。
#### 体验Demo
我们提供了体验demo,请使用微信扫码下载安装体验
## 野火Demo
请使用微信扫码下载安装体验野火IM移动客户端
![野火IM](http://static.wildfirechat.cn/download_qrcode.png)
#### 应用截图
Web客户端点击[这里](https://web.wildfirechat.cn)
PC客户端点[这里](https://github.com/wildfirechat/vue-pc-chat/releases)下载安装。
小程序客户端请用微信扫码
![野火IM](http://static.wildfirechat.net/wx.jpg)
## 应用截图
![ios-demo](http://static.wildfirechat.cn/ios-demo.gif)
<img src="http://static.wildfirechat.cn/ios-message-view.png" width = 50% height = 50% />
@@ -71,16 +77,49 @@
<img src="http://static.wildfirechat.cn/ios-voip-view.png" width = 50% height = 50% />
## 编译
在安装JDK1.8以上及maven的前提下,在命令行中执行```mvn clean compile package```,生成的目标文件在```./distribution/target/distribution-xxxx-bundle-tar.tar.gz```
在安装JDK1.8以上及maven的前提下,在命令行中执行```mvn clean package```,生成的目标文件在```./distribution/target/distribution-xxxx-bundle-tar.tar.gz```
> 由于使用了一个git的maven插件,如果本地没有git信息就会编译出错,请使用```git clone```的方法下载代码,或者下载压缩包解压后在根目录创建```.git```的空目录。建议用```git clone```的方式下载代码。
## 配置
解压```distribution-xxxx-bundle-tar.tar.gz```,修改解压出来的```config```目录下的```wildfirechat.conf```。修改如下部分:
1. 修改```server.ip```为您的服务器的公网IP,或者域名。如果用域名需要做好域名解析。
2. 可以阅读配置文件注释和文档,对其它配置项进行调整。
## 运行
在程序目录运行如下命令:
```
./bin/wildfirechat.sh
```
## 验证
1. 在浏览器中输入地址 ```http://${ip}/api/version```可以看到返回一个json文件。
2. 部署[应用服务](应用服务),配置和编译[Android客户端](https://github.com/wildfirechat/android-chat)和[iOS客户端](https://github.com/wildfirechat/ios-chat)进行验证。详情可参考[快速开始](https://docs.wildfirechat.cn/quick_start/)。
## 升级说明
1. 从0.42 版本增加了群成员数限制,默认为2000。如果您从之前的版本升级到这个版本或以后,需要注意到群成员数的限制。升级之后超出限制的群不受影响,但不能继续加人,如果您想修改默认值,可以在升级版本之后,修改t_setting表,把默认的大小改为您期望的人数。另外修改t_group表,把已经存在的群组max_member_count改成您期望的,然后重启。
2. 0.46和0.47版本升级到0.48及以后版本时,可能会提示flyway migrate 38错误,请执行 [修复脚本](https://github.com/wildfirechat/server/blob/wildfirechat/flyway_repaire_migrate_38.sql) 进行修复。0.46和0.47版本之外的版本不会出现此问题。
3. 从0.54之前版本升级到0.54及以后版本时,会提示flyway migrate错误。因为0.54版本删除了sql脚本中默认敏感词的内容,flyway checksum失败。请执行```update flyway_schema_history set checksum = 0 where script = 'V17__add_default_sensitive_word.sql';```来修复。
4. 从0.59之前的版本升级到之后的版本执行数据库升级时间比较长,请耐心等待提示运行成功,避免中途中断。
## 联系我们
商务合作请使用如下邮箱和微信联系:
邮箱: support@wildfirechat.cn 微信1:wfchat 微信2:wildfirechat
## 问题交流
1. 如果大家发现bug,请在GitHub提issue;如果有需求也请给我们提issue。
2. 其他问题,请到[野火IM论坛](http://bbs.wildfirechat.cn/)进行交流学习
3. 关注我们的公众号。我们有新版本发布或者有重大更新会通过公众号通知大家,另外我们也会不定期的发布一些关于野火IM的技术介绍。
<img src="http://static.wildfirechat.cn/wx_wfc_qrcode.jpg" width = 50% height = 50% />
> 我们有研发工程师轮流值班处理issue和论坛,一般简单问题几个小时就会回复一遍,疑难Bug的修改和新需求的开发我们也会尽快解决。
## 特别感谢
1. [moquette](https://github.com/moquette-io/moquette) 本项目是基于此项目二次开发而来,处理MQTT相关业务。
2. [loServer](https://github.com/looly/loServer) 本项目使用loServer处理HTTP相关业务。
+6 -3
View File
@@ -118,13 +118,13 @@ friend.disable_nick_name_search false
##禁止发送好友邀请,通过server api添加好友不受此限制(force参数需要为true)
friend.disable_friend_request false
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为无限长期限。
friend.repeat_request_duration 604800000
##好友请求被拒绝后再次发送的间隔,单位是毫秒,默认是30天,0为不限制
##好友请求被拒绝后再次发送的间隔,单位是毫秒,默认是30天,0为不限制。不能小于friend.repeat_request_duration。
friend.reject_request_duration 2592000000
##好友请求过期时间,单位是毫秒,默认是7天,0为不限制
##好友请求过期时间,单位是毫秒,默认是7天,0为无限长期限。
friend.request_expiration_duration 604800000
##添加好友后会发送欢迎消息,比如"你们已经是好友了,可以聊天了"。这个开关控制是用旧的方式还是用新的方式。
@@ -157,6 +157,9 @@ group.visible_quit_or_kickoff_notification 0
## 注意,修改本配置不会对已经同步的信息产生影响。
#user.hide_properties 3,4,5
## 销毁用户时,用户信息会被清空,deleted字段设置为1,这个开关控制是否保留用户昵称,默认为true。
user.keep_display_name_when_destroy true
# 好友/好友请求/用户设置 这三类数据同步的最大条目数。之前是客户第一次登录时,会把所有的对应数据一次下载到客户端,但如果有特别多的信息,会导致无法同步到客户端,
# 因此需要分段多次同步,此开关定义了每次同步的数据的条数。此需要客户端支持,客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。
#sync.data_part_size 1000
+1 -1
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.85</version>
<version>0.87</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -0,0 +1,56 @@
/*
* 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 com.xiaoleilu.loServer.action.admin;
import cn.wildfirechat.common.APIPath;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.InputMessageUid;
import cn.wildfirechat.pojos.OutputMessageData;
import cn.wildfirechat.pojos.RecallMessageData;
import cn.wildfirechat.proto.WFCMessage;
import com.xiaoleilu.loServer.RestResult;
import com.xiaoleilu.loServer.annotation.HttpMethod;
import com.xiaoleilu.loServer.annotation.Route;
import com.xiaoleilu.loServer.handler.Request;
import com.xiaoleilu.loServer.handler.Response;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.util.internal.StringUtil;
import win.liyufan.im.IMTopic;
@Route(APIPath.Msg_GetOne)
@HttpMethod("POST")
public class GetMessageAction extends AdminAction {
@Override
public boolean isTransactionAction() {
return true;
}
@Override
public boolean action(Request request, Response response) {
if (request.getNettyRequest() instanceof FullHttpRequest) {
InputMessageUid inputMessageUid = getRequestBody(request.getNettyRequest(), InputMessageUid.class);
if (inputMessageUid != null && inputMessageUid.messageUid > 0) {
RestResult result;
WFCMessage.Message msg = messagesStore.getMessage(inputMessageUid.messageUid);
if(msg == null) {
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
} else {
result = RestResult.ok(OutputMessageData.fromProtoMessage(msg));
}
setResponseContent(result, response);
} else {
setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);
}
}
return true;
}
}
@@ -160,6 +160,8 @@ public final class BrokerConstants {
public static final String GROUP_Visible_Quit_Kickoff_Notification = "group.visible_quit_or_kickoff_notification";
public static final String USER_HIDE_PROPERTIES = "user.hide_properties";
public static final String USER_KEEP_DISPLAY_NAME_WHEN_DESTROY = "user.keep_display_name_when_destroy";
public static final String SYNC_Data_Part_Size = "sync.data_part_size";
public static final String MESSAGES_FORBIDDEN_CLIENT_SEND_TYPES = "message.forbidden_client_send_types";
@@ -11,9 +11,7 @@ package io.moquette.imhandler;
import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import io.moquette.persistence.MemorySessionStore;
import io.moquette.spi.impl.Qos1PublishHandler;
import io.moquette.spi.impl.security.TokenAuthenticator;
import io.netty.buffer.ByteBuf;
import win.liyufan.im.IMTopic;
@@ -30,7 +28,7 @@ public class DestroyUserHandler extends IMHandler<WFCMessage.IDBuf> {
m_messagesStore.clearUserFriend(fromUser);
m_messagesStore.clearUserGroups(fromUser);
m_messagesStore.clearUserChannels(fromUser);
m_messagesStore.destoryUser(fromUser);
m_messagesStore.destroyUser(fromUser);
m_messagesStore.destroyRobot(fromUser);
});
@@ -160,6 +160,7 @@ public class MemoryMessagesStore implements IMessagesStore {
private boolean mGroupAllowRobotCustomOperationNotification;
private int mGroupVisibleQuitKickoffNotification;
private int mSyncDataPartSize = 0;
private boolean keepDisplayNameWhenDestroyUser = true;
private Set<Integer> mUserHideProperties = new HashSet<>();
@@ -418,6 +419,11 @@ public class MemoryMessagesStore implements IMessagesStore {
mSyncDataPartSize = Integer.parseInt(server.getConfig().getProperty(SYNC_Data_Part_Size, "0"));
} catch (Exception e) {
}
try {
keepDisplayNameWhenDestroyUser = Boolean.parseBoolean(server.getConfig().getProperty(USER_KEEP_DISPLAY_NAME_WHEN_DESTROY, "true"));
} catch (Exception e) {
}
@@ -2487,25 +2493,41 @@ public class MemoryMessagesStore implements IMessagesStore {
}
@Override
public void destoryUser(String userId) {
public void destroyUser(String userId) {
HazelcastInstance hzInstance = m_Server.getHazelcastInstance();
IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);
WFCMessage.User us = mUserMap.get(userId);
if (us != null) {
us = WFCMessage.User.newBuilder()
.setUid(userId)
.setUpdateDt(System.currentTimeMillis())
.setName(userId)
.setDeleted(1)
.clearDisplayName()
.clearAddress()
.clearCompany()
.clearEmail()
.clearExtra()
.clearMobile()
.clearPortrait()
.clearSocial()
.build();
if (keepDisplayNameWhenDestroyUser) {
us = WFCMessage.User.newBuilder()
.setUid(userId)
.setUpdateDt(System.currentTimeMillis())
.setName(userId)
.setDeleted(1)
.clearAddress()
.clearCompany()
.clearEmail()
.clearExtra()
.clearMobile()
.clearPortrait()
.clearSocial()
.build();
} else {
us = WFCMessage.User.newBuilder()
.setUid(userId)
.setUpdateDt(System.currentTimeMillis())
.setName(userId)
.setDeleted(1)
.clearDisplayName()
.clearAddress()
.clearCompany()
.clearEmail()
.clearExtra()
.clearMobile()
.clearPortrait()
.clearSocial()
.build();
}
try {
databaseStore.updateUser(us);
@@ -751,10 +751,12 @@ public class MemorySessionStore implements ISessionsStore {
public void disableSession(String userId, String clientId) {
Session session = sessions.get(clientId);
if (session != null && session.getDeleted() == 0 && (userId == null || session.getUsername().equals(userId))) {
databaseStore.updateSessionDeleted(session.getUsername(), clientId, 1);
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);
sessionSet.remove(clientId);
sessions.remove(clientId);
mServer.getProcessor().processOffline(session, true, () -> {
databaseStore.updateSessionDeleted(session.getUsername(), clientId, 1);
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);
sessionSet.remove(clientId);
sessions.remove(clientId);
});
}
}
@@ -772,23 +774,25 @@ public class MemorySessionStore implements ISessionsStore {
return;
}
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);
sessionSet.remove(clientID);
mServer.getProcessor().processOffline(session, true, () -> {
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);
sessionSet.remove(clientID);
// remove also the messages stored of type QoS1/2
LOG.info("Removing stored messages with QoS 1 and 2. ClientId={}", clientID);
// remove also the messages stored of type QoS1/2
LOG.info("Removing stored messages with QoS 1 and 2. ClientId={}", clientID);
session.secondPhaseStore.clear();
session.outboundFlightMessages.clear();
session.inboundFlightMessages.clear();
session.secondPhaseStore.clear();
session.outboundFlightMessages.clear();
session.inboundFlightMessages.clear();
LOG.info("Wiping existing subscriptions. ClientId={}", clientID);
LOG.info("Wiping existing subscriptions. ClientId={}", clientID);
//remove also the enqueued messages
dropQueue(clientID);
//remove also the enqueued messages
dropQueue(clientID);
// TODO this missing last step breaks the junit test
sessions.remove(clientID);
// TODO this missing last step breaks the junit test
sessions.remove(clientID);
});
}
@Override
public boolean isMultiEndpointSupported() {
@@ -150,7 +150,7 @@ public interface IMessagesStore {
ErrorCode updateUserInfo(InputOutputUserInfo userInfo, int flag);
void addUserInfo(WFCMessage.User user, String password) throws Exception;
void destoryUser(String userId);
void destroyUser(String userId);
void updateUserInfo(WFCMessage.User user) throws Exception;
WFCMessage.User getUserInfo(String userId);
WFCMessage.User getUserInfoByName(String name);
@@ -620,15 +620,27 @@ public class ProtocolProcessor {
String username = NettyUtils.userName(channel);
MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);
if(session != null) {
session.refreshLastActiveTime();
forwardOnlineStatusEvent(username, clientID, session.getPlatform(), clearSession ? UserOnlineStatus.LOGOUT : UserOnlineStatus.OFFLINE, session.getAppName());
processOffline(session, clearSession, () -> {
ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);
if(connectionDescriptors.removeConnection(oldConnDescr)) {
m_interceptor.notifyClientConnectionLost(clientID, username);
}
});
} else {
ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);
if(connectionDescriptors.removeConnection(oldConnDescr)) {
m_interceptor.notifyClientConnectionLost(clientID, username);
}
}
}
ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);
if(connectionDescriptors.removeConnection(oldConnDescr)) {
m_interceptor.notifyClientConnectionLost(clientID, username);
}
public void processOffline(MemorySessionStore.Session session, boolean logout, Runnable runnable) {
if(session != null) {
session.refreshLastActiveTime();
forwardOnlineStatusEvent(session.getUsername(), session.getClientID(), session.getPlatform(), logout ? UserOnlineStatus.LOGOUT : UserOnlineStatus.OFFLINE, session.getAppName());
if(runnable != null) {
runnable.run();
}
m_messagesStore.updateUserOnlineSetting(session, false);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.85</version>
<version>0.87</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -50,6 +50,7 @@ public interface APIPath {
String Msg_Recall = "/admin/message/recall";
String Msg_Delete = "/admin/message/delete";
String Msg_Update = "/admin/message/update";
String Msg_GetOne = "/admin/message/get_one";
String Msg_Broadcast = "/admin/message/broadcast";
String Msg_Multicast = "/admin/message/multicast";
String Msg_RecallBroadCast = "/admin/message/recall_broadcast";
@@ -9,7 +9,7 @@ public class GetOnlineUserResult {
public int platform;
}
ArrayList<GetOnlineUserResult.UserClient> userClients;
public ArrayList<GetOnlineUserResult.UserClient> userClients;
public int totalCount;
public int offset;
}
@@ -0,0 +1,12 @@
package cn.wildfirechat.pojos;
public class InputMessageUid {
public long messageUid;
public InputMessageUid() {
}
public InputMessageUid(long messageUid) {
this.messageUid = messageUid;
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.85</version>
<version>0.87</version>
</parent>
<artifactId>distribution</artifactId>
@@ -113,13 +113,13 @@ friend.disable_nick_name_search false
##禁止发送好友邀请,通过server api添加好友不受此限制(force参数需要为true)
friend.disable_friend_request false
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为不限制
##好友请求重复发送的间隔,单位是毫秒,默认是7天,0为无限长期限。
friend.repeat_request_duration 604800000
##好友请求被拒绝后再次发送的间隔,单位是毫秒,默认是30天,0为不限制
##好友请求被拒绝后再次发送的间隔,单位是毫秒,默认是30天,0为不限制。不能小于friend.repeat_request_duration。
friend.reject_request_duration 2592000000
##好友请求过期时间,单位是毫秒,默认是7天,0为不限制
##好友请求过期时间,单位是毫秒,默认是7天,0为无限长期限。
friend.request_expiration_duration 604800000
##添加好友后会发送欢迎消息,比如"你们已经是好友了,可以聊天了"。这个开关控制是用旧的方式还是用新的方式。
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>0.85</version>
<version>0.87</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.85</version>
<version>0.87</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -667,6 +667,13 @@ public class Main {
System.exit(-1);
}
IMResult<OutputMessageData> outputMessageDataIMResult = MessageAdmin.getMessage(resultSendMessage.result.getMessageUid());
if(outputMessageDataIMResult != null && outputMessageDataIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && outputMessageDataIMResult.getResult().getMessageId() == resultSendMessage.getResult().getMessageUid()) {
System.out.println("get message success");
} else {
System.out.println("get message failure");
System.exit(-1);
}
IMResult<Void> voidIMResult = MessageAdmin.recallMessage("user1", resultSendMessage.getResult().getMessageUid());
if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
@@ -48,7 +48,17 @@ public class MessageAdmin {
return AdminHttpUtils.httpJsonPost(path, updateMessageContentData, Void.class);
}
/**
* 获取单条消息。如果想要更多消息的读取,可以直接读取IM服务的数据库。
* @param messageUid
* @return
* @throws Exception
*/
public static IMResult<OutputMessageData> getMessage(long messageUid) throws Exception {
String path = APIPath.Msg_GetOne;
InputMessageUid inputMessageUid = new InputMessageUid(messageUid);
return AdminHttpUtils.httpJsonPost(path, inputMessageUid, OutputMessageData.class);
}
/**
* 撤回群发或者广播的消息