Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
220e010193 | ||
|
|
865888824c | ||
|
|
583df110fd | ||
|
|
f204bd693e | ||
|
|
b6be1ca045 | ||
|
|
beb403a9f7 | ||
|
|
00f1187200 | ||
|
|
7ee490cc1b | ||
|
|
3dc0ae7a47 | ||
|
|
994a8b5c4a | ||
|
|
5cd2e7affe | ||
|
|
f29ffe4cd2 | ||
|
|
6c7d2ab3ad | ||
|
|
ab7b20871a | ||
|
|
6883418e22 | ||
|
|
32f7266a5f | ||
|
|
35db76e9cd | ||
|
|
4f6aa87b9f | ||
|
|
f5816e20dd | ||
|
|
e72ae59e49 | ||
|
|
f0c2fd82ca | ||
|
|
5a588c8268 | ||
|
|
2adc030d6f | ||
|
|
b0ca8ed2b7 | ||
|
|
f9d5c861ce | ||
|
|
9aaaa71ce9 | ||
|
|
73a971bde3 | ||
|
|
5942eb7b15 | ||
|
|
b97fea1841 | ||
|
|
33637229d6 | ||
|
|
af366fcdb2 | ||
|
|
c9089c5d51 | ||
|
|
3afc6a2da9 | ||
|
|
12d22e78bf | ||
|
|
bcf969e56f | ||
|
|
b3a95c0310 | ||
|
|
ae863ab6e4 | ||
|
|
688ca4e31d | ||
|
|
724b6dddd6 | ||
|
|
bf3b30eb2c | ||
|
|
4f0545dfc1 | ||
|
|
c1b9a81e12 | ||
|
|
029b6ed691 | ||
|
|
4fdefca33d | ||
|
|
e90ca145be | ||
|
|
bf3d3c308d | ||
|
|
bee2f3c6ef | ||
|
|
d4e13e4578 | ||
|
|
66486b019f | ||
|
|
6510204fe6 | ||
|
|
b4b736c0c4 | ||
|
|
c4e8c5811c | ||
|
|
804b2fc610 | ||
|
|
0a7487a144 | ||
|
|
4ae9de0628 | ||
|
|
04d0f717d8 | ||
|
|
b3ddda78a1 | ||
|
|
066e74be5f | ||
|
|
f9c2cf8e31 | ||
|
|
d3fc625299 | ||
|
|
905763b6e3 | ||
|
|
877b7bc217 | ||
|
|
d8b7f6a8de | ||
|
|
579d3b529f | ||
|
|
065a79adc3 | ||
|
|
5ed45ef414 | ||
|
|
ba671b3370 | ||
|
|
e975f20a6b | ||
|
|
70bdebd4a0 | ||
|
|
409078801e | ||
|
|
06fed7de52 | ||
|
|
da2428a9f9 | ||
|
|
83b6ae5229 | ||
|
|
4b7804cdfd | ||
|
|
d075b5212f | ||
|
|
636c8ce219 | ||
|
|
091d7fa3ec | ||
|
|
59356e5b52 | ||
|
|
882bf29e63 | ||
|
|
f3eef4dd6b | ||
|
|
898983c6e5 | ||
|
|
dae5d032fa | ||
|
|
ff76622796 | ||
|
|
a6fd11a243 | ||
|
|
cf983be44c | ||
|
|
1a72de0e85 | ||
|
|
bf70a1e80e | ||
|
|
512d797d4d | ||
|
|
4a46dd1dde | ||
|
|
7494cdc071 | ||
|
|
608184ef9e | ||
|
|
eb4d8a9b68 | ||
|
|
6b92ae383c | ||
|
|
5fee857c4a | ||
|
|
53b7139c30 | ||
|
|
83e864d667 | ||
|
|
b88297e6de | ||
|
|
4aa2f46011 | ||
|
|
1fb3c757e2 | ||
|
|
3f640b6c14 | ||
|
|
49eb57af00 | ||
|
|
6bd6a80e71 | ||
|
|
38b84f0fa5 | ||
|
|
1f46debd0c | ||
|
|
37998e76d1 | ||
|
|
80b5508533 | ||
|
|
a646cc8227 | ||
|
|
92692adf52 | ||
|
|
b2cfc2b99b | ||
|
|
86e08f6151 | ||
|
|
8d852eb2d1 | ||
|
|
8bef018911 | ||
|
|
5e13419c28 | ||
|
|
503a7ae18f | ||
|
|
dfb9638a38 | ||
|
|
8452b0675b | ||
|
|
930643706a | ||
|
|
a2eac1f721 | ||
|
|
6e994cd694 | ||
|
|
c82869c631 | ||
|
|
f5a94868c4 | ||
|
|
c5628d613b | ||
|
|
9509b1ffa8 | ||
|
|
c1dac8a21e | ||
|
|
950846df45 | ||
|
|
31d96e2dc6 | ||
|
|
031e96075e | ||
|
|
bf2caeac6c | ||
|
|
12e523b37e | ||
|
|
576c985d8f | ||
|
|
9365807f47 | ||
|
|
25ce10fa61 | ||
|
|
09c333501f | ||
|
|
c51b09ee3a | ||
|
|
4d82eace86 | ||
|
|
385b03a163 | ||
|
|
4b438afa69 | ||
|
|
66961b94da | ||
|
|
39b62e5942 | ||
|
|
5bb8ab3d95 | ||
|
|
8dfc23b61d | ||
|
|
c8769808b5 | ||
|
|
2fc106aa26 | ||
|
|
da0b725ff8 | ||
|
|
15703d66fb | ||
|
|
c68beeaa51 | ||
|
|
5ef8868916 | ||
|
|
24488cc985 | ||
|
|
1c9faaa1e6 | ||
|
|
ac32875b14 | ||
|
|
07c1dd29e0 | ||
|
|
bd93233c34 | ||
|
|
20aec2fbcf | ||
|
|
a149139143 | ||
|
|
c857d1abb7 | ||
|
|
dde9da7006 | ||
|
|
d18a1970e5 | ||
|
|
66b9aeec17 | ||
|
|
ea301a3923 |
@@ -49,6 +49,8 @@ maven-metadata.xml
|
||||
/bin/
|
||||
broker/config/git.properties
|
||||
distribution/src/main/resources/git.properties
|
||||
license/target
|
||||
server/target
|
||||
broker/h2db
|
||||
broker/media
|
||||
common/target
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
## 野火IM解决方案
|
||||
|
||||
野火IM是一套跨平台、全开源的即时通讯解决方案,主要包含以下内容。
|
||||
野火IM是一套跨平台、核心功能开源的即时通讯解决方案,主要包含以下内容。
|
||||
|
||||
| 仓库 | 说明 | 备注 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------- |
|
||||
| [android-chat](https://github.com/wildfirechat/android-chat) | 野火IM Android 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平台应用 | |
|
||||
| [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相关文档,包含设计、概念、开发、使用说明 | |
|
||||
| 仓库 | 说明 | 备注 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------- | ---- |
|
||||
| [android-chat](https://github.com/wildfirechat/android-chat) | 野火IM Android 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平台应用 | |
|
||||
| [web-chat](https://github.com/wildfirechat/web-chat) | Web平台的Demo, [体验地址](http://web.wildfirechat.cn) | |
|
||||
| [wx-chat](https://github.com/wildfirechat/wx-chat) | 微信小程序平台的Demo | |
|
||||
| [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作为一个通用的即时通讯解决方案,可以集成到各种应用中。请阅读[docs](http://docs.wildfirechat.cn)或下载服务器[发布版本](https://github.com/wildfirechat/server/releases)
|
||||
@@ -20,11 +21,18 @@
|
||||
|
||||
开发一套IM系统真的很艰辛,请路过的朋友们给点个star,支持我们坚持下去🙏🙏🙏🙏🙏
|
||||
|
||||
|
||||
### 联系我们
|
||||
问题讨论请加群:822762829
|
||||
|
||||
微信公众号:
|
||||
> 商务合作请优先采用邮箱和我们联系。技术问题请到[野火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% />
|
||||
|
||||
@@ -35,6 +43,11 @@
|
||||
|
||||

|
||||
|
||||
#### 加入野火官方体验交流群
|
||||
使用野火IM移动客户端扫码下面二维码(不是使用微信扫码),和野火IM的爱好者一起畅谈野火IM的问题和经验:
|
||||
|
||||

|
||||
|
||||
#### 应用截图
|
||||

|
||||
|
||||
@@ -65,7 +78,7 @@
|
||||
|
||||
| 捐赠者 | 商标 | 金额 | 简介 |
|
||||
| ----- | ---- | -------- | --- |
|
||||
| [SAMOS](http://samos.io) |  | 每月2000¥ | 一站式区块链解决方案服务商(http://samos.io) |
|
||||
| [SAMOS](http://samos.io) |  | 保密 | 一站式区块链解决方案服务商(http://samos.io) |
|
||||
|
||||
## 特别感谢
|
||||
1. [moquette](https://github.com/moquette-io/moquette) 本项目是基于此项目二次开发而来,处理MQTT相关业务。
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
|
||||
<!-- # 本配置文件为debug使用,修改这里不会在Release包中生效。Release中包含的配置文件在 ${Porject_Path}/distribution/src/main/resources目录下-->
|
||||
|
||||
|
||||
<hazelcast
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#
|
||||
#
|
||||
# 本配置文件为debug使用,修改这里不会在Release包中生效。Release中包含的配置文件在 ${Porject_Path}/distribution/src/main/resources目录下
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
|
||||
#*********************************************************************
|
||||
# Server configuration
|
||||
#*********************************************************************
|
||||
#服务器的接入IP。给客户端提供是${server.ip}和${http_port}。
|
||||
#客户端会从${http_port}端口获取到长链接端口。
|
||||
#客户端会从${http_port}端口获取到长链接端口。这个地址一定要改成客户端可以访问到的IP地址
|
||||
# (如果您部署云服务器上或者具有独立公网出口的服务器上,请改为对应的公网IP;如果您部署在在内网环境下,在内网使用,这个地方改成内网地址)
|
||||
server.ip 0.0.0.0
|
||||
|
||||
##原生客户端长链接端口
|
||||
@@ -26,14 +35,15 @@ host 0.0.0.0
|
||||
##本地绑定端口
|
||||
local_port 80
|
||||
|
||||
##是否使用内置DB。0使用mysql;1使用h2db
|
||||
embed.db 1
|
||||
##是否使用内置DB。0使用mysql;1使用h2db;2使用mysql+mongodb。社区版只支持0和1,专业版支持2
|
||||
embed.db 0
|
||||
|
||||
##服务器管理接口密钥
|
||||
http.admin.secret_key 123456
|
||||
|
||||
##服务器API接口参数是否检查时间。当设置为false时,所有的请求会检查时间的有效性;当设置为true时,可以在http.admin.secret_key保持不变的情况下,使用固定的服务API签名
|
||||
##nonce = "76616", timestamp = "1558350862502", sign = "b98f9b0717f59febccf1440067a7f50d9b31bdde"
|
||||
##这个地方上线前要改为false
|
||||
http.admin.no_check_time true
|
||||
|
||||
##客户端协议栈密钥,需要与客户端协议栈文件libemqq.cc文件中的aes_key值保持一致,16进制byte用逗号分割。这个密钥对安全性帮助不大,客户不要修改
|
||||
@@ -42,6 +52,15 @@ client.proto.secret_key 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0
|
||||
##用来生产im token的私钥,只在服务器使用,客户端不用。正式使用时为了安全一定要修改这个值,切记切记
|
||||
token.key testim
|
||||
|
||||
##首次登录,是否接收之前的历史消息。0 不接收;1接收。
|
||||
message.roaming 0
|
||||
|
||||
##是否开启拉取远程历史消息
|
||||
message.remote_history_message 0
|
||||
|
||||
##服务器为每个用户缓存的消息数量。这个值改得太大,拉取消息时间变长,另外会占用大量内存。
|
||||
message.max_queue 1024
|
||||
|
||||
#*********************************************************************
|
||||
# hazelcase configuration
|
||||
#*********************************************************************
|
||||
@@ -86,6 +105,9 @@ qiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn
|
||||
# 本地媒体服务器配置。
|
||||
local.media.storage.root media
|
||||
|
||||
# 是否支持多端登陆
|
||||
server.multi_endpoint false
|
||||
|
||||
#*********************************************************************
|
||||
# Push server configuration
|
||||
#*********************************************************************
|
||||
@@ -95,10 +117,20 @@ push.android.server.address http://localhost:8085/android/push
|
||||
push.ios.server.address http://localhost:8085/ios/push
|
||||
|
||||
|
||||
#*********************************************************************
|
||||
# MongoDB configuration
|
||||
#*********************************************************************
|
||||
#专业版支持,社区版请忽略
|
||||
#mongodb.client_uri mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
|
||||
#mongodb.client_uri mongodb://host1:27017,host2:27017,host3:27017/wfchat?replicaSet=myReplicaSet
|
||||
mongodb.client_uri mongodb://wfc:123456@localhost:27017/wfchat
|
||||
mongodb.database wfchat
|
||||
mongodb.data_expire_days 1096
|
||||
|
||||
#*********************************************************************
|
||||
# Sensitive configuration
|
||||
#*********************************************************************
|
||||
##文本敏感词过滤处理方法,0 发送失败;1 发送成功但消息被服务器直接丢弃;2 命中的敏感词被替换成***
|
||||
##文本敏感词过滤处理方法,0 发送失败;1 发送成功但消息被服务器直接丢弃;2 命中的敏感词被替换成***;3 记录并继续发送
|
||||
sensitive.filter.type 0
|
||||
|
||||
#*********************************************************************
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
|
||||
insert into t_user (`_uid`,`_name`,`_display_name`,`_type`,`_dt`) values ('admin','admin','系统管理员',3,1);
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
ALTER TABLE t_user_session MODIFY _token VARCHAR(240) DEFAULT NULL;
|
||||
@@ -0,0 +1,4 @@
|
||||
alter table `t_group` add column `_mute` tinyint NOT NULL DEFAULT 0;
|
||||
alter table `t_group` add column `_join_type` tinyint NOT NULL DEFAULT 0;
|
||||
alter table `t_group` add column `_private_chat` tinyint NOT NULL DEFAULT 0;
|
||||
alter table `t_group` add column `_searchable` tinyint NOT NULL DEFAULT 0;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
|
||||
DROP TABLE IF EXISTS `t_settings`;
|
||||
CREATE TABLE `t_settings` (
|
||||
`id` int(11) NOT NULL PRIMARY KEY,
|
||||
`value` varchar(64) NOT NULL,
|
||||
`desc` varchar(128) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
insert into t_settings(`id`, `value`,`desc`) values (1, '3000', '最大群成员数量');
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_sensitiveword` add column `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
alter table `t_user_session` modify column `_voip_token` varchar(240) DEFAULT '';
|
||||
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
alter table t_friend add column `_blacked` tinyint DEFAULT 0;
|
||||
update t_friend set `_blacked` = 1 where `_state` = 2;
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_user_session` ADD INDEX `session_token_index` ( `_token` );
|
||||
+1
@@ -0,0 +1 @@
|
||||
alter table t_friend_request add index `friend_request_uid_index` (`_friend_uid`);
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_user_session` ADD INDEX `session_uid_index` ( `_uid` );
|
||||
+1
@@ -0,0 +1 @@
|
||||
alter table `t_user_session` add column `_deleted` tinyint DEFAULT 0;
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
alter table `t_user` add column `_deleted` tinyint DEFAULT 0;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table t_user add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;
|
||||
alter table t_group add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_messages` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
|
||||
DROP TABLE IF EXISTS `t_sensitive_messages`;
|
||||
CREATE TABLE `t_sensitive_messages` (
|
||||
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`_mid` bigint(20) NOT NULL,
|
||||
`_from` varchar(64) NOT NULL,
|
||||
`_type` tinyint NOT NULL DEFAULT 0,
|
||||
`_target` varchar(64) NOT NULL,
|
||||
`_line` int(11) NOT NULL DEFAULT 0,
|
||||
`_data` BLOB NOT NULL,
|
||||
`_searchable_key` TEXT DEFAULT NULL,
|
||||
`_dt` DATETIME NOT NULL DEFAULT NOW(),
|
||||
`_content_type` int(11) NOT NULL DEFAULT 0,
|
||||
UNIQUE INDEX `sensitive_message_uid_index` (`_mid` ASC)
|
||||
);
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
|
||||
insert into t_user (`_uid`,`_name`,`_display_name`,`_type`,`_dt`) values ('admin','admin','系统管理员',3,1);
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
ALTER TABLE t_user_session MODIFY _token VARCHAR(240) DEFAULT NULL;
|
||||
@@ -0,0 +1,4 @@
|
||||
alter table `t_group` add column `_mute` tinyint NOT NULL DEFAULT 0;
|
||||
alter table `t_group` add column `_join_type` tinyint NOT NULL DEFAULT 0;
|
||||
alter table `t_group` add column `_private_chat` tinyint NOT NULL DEFAULT 0;
|
||||
alter table `t_group` add column `_searchable` tinyint NOT NULL DEFAULT 0;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
|
||||
DROP TABLE IF EXISTS `t_session`;
|
||||
CREATE TABLE `t_session` (
|
||||
`row_id` varchar(50) not null primary key,
|
||||
`del_flag` tinyint(1) default 0 null,
|
||||
`create_time` timestamp null,
|
||||
`update_time` timestamp null,
|
||||
`expire_time` timestamp null,
|
||||
`user_id` int null,
|
||||
constraint `t_session_pk_2` unique (`user_id`, `expire_time`)
|
||||
)
|
||||
ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table t_user MODIFY column `_createTime` DATETIME NOT NULL DEFAULT NOW();
|
||||
alter table t_group MODIFY column `_createTime` DATETIME NOT NULL DEFAULT NOW();
|
||||
@@ -0,0 +1,4 @@
|
||||
alter table t_session MODIFY column `create_time` DATETIME NOT NULL DEFAULT NOW();
|
||||
alter table t_session MODIFY column `update_time` DATETIME NOT NULL DEFAULT NOW();
|
||||
alter table t_session MODIFY column `expire_time` DATETIME NOT NULL DEFAULT NOW();
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
update t_messages_0 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_1 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_2 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_3 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_4 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_5 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_6 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_7 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_8 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_9 set _dt = date_add(_dt, interval 8 hour);
|
||||
|
||||
update t_messages_10 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_11 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_12 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_13 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_14 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_15 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_16 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_17 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_18 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_19 set _dt = date_add(_dt, interval 8 hour);
|
||||
|
||||
update t_messages_20 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_21 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_22 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_23 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_24 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_25 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_26 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_27 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_28 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_29 set _dt = date_add(_dt, interval 8 hour);
|
||||
|
||||
|
||||
update t_messages_30 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_31 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_32 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_33 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_34 set _dt = date_add(_dt, interval 8 hour);
|
||||
update t_messages_35 set _dt = date_add(_dt, interval 8 hour);
|
||||
+4038
File diff suppressed because it is too large
Load Diff
+13
@@ -0,0 +1,13 @@
|
||||
|
||||
DROP TABLE IF EXISTS `t_settings`;
|
||||
CREATE TABLE `t_settings` (
|
||||
`id` int(11) NOT NULL PRIMARY KEY,
|
||||
`value` varchar(64) NOT NULL,
|
||||
`desc` varchar(128) NOT NULL default ""
|
||||
)
|
||||
ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
insert into t_settings(`id`, `value`,`desc`) values (1, "3000", "最大群成员数量");
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_sensitiveword` add column `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT;
|
||||
@@ -0,0 +1,3 @@
|
||||
alter table `t_user_session` modify column `_voip_token` varchar(240) DEFAULT '';
|
||||
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
alter table t_friend add column `_blacked` tinyint DEFAULT 0 COMMENT "0, normal; 1, blacked";
|
||||
update t_friend set `_blacked` = 1 where `_state` = 2;
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_user_session` ADD INDEX `session_token_index` ( `_token` );
|
||||
@@ -0,0 +1 @@
|
||||
alter table t_friend_request add index `friend_request_uid_index` (`_friend_uid`);
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_user_session` ADD INDEX `session_uid_index` ( `_uid` );
|
||||
@@ -0,0 +1 @@
|
||||
alter table `t_user_session` add column `_deleted` tinyint DEFAULT 0;
|
||||
+1
@@ -0,0 +1 @@
|
||||
alter table `t_user` add column `_deleted` tinyint DEFAULT 0;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table t_user add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;
|
||||
alter table t_group add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;
|
||||
@@ -0,0 +1,36 @@
|
||||
alter table `t_messages_0` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_1` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_2` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_3` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_4` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_5` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_6` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_7` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_8` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_9` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_10` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_11` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_12` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_13` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_14` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_15` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_16` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_17` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_18` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_19` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_20` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_21` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_22` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_23` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_24` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_25` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_26` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_27` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_28` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_29` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_30` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_31` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_32` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_33` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_34` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
alter table `t_messages_35` add column `_content_type` int(11) NOT NULL DEFAULT '0';
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
|
||||
DROP TABLE IF EXISTS `t_sensitive_messages`;
|
||||
CREATE TABLE `t_sensitive_messages` (
|
||||
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`_mid` bigint(20) NOT NULL,
|
||||
`_from` varchar(64) NOT NULL,
|
||||
`_type` tinyint NOT NULL DEFAULT 0,
|
||||
`_target` varchar(64) NOT NULL,
|
||||
`_line` int(11) NOT NULL DEFAULT 0,
|
||||
`_data` BLOB NOT NULL,
|
||||
`_searchable_key` TEXT DEFAULT NULL,
|
||||
`_dt` DATETIME NOT NULL,
|
||||
`_content_type` int(11) NOT NULL DEFAULT '0',
|
||||
INDEX `message_uid_index` (`_mid` DESC)
|
||||
)
|
||||
ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci;
|
||||
Executable → Regular
+9
-33
@@ -5,7 +5,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
<artifactId>wildfirechat-parent</artifactId>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<version>0.22</version>
|
||||
<version>0.35</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>moquette-broker</artifactId>
|
||||
@@ -31,12 +31,6 @@
|
||||
<version>1.7.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<artifactId>client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.wildfirechat</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
@@ -110,34 +104,11 @@
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
<!--
|
||||
<!--
|
||||
<classifier>${os.detected.name}-${os.detected.arch}</classifier>
|
||||
-->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
<artifactId>metrics-core</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
<artifactId>metrics-jvm</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.librato.metrics</groupId>
|
||||
<artifactId>metrics-librato</artifactId>
|
||||
<version>5.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.bugsnag</groupId>
|
||||
<artifactId>bugsnag</artifactId>
|
||||
<version>[3.0,4.0)</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
@@ -170,7 +141,7 @@
|
||||
<dependency>
|
||||
<groupId>com.mchange</groupId>
|
||||
<artifactId>c3p0</artifactId>
|
||||
<version>[0.9.5.3,)</version>
|
||||
<version>0.9.5.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- needs extra dependencies: objenesis & hamcrest -->
|
||||
@@ -190,7 +161,7 @@
|
||||
<dependency>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -256,6 +227,11 @@
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ public class PushServer {
|
||||
}
|
||||
|
||||
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(() ->{
|
||||
try {
|
||||
pushMessageInternel(pushMessage, deviceId, pushContent);
|
||||
|
||||
@@ -22,6 +22,8 @@ import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
/**
|
||||
@@ -84,7 +86,7 @@ abstract public class Action {
|
||||
if (request instanceof FullHttpRequest) {
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
String content = new String(bytes);
|
||||
String content = new String(bytes, StandardCharsets.UTF_8);//contribute by JiaRG from github
|
||||
Gson gson = new Gson();
|
||||
T t = gson.fromJson(content, cls);
|
||||
return t;
|
||||
|
||||
@@ -35,12 +35,15 @@ import java.util.concurrent.Executor;
|
||||
@HttpMethod("POST")
|
||||
public class RouteAction extends Action {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RouteAction.class);
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
|
||||
response.setContentType("application/octet-stream");
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest) request.getNettyRequest();
|
||||
boolean b = false;
|
||||
if ("web".equalsIgnoreCase(fullHttpRequest.headers().get("p"))) {
|
||||
b = true;
|
||||
@@ -79,7 +82,7 @@ public class RouteAction extends Action {
|
||||
|
||||
MemorySessionStore.Session session = sessionsStore.sessionForClientAndUser(uid, cid);
|
||||
if (session == null) {
|
||||
ErrorCode errorCode = sessionsStore.createNewSession(uid, cid, true, true);
|
||||
ErrorCode errorCode = sessionsStore.loadActiveSession(uid, cid);
|
||||
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
sendResponse(response, errorCode, null, base64Response);
|
||||
return true;
|
||||
@@ -144,10 +147,14 @@ public class RouteAction extends Action {
|
||||
|
||||
private void sendResponse(Response response, ErrorCode errorCode, byte[] contents, boolean base64Response) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if(contents == null) {
|
||||
if (contents == null) {
|
||||
ByteBuf ackPayload = Unpooled.buffer();
|
||||
ackPayload.ensureWritable(1).writeByte(errorCode.getCode());
|
||||
response.setContent(ackPayload);
|
||||
contents = ackPayload.array();
|
||||
}
|
||||
if (base64Response) {
|
||||
byte[] base64Data = Base64.getEncoder().encode(contents);
|
||||
response.setContent(base64Data);
|
||||
} else {
|
||||
response.setContent(contents);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class BlockUserAction extends AdminAction {
|
||||
result = RestResult.resultOf(errorCode);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
|
||||
if (inputUserBlock.getStatus() != 0) {
|
||||
if (inputUserBlock.getStatus() == 2) {
|
||||
RPCCenter.getInstance().sendRequest(null, null, RPCCenter.KICKOFF_USER_REQUEST, inputUserBlock.getUserId().getBytes(), inputUserBlock.getUserId(), TargetEntry.Type.TARGET_TYPE_USER, null, true);
|
||||
}
|
||||
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
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.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.IMTopic;
|
||||
import win.liyufan.im.UUIDGenerator;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route(APIPath.Create_Channel)
|
||||
@HttpMethod("POST")
|
||||
public class CreateChannelAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputCreateChannel inputCreateChannel = getRequestBody(request.getNettyRequest(), InputCreateChannel.class);
|
||||
if (inputCreateChannel != null
|
||||
&& !StringUtil.isNullOrEmpty(inputCreateChannel.getName())) {
|
||||
|
||||
|
||||
if(StringUtil.isNullOrEmpty(inputCreateChannel.getTargetId())) {
|
||||
inputCreateChannel.setTargetId(messagesStore.getShortUUID());
|
||||
}
|
||||
|
||||
RPCCenter.getInstance().sendRequest(inputCreateChannel.getOwner(), null, IMTopic.CreateChannelTopic, inputCreateChannel.toProtoChannelInfo().toByteArray(), inputCreateChannel.getOwner(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
sendResponse(response, null, new OutputCreateChannel(inputCreateChannel.getTargetId()));
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
return false;
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.InputDestroyUser;
|
||||
import cn.wildfirechat.pojos.InputOutputUserInfo;
|
||||
import cn.wildfirechat.pojos.OutputCreateUser;
|
||||
import cn.wildfirechat.pojos.OutputGetIMTokenData;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
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.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.IMTopic;
|
||||
import win.liyufan.im.UUIDGenerator;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route(APIPath.Destroy_User)
|
||||
@HttpMethod("POST")
|
||||
public class DestroyUserAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputDestroyUser inputDestroyUser = getRequestBody(request.getNettyRequest(), InputDestroyUser.class);
|
||||
if (inputDestroyUser != null
|
||||
&& !StringUtil.isNullOrEmpty(inputDestroyUser.getUserId())) {
|
||||
|
||||
WFCMessage.IDBuf idBuf = WFCMessage.IDBuf.newBuilder().setId(inputDestroyUser.getUserId()).build();
|
||||
RPCCenter.getInstance().sendRequest(inputDestroyUser.getUserId(), null, IMTopic.DestroyUserTopic, idBuf.toByteArray(), inputDestroyUser.getUserId(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ErrorCode errorCode1 = ErrorCode.fromCode(result[0]);
|
||||
if (errorCode1 == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
//ba errorcode qudiao
|
||||
byte[] data = new byte[result.length -1];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = result[i+1];
|
||||
}
|
||||
String token = Base64.getEncoder().encodeToString(data);
|
||||
|
||||
sendResponse(response, null, null);
|
||||
} else {
|
||||
sendResponse(response, errorCode1, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
return false;
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -36,7 +36,7 @@ public class FriendRelationGetAction extends AdminAction {
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetFriendList inputGetFriendList = getRequestBody(request.getNettyRequest(), InputGetFriendList.class);
|
||||
List<FriendData> dataList = messagesStore.getFriendList(inputGetFriendList.getUserId(), 0);
|
||||
List<FriendData> dataList = messagesStore.getFriendList(inputGetFriendList.getUserId(), null, 0);
|
||||
List<String> list = new ArrayList<>();
|
||||
for (FriendData data : dataList) {
|
||||
if (data.getState() == inputGetFriendList.getStatus()) {
|
||||
|
||||
@@ -41,7 +41,7 @@ public class GetIMTokenAction extends AdminAction {
|
||||
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() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.InputGetUserInfo;
|
||||
import cn.wildfirechat.pojos.InputOutputUserInfo;
|
||||
import cn.wildfirechat.pojos.SystemSettingPojo;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
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.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
@Route(APIPath.Get_System_Setting)
|
||||
@HttpMethod("POST")
|
||||
public class GetSystemSettingAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
SystemSettingPojo inputUserId = getRequestBody(request.getNettyRequest(), SystemSettingPojo.class);
|
||||
if (inputUserId != null) {
|
||||
SystemSettingPojo output = messagesStore.getSystemSetting(inputUserId.id);
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result;
|
||||
if (output == null) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
result = RestResult.ok(output);
|
||||
}
|
||||
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.InputGetGroup;
|
||||
import cn.wildfirechat.pojos.InputUserId;
|
||||
import cn.wildfirechat.pojos.OutputGroupIds;
|
||||
import cn.wildfirechat.pojos.PojoGroupInfo;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
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.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
@Route(APIPath.Get_User_Groups)
|
||||
@HttpMethod("POST")
|
||||
public class GetUserGroupsAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputUserId inputUserId = getRequestBody(request.getNettyRequest(), InputUserId.class);
|
||||
if (inputUserId != null
|
||||
&& (!StringUtil.isNullOrEmpty(inputUserId.getUserId()))) {
|
||||
|
||||
Set<String> groupIds = messagesStore.getUserGroupIds(inputUserId.getUserId());
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
OutputGroupIds outputGroupIds = new OutputGroupIds();
|
||||
outputGroupIds.setGroupIds(new ArrayList<>(groupIds));
|
||||
RestResult result = RestResult.ok(outputGroupIds);
|
||||
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class KickoffGroupMemberAction extends AdminAction {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputKickoffGroupMember inputKickoffGroupMember = getRequestBody(request.getNettyRequest(), InputKickoffGroupMember.class);
|
||||
if (inputKickoffGroupMember.isValide()) {
|
||||
RPCCenter.getInstance().sendRequest(inputKickoffGroupMember.getOperator(), null, IMTopic.AddGroupMemberTopic, inputKickoffGroupMember.toProtoGroupRequest().toByteArray(), inputKickoffGroupMember.getOperator(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
RPCCenter.getInstance().sendRequest(inputKickoffGroupMember.getOperator(), null, IMTopic.KickoffGroupMemberTopic, inputKickoffGroupMember.toProtoGroupRequest().toByteArray(), inputKickoffGroupMember.getOperator(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.InputAddGroupMember;
|
||||
import cn.wildfirechat.pojos.InputModifyGroupInfo;
|
||||
import com.google.gson.Gson;
|
||||
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.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route(APIPath.Group_Modify_Info)
|
||||
@HttpMethod("POST")
|
||||
public class ModifyGroupInfoAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputModifyGroupInfo inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputModifyGroupInfo.class);
|
||||
if (inputAddGroupMember.isValide()) {
|
||||
RPCCenter.getInstance().sendRequest(inputAddGroupMember.getOperator(), null, IMTopic.ModifyGroupInfoTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), inputAddGroupMember.getOperator(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
sendResponse(response, null, null);
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
return false;
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.BroadMessageData;
|
||||
import cn.wildfirechat.pojos.BroadMessageResult;
|
||||
import cn.wildfirechat.pojos.MultiMessageResult;
|
||||
import cn.wildfirechat.pojos.MulticastMessageData;
|
||||
import com.google.gson.Gson;
|
||||
import com.hazelcast.util.StringUtil;
|
||||
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.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route(APIPath.Msg_Multicast)
|
||||
@HttpMethod("POST")
|
||||
public class MulticastMessageAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
MulticastMessageData sendMessageData = getRequestBody(request.getNettyRequest(), MulticastMessageData.class);
|
||||
if (MulticastMessageData.isValide(sendMessageData)) {
|
||||
RPCCenter.getInstance().sendRequest(sendMessageData.getSender(), null, IMTopic.MultiCastMessageTopic, sendMessageData.toProtoMessage().toByteArray(), sendMessageData.getSender(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
long messageId = byteBuf.readLong();
|
||||
long timestamp = byteBuf.readLong();
|
||||
sendResponse(response, null, new MultiMessageResult(messageId, timestamp));
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
return false;
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.InputGetUserInfo;
|
||||
import cn.wildfirechat.pojos.InputOutputUserInfo;
|
||||
import cn.wildfirechat.pojos.SystemSettingPojo;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
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.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
@Route(APIPath.Put_System_Setting)
|
||||
@HttpMethod("POST")
|
||||
public class PutSystemSettingAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
SystemSettingPojo inputUserId = getRequestBody(request.getNettyRequest(), SystemSettingPojo.class);
|
||||
if (inputUserId != null
|
||||
&& (!StringUtil.isNullOrEmpty(inputUserId.value) || !StringUtil.isNullOrEmpty(inputUserId.desc))) {
|
||||
|
||||
|
||||
boolean success = messagesStore.updateSystemSetting(inputUserId.id, inputUserId.value, inputUserId.desc);
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result;
|
||||
if (!success) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_SERVER_ERROR);
|
||||
} else {
|
||||
result = RestResult.ok();
|
||||
}
|
||||
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.InputAddGroupMember;
|
||||
import cn.wildfirechat.pojos.InputSetGroupManager;
|
||||
import com.google.gson.Gson;
|
||||
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.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route(APIPath.Group_Set_Manager)
|
||||
@HttpMethod("POST")
|
||||
public class SetGroupManagerAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputSetGroupManager inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputSetGroupManager.class);
|
||||
if (inputAddGroupMember.isValide()) {
|
||||
RPCCenter.getInstance().sendRequest(inputAddGroupMember.getOperator(), null, IMTopic.SetGroupManagerTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), inputAddGroupMember.getOperator(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
sendResponse(response, null, null);
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
return false;
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Action处理单元
|
||||
*
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||
@@ -45,7 +45,7 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
try {
|
||||
//do filter
|
||||
boolean isPass = this.doFilter(request, response);
|
||||
|
||||
|
||||
if(isPass){
|
||||
//do action
|
||||
this.doAction(ctx, request, response);
|
||||
@@ -64,10 +64,10 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
ctx.fireExceptionCaught(e);
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
@@ -75,7 +75,7 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
Channel channel = ctx.channel();
|
||||
if(channel.isActive())ctx.close();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------- Private method start
|
||||
/**
|
||||
* 执行过滤
|
||||
@@ -91,7 +91,7 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//自定义Path过滤器
|
||||
filter = ServerSetting.getFilter(request.getPath());
|
||||
if(null != filter){
|
||||
@@ -99,7 +99,7 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
* @param response 响应对象
|
||||
*/
|
||||
private void doAction(ChannelHandlerContext ctx, Request request, Response response){
|
||||
if( "/route".equalsIgnoreCase(request.getPath()) && "OPTIONS".equalsIgnoreCase(request.getMethod())){
|
||||
handleOptions(ctx, request, response);
|
||||
return;
|
||||
}
|
||||
Action action;
|
||||
if (isValidePath(request.getPath())) {
|
||||
action = ServerSetting.getAction(request.getPath(), request.getMethod().toUpperCase());
|
||||
@@ -141,4 +145,11 @@ abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
|
||||
private void handleOptions(ChannelHandlerContext ctx, Request request, Response response){
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||
response.send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,16 @@ public class FriendData implements Serializable {
|
||||
private String friendUid;
|
||||
private String alias;
|
||||
private int state;
|
||||
private int blacked;
|
||||
private long timestamp;
|
||||
|
||||
|
||||
public FriendData(String userId, String friendUid, String alias, int state, long timestamp) {
|
||||
public FriendData(String userId, String friendUid, String alias, int state, int blacked, long timestamp) {
|
||||
this.userId = userId;
|
||||
this.friendUid = friendUid;
|
||||
this.alias = alias;
|
||||
this.state = state;
|
||||
this.blacked = blacked;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@@ -61,6 +63,14 @@ public class FriendData implements Serializable {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public int getBlacked() {
|
||||
return blacked;
|
||||
}
|
||||
|
||||
public void setBlacked(int blacked) {
|
||||
this.blacked = blacked;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@@ -60,13 +60,6 @@ public final class BrokerConstants {
|
||||
public static final String NETTY_SO_KEEPALIVE_PROPERTY_NAME = "netty.so_keepalive";
|
||||
public static final String NETTY_CHANNEL_TIMEOUT_SECONDS_PROPERTY_NAME = "netty.channel_timeout.seconds";
|
||||
public static final String NETTY_EPOLL_PROPERTY_NAME = "netty.epoll";
|
||||
public static final String METRICS_ENABLE_PROPERTY_NAME = "use_metrics";
|
||||
public static final String METRICS_LIBRATO_EMAIL_PROPERTY_NAME = "metrics.librato.email";
|
||||
public static final String METRICS_LIBRATO_TOKEN_PROPERTY_NAME = "metrics.librato.token";
|
||||
public static final String METRICS_LIBRATO_SOURCE_PROPERTY_NAME = "metrics.librato.source";
|
||||
|
||||
public static final String BUGSNAG_ENABLE_PROPERTY_NAME = "use_bugsnag";
|
||||
public static final String BUGSNAG_TOKEN_PROPERTY_NAME = "bugsnag.token";
|
||||
|
||||
public static final String STORAGE_CLASS_NAME = "storage_class";
|
||||
|
||||
@@ -103,7 +96,7 @@ public final class BrokerConstants {
|
||||
public static final String HTTP_SERVER_API_NO_CHECK_TIME = "http.admin.no_check_time";
|
||||
|
||||
public static final String CLIENT_PROTO_SECRET_KEY = "client.proto.secret_key";
|
||||
public static final String TOKEN_SECRET_KEY = "token.key ";
|
||||
public static final String TOKEN_SECRET_KEY = "token.key";
|
||||
|
||||
public static final String EMBED_DB_PROPERTY_NAME = "embed.db";
|
||||
|
||||
@@ -113,6 +106,17 @@ public final class BrokerConstants {
|
||||
|
||||
public static final String MESSAGE_Forward_Url = "message.forward.url";
|
||||
|
||||
public static final String SERVER_MULTI_ENDPOINT = "server.multi_endpoint";
|
||||
|
||||
public static final String MONGODB_Client_URI = "mongodb.client_uri";
|
||||
public static final String MONGODB_Database = "mongodb.database";
|
||||
public static final String MONGODB_Data_Expire_Days = "mongodb.data_expire_days";
|
||||
|
||||
public static final String MESSAGE_ROAMING = "message.roaming";
|
||||
public static final String MESSAGE_Remote_History_Message = "message.remote_history_message";
|
||||
|
||||
public static final String MESSAGE_Max_Queue = "message.max_queue";
|
||||
|
||||
|
||||
|
||||
private BrokerConstants() {
|
||||
|
||||
@@ -22,7 +22,7 @@ public class AddGroupMember extends GroupHandler<WFCMessage.AddGroupMemberReques
|
||||
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.AddGroupMemberRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = m_messagesStore.addGroupMembers(fromUser, request.getGroupId(), request.getAddedMemberList());
|
||||
ErrorCode errorCode = m_messagesStore.addGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getAddedMemberList());
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());
|
||||
|
||||
@@ -14,10 +14,18 @@ import io.netty.buffer.ByteBuf;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
@Handler(IMTopic.DeleteFriendTopic)
|
||||
public class DeleteFriendHandler extends IMHandler<WFCMessage.IDBuf> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {
|
||||
return m_messagesStore.deleteFriend(fromUser, request.getId());
|
||||
long[] head = new long[2];
|
||||
ErrorCode errorCode = m_messagesStore.deleteFriend(fromUser, request.getId(), head);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, head[0]);
|
||||
publisher.publishNotification(IMTopic.NotifyFriendTopic, request.getId(), head[1]);
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.common.ErrorCode;
|
||||
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;
|
||||
|
||||
@Handler(IMTopic.DestroyUserTopic)
|
||||
public class DestroyUserHandler extends IMHandler<WFCMessage.IDBuf> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {
|
||||
if (isAdmin) {
|
||||
mServer.getImBusinessScheduler().execute(()-> {
|
||||
m_sessionsStore.clearUserSession(fromUser);
|
||||
m_messagesStore.clearUserMessages(fromUser);
|
||||
m_messagesStore.clearUserSettings(fromUser);
|
||||
m_messagesStore.clearUserFriend(fromUser);
|
||||
m_messagesStore.clearUserGroups(fromUser);
|
||||
m_messagesStore.clearUserChannels(fromUser);
|
||||
m_messagesStore.destoryUser(fromUser);
|
||||
});
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
} else {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
package io.moquette.imhandler;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.hazelcast.util.StringUtil;
|
||||
import com.xiaoleilu.loServer.model.FriendData;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -21,11 +22,15 @@ import java.util.List;
|
||||
public class FriendPullHandler extends IMHandler<WFCMessage.Version> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.Version request, Qos1PublishHandler.IMCallback callback) {
|
||||
List<FriendData> friendDatas = m_messagesStore.getFriendList(fromUser, request.getVersion());
|
||||
List<FriendData> friendDatas = m_messagesStore.getFriendList(fromUser, clientID, request.getVersion());
|
||||
WFCMessage.GetFriendsResult.Builder builder = WFCMessage.GetFriendsResult.newBuilder();
|
||||
for (FriendData data : friendDatas
|
||||
) {
|
||||
builder.addEntry(WFCMessage.Friend.newBuilder().setState(data.getState()).setUid(data.getFriendUid()).setUpdateDt(data.getTimestamp()).setAlias(data.getAlias()).build());
|
||||
WFCMessage.Friend.Builder builder1 = WFCMessage.Friend.newBuilder().setState(data.getState()).setBlacked(data.getBlacked()).setUid(data.getFriendUid()).setUpdateDt(data.getTimestamp());
|
||||
if (!StringUtil.isNullOrEmpty(data.getAlias())) {
|
||||
builder1.setAlias(data.getAlias());
|
||||
}
|
||||
builder.addEntry(builder1.build());
|
||||
}
|
||||
byte[] data = builder.build().toByteArray();
|
||||
ackPayload.ensureWritable(data.length).writeBytes(data);
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.common.ErrorCode;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.qiniu.util.Auth;
|
||||
import com.xiaoleilu.loServer.action.UploadFileAction;
|
||||
import io.moquette.server.config.MediaServerConfig;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@Handler("GMUT")
|
||||
public class GetMediaUploadTokenHandler extends IMHandler<WFCMessage.GetUploadTokenRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.GetUploadTokenRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
int type = request.getMediaType();
|
||||
|
||||
String token;
|
||||
|
||||
WFCMessage.GetUploadTokenResult.Builder resultBuilder = WFCMessage.GetUploadTokenResult.newBuilder();
|
||||
if (MediaServerConfig.USER_QINIU) {
|
||||
Auth auth = Auth.create(MediaServerConfig.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_SECRET_KEY);
|
||||
|
||||
|
||||
String bucketName;
|
||||
String bucketDomain;
|
||||
switch (type) {
|
||||
case 0:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;
|
||||
break;
|
||||
case 1:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_IMAGE_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_IMAGE_DOMAIN;
|
||||
break;
|
||||
case 2:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_VOICE_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_VOICE_DOMAIN;
|
||||
break;
|
||||
case 3:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_VIDEO_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_VIDEO_DOMAIN;
|
||||
break;
|
||||
case 4:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_FILE_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN;
|
||||
break;
|
||||
case 5:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN;
|
||||
break;
|
||||
case 6:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;
|
||||
break;
|
||||
default:
|
||||
bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;
|
||||
bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
byte[] data = resultBuilder.buildPartial().toByteArray();
|
||||
ackPayload.ensureWritable(data.length).writeBytes(data);
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import win.liyufan.im.IMTopic;
|
||||
public class GetTokenHandler extends IMHandler<WFCMessage.GetTokenRequest> {
|
||||
@Override
|
||||
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();
|
||||
String strToken = authenticator.generateToken(fromUser);
|
||||
String result = strToken + "|" + session.getSecret() + "|" + session.getDbSecret();
|
||||
|
||||
@@ -32,6 +32,8 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -81,11 +83,10 @@ abstract public class IMHandler<T> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Method method : getClass().getDeclaredMethods()
|
||||
) {
|
||||
|
||||
if (method.getName() == actionName && method.getParameterCount() == 6) {
|
||||
if (method.getName() == actionName && method.getParameterCount() == 6 && !method.getParameterTypes()[4].equals(Object.class)) {
|
||||
dataCls = method.getParameterTypes()[4];
|
||||
break;
|
||||
}
|
||||
@@ -233,13 +234,22 @@ abstract public class IMHandler<T> {
|
||||
public void afterAction(String clientID, String fromUser, String topic, Qos1PublishHandler.IMCallback callback) {
|
||||
|
||||
}
|
||||
protected long publish(String username, String clientID, WFCMessage.Message message) {
|
||||
Set<String> notifyReceivers = new LinkedHashSet<>();
|
||||
|
||||
WFCMessage.Message.Builder messageBuilder = message.toBuilder();
|
||||
int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers);
|
||||
mServer.getImBusinessScheduler().execute(() -> this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType));
|
||||
return notifyReceivers.size();
|
||||
}
|
||||
|
||||
protected long saveAndPublish(String username, String clientID, WFCMessage.Message message) {
|
||||
Set<String> notifyReceivers = new LinkedHashSet<>();
|
||||
|
||||
message = m_messagesStore.storeMessage(username, clientID, message);
|
||||
int pullType = m_messagesStore.getNotifyReceivers(username, message, notifyReceivers);
|
||||
this.publisher.publish2Receivers(message, notifyReceivers, clientID, pullType);
|
||||
WFCMessage.Message.Builder messageBuilder = message.toBuilder();
|
||||
int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers);
|
||||
mServer.getImBusinessScheduler().execute(() -> this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType));
|
||||
return notifyReceivers.size();
|
||||
}
|
||||
|
||||
@@ -249,4 +259,12 @@ abstract public class IMHandler<T> {
|
||||
mServer.getImBusinessScheduler().execute(() -> publisher.publish2Receivers(updatedMessage, notifyReceivers, clientID, ProtoConstants.PullType.Pull_Normal));
|
||||
return notifyReceivers.size();
|
||||
}
|
||||
|
||||
protected long saveAndMulticast(String username, String clientID, WFCMessage.Message message, Collection<String> targets) {
|
||||
Set<String> notifyReceivers = new HashSet<>();
|
||||
notifyReceivers.addAll(targets);
|
||||
WFCMessage.Message updatedMessage = m_messagesStore.storeMessage(username, clientID, message);
|
||||
mServer.getImBusinessScheduler().execute(() -> publisher.publish2Receivers(updatedMessage, notifyReceivers, clientID, ProtoConstants.PullType.Pull_Normal));
|
||||
return notifyReceivers.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,20 +24,38 @@ public class KickoffGroupMember extends GroupHandler<WFCMessage.RemoveGroupMembe
|
||||
WFCMessage.GroupInfo groupInfo = m_messagesStore.getGroupInfo(request.getGroupId());
|
||||
if (groupInfo == null) {
|
||||
errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
|
||||
} else if ((groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted)
|
||||
&& groupInfo.getOwner() != null && groupInfo.getOwner().equals(fromUser)) {
|
||||
|
||||
//send notify message first, then kickoff the member
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
|
||||
} else {
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, request.getRemovedMemberList()).getKickokfMemberGroupNotifyContent();
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
|
||||
}
|
||||
errorCode = m_messagesStore.kickoffGroupMembers(fromUser, request.getGroupId(), request.getRemovedMemberList());
|
||||
} else {
|
||||
errorCode = ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
boolean isAllow = isAdmin;
|
||||
if (!isAllow) {
|
||||
if (groupInfo.getOwner() != null) {
|
||||
if (request.getRemovedMemberList().contains(groupInfo.getOwner())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (groupInfo.getOwner() != null && groupInfo.getOwner().equals(fromUser)) {
|
||||
isAllow = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAllow) {
|
||||
WFCMessage.GroupMember gm = m_messagesStore.getGroupMember(request.getGroupId(), fromUser);
|
||||
if (gm != null && gm.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Manager) {
|
||||
isAllow = true;
|
||||
}
|
||||
}
|
||||
if (!isAllow && (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted)) {
|
||||
errorCode = ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
} else {
|
||||
//send notify message first, then kickoff the member
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
|
||||
} else {
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, request.getRemovedMemberList()).getKickokfMemberGroupNotifyContent();
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
|
||||
}
|
||||
errorCode = m_messagesStore.kickoffGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getRemovedMemberList());
|
||||
}
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
@@ -14,16 +14,15 @@ import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
|
||||
import static cn.wildfirechat.proto.ProtoConstants.ModifyGroupInfoType.Modify_Group_Name;
|
||||
import static cn.wildfirechat.proto.ProtoConstants.ModifyGroupInfoType.Modify_Group_Portrait;
|
||||
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
import static cn.wildfirechat.proto.ProtoConstants.ModifyGroupInfoType.*;
|
||||
import static win.liyufan.im.IMTopic.ModifyGroupInfoTopic;
|
||||
|
||||
@Handler(value = ModifyGroupInfoTopic)
|
||||
public class ModifyGroupInfoHandler extends GroupHandler<WFCMessage.ModifyGroupInfoRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.ModifyGroupInfoRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode= m_messagesStore.modifyGroupInfo(fromUser, request.getGroupId(), request.getType(), request.getValue());
|
||||
ErrorCode errorCode= m_messagesStore.modifyGroupInfo(fromUser, request.getGroupId(), request.getType(), request.getValue(), isAdmin);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());
|
||||
@@ -33,6 +32,14 @@ public class ModifyGroupInfoHandler extends GroupHandler<WFCMessage.ModifyGroupI
|
||||
content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), "").getChangeGroupNameNotifyContent();
|
||||
} else if(request.getType() == Modify_Group_Portrait) {
|
||||
content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, "").getChangeGroupPortraitNotifyContent();
|
||||
} else if(request.getType() == Modify_Group_Mute) {
|
||||
content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), "").getChangeGroupMuteNotifyContent();
|
||||
} else if(request.getType() == Modify_Group_JoinType) {
|
||||
content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), "").getChangeGroupJointypeNotifyContent();
|
||||
} else if(request.getType() == Modify_Group_PrivateChat) {
|
||||
content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), "").getChangeGroupPrivatechatNotifyContent();
|
||||
} else if(request.getType() == Modify_Group_Searchable) {
|
||||
content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), "").getChangeGroupSearchableNotifyContent();
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.common.ErrorCode;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.hazelcast.util.StringUtil;
|
||||
import io.moquette.BrokerConstants;
|
||||
import io.moquette.server.Server;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import win.liyufan.im.IMTopic;
|
||||
import win.liyufan.im.MessageShardingUtil;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.wildfirechat.proto.ProtoConstants.ContentType.Text;
|
||||
import static cn.wildfirechat.proto.ProtoConstants.ConversationType.ConversationType_Private;
|
||||
|
||||
@Handler(value = IMTopic.MultiCastMessageTopic)
|
||||
public class MultiCastMessageHandler extends IMHandler<WFCMessage.MultiCastMessage> {
|
||||
|
||||
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.MultiCastMessage multiCastMessage, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
if (!isAdmin) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
}
|
||||
|
||||
long timestamp = System.currentTimeMillis();
|
||||
long messageId = MessageShardingUtil.generateId();
|
||||
WFCMessage.Message message = WFCMessage.Message.newBuilder()
|
||||
.setContent(multiCastMessage.getContent())
|
||||
.setConversation(WFCMessage.Conversation.newBuilder().setTarget(fromUser).setType(ConversationType_Private).setLine(multiCastMessage.getLine()).build())
|
||||
.setFromUser(fromUser)
|
||||
.setMessageId(messageId)
|
||||
.setServerTimestamp(timestamp)
|
||||
.build();
|
||||
|
||||
saveAndMulticast(fromUser, clientID, message, multiCastMessage.getToList());
|
||||
|
||||
ackPayload = ackPayload.capacity(20);
|
||||
ackPayload.writeLong(messageId);
|
||||
ackPayload.writeLong(timestamp);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,19 +20,14 @@ import static win.liyufan.im.IMTopic.QuitGroupTopic;
|
||||
public class QuitGroupHandler extends GroupHandler<WFCMessage.QuitGroupRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.QuitGroupRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
WFCMessage.GroupInfo groupInfo = m_messagesStore.getGroupInfo(request.getGroupId());
|
||||
if (groupInfo == null) {
|
||||
errorCode = m_messagesStore.quitGroup(fromUser, request.getGroupId());
|
||||
} else {
|
||||
//send notify message first, then quit group
|
||||
ErrorCode errorCode = m_messagesStore.quitGroup(fromUser, request.getGroupId());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());
|
||||
} else {
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, "").getQuitGroupNotifyContent();
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
|
||||
}
|
||||
errorCode = m_messagesStore.quitGroup(fromUser, request.getGroupId());
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Set;
|
||||
public class RecallMessageHandler extends IMHandler<WFCMessage.INT64Buf> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.INT64Buf int64Buf, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = m_messagesStore.recallMessage(int64Buf.getId(), fromUser);
|
||||
ErrorCode errorCode = m_messagesStore.recallMessage(int64Buf.getId(), fromUser, isAdmin);
|
||||
|
||||
if(errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
return errorCode;
|
||||
@@ -33,7 +33,11 @@ public class RecallMessageHandler extends IMHandler<WFCMessage.INT64Buf> {
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
|
||||
m_messagesStore.getNotifyReceivers(fromUser, message, notifyReceivers);
|
||||
publish(fromUser, clientID, message);
|
||||
|
||||
|
||||
//等待客户端实现根据撤回消息更新内容,之后可以删掉这段代码
|
||||
m_messagesStore.getNotifyReceivers(fromUser, message.toBuilder(), notifyReceivers);
|
||||
this.publisher.publishRecall2Receivers(int64Buf.getId(), fromUser, notifyReceivers, clientID);
|
||||
|
||||
return errorCode;
|
||||
|
||||
@@ -32,7 +32,7 @@ public class RouteHandler extends IMHandler<WFCMessage.RouteRequest> {
|
||||
ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);
|
||||
boolean isSessionAlreadyStored = clientSession != null;
|
||||
if (!isSessionAlreadyStored) {
|
||||
m_sessionsStore.createNewSession(fromUser, clientID, true, true);
|
||||
m_sessionsStore.loadActiveSession(fromUser, clientID);
|
||||
} else {
|
||||
m_sessionsStore.updateExistSession(fromUser, clientID, request, true);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
if (message != null) {
|
||||
if (!isAdmin) { //admin do not check the right
|
||||
// 不能在端上直接发送撤回和群通知
|
||||
if (message.getContent().getType() == 80 || (message.getContent().getType() >= 100 && message.getContent().getType() < 200)) {
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
int userStatus = m_messagesStore.getUserStatus(fromUser);
|
||||
if (userStatus == 1 || userStatus == 2) {
|
||||
return ErrorCode.ERROR_CODE_FORBIDDEN_SEND_MSG;
|
||||
@@ -58,14 +62,19 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
}
|
||||
|
||||
|
||||
if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group && !m_messagesStore.isMemberInGroup(fromUser, message.getConversation().getTarget())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_GROUP;
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group && m_messagesStore.isForbiddenInGroup(fromUser, message.getConversation().getTarget())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_RIGHT;
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom && !m_messagesStore.checkUserClientInChatroom(fromUser, clientID, message.getConversation().getTarget())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_CHATROOM;
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel && !m_messagesStore.checkUserInChannel(fromUser, message.getConversation().getTarget())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_CHANNEL;
|
||||
if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group ) {
|
||||
errorCode = m_messagesStore.canSendMessageInGroup(fromUser, message.getConversation().getTarget());
|
||||
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
return errorCode;
|
||||
}
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom) {
|
||||
if(!m_messagesStore.checkUserClientInChatroom(fromUser, clientID, message.getConversation().getTarget())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_CHATROOM;
|
||||
}
|
||||
} else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {
|
||||
if(!m_messagesStore.checkUserInChannel(fromUser, message.getConversation().getTarget())) {
|
||||
return ErrorCode.ERROR_CODE_NOT_IN_CHANNEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,17 +90,20 @@ public class SendMessageHandler extends IMHandler<WFCMessage.Message> {
|
||||
if (!isAdmin && message.getContent().getType() == Text) {
|
||||
Set<String> matched = m_messagesStore.handleSensitiveWord(message.getContent().getSearchableContent());
|
||||
if (matched != null && !matched.isEmpty()) {
|
||||
m_messagesStore.storeSensitiveMessage(message);
|
||||
if (mSensitiveType == 0) {
|
||||
errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;
|
||||
} else if(mSensitiveType == 1) {
|
||||
ignoreMsg = true;
|
||||
} else {
|
||||
} else if(mSensitiveType == 2) {
|
||||
String text = message.getContent().getSearchableContent();
|
||||
for (String word : matched) {
|
||||
text = text.replace(word, "***");
|
||||
}
|
||||
|
||||
message = message.toBuilder().setContent(message.getContent().toBuilder().setSearchableContent(text).build()).build();
|
||||
} else if(mSensitiveType == 3) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.common.ErrorCode;
|
||||
import cn.wildfirechat.pojos.GroupNotificationBinaryContent;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.moquette.spi.impl.Qos1PublishHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
@Handler(IMTopic.SetGroupManagerTopic)
|
||||
public class SetGroupManagerHandler extends GroupHandler<WFCMessage.SetGroupManagerRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.SetGroupManagerRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
ErrorCode errorCode = m_messagesStore.setGroupManager(fromUser, request.getGroupId(), request.getType(), request.getUserIdList(), isAdmin);
|
||||
if (errorCode == ERROR_CODE_SUCCESS) {
|
||||
if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());
|
||||
} else {
|
||||
WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getType() + "", request.getUserIdList()).getSetGroupManagerNotifyContent();
|
||||
sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);
|
||||
}
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
@@ -26,12 +26,12 @@ public class UploadDeviceTokenHandler extends IMHandler<WFCMessage.UploadDeviceT
|
||||
session.setAppName(request.getAppName());
|
||||
if (request.getPlatform() == ProtoConstants.Platform.Platform_iOS && request.getPushType() == 2) {
|
||||
session.setVoipDeviceToken(request.getDeviceToken());
|
||||
session.setPushType(0);//如果有voip token,肯定是生产环境的推送
|
||||
m_sessionsStore.updateSessionToken(session, true);
|
||||
} else {
|
||||
session.setDeviceToken(request.getDeviceToken());
|
||||
session.setPushType(request.getPushType());
|
||||
m_sessionsStore.updateSessionToken(session, false);
|
||||
m_sessionsStore.cleanDuplatedToken(session.getClientID(), session.getPushType(), session.getDeviceToken(), false);
|
||||
}
|
||||
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.List;
|
||||
public class UserSearchHandler extends IMHandler<WFCMessage.SearchUserRequest> {
|
||||
@Override
|
||||
public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, boolean isAdmin, WFCMessage.SearchUserRequest request, Qos1PublishHandler.IMCallback callback) {
|
||||
List<WFCMessage.User> users = m_messagesStore.searchUser(request.getKeyword(), request.getFuzzy() > 0, request.getPage());
|
||||
List<WFCMessage.User> users = m_messagesStore.searchUser(request.getKeyword(), request.getFuzzy(), request.getPage());
|
||||
WFCMessage.SearchUserResult.Builder builder = WFCMessage.SearchUserResult.newBuilder();
|
||||
builder.addAllEntry(users);
|
||||
byte[] data = builder.build().toByteArray();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -16,17 +16,19 @@
|
||||
|
||||
package io.moquette.persistence;
|
||||
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.hazelcast.util.StringUtil;
|
||||
import io.moquette.BrokerConstants;
|
||||
import io.moquette.server.Constants;
|
||||
import io.moquette.server.Server;
|
||||
import io.moquette.spi.ClientSession;
|
||||
import io.moquette.spi.IMessagesStore.StoredMessage;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
|
||||
import io.moquette.spi.IMessagesStore.StoredMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttVersion;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
@@ -35,6 +37,8 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
private static int dumy = 1;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MemorySessionStore.class);
|
||||
|
||||
private boolean supportMultiEndpoint = false;
|
||||
|
||||
public static class Session implements Comparable<Session>{
|
||||
final String clientID;
|
||||
String username;
|
||||
@@ -50,6 +54,16 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
|
||||
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;
|
||||
|
||||
public long getLastActiveTime() {
|
||||
@@ -130,6 +144,9 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
|
||||
public void setUpdateDt(long updateDt) {
|
||||
this.updateDt = updateDt;
|
||||
if (this.lastActiveTime == 0) {
|
||||
this.lastActiveTime = updateDt;
|
||||
}
|
||||
}
|
||||
|
||||
private int pushType;
|
||||
@@ -248,8 +265,14 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
private final Server mServer;
|
||||
private final DatabaseStore databaseStore;
|
||||
public MemorySessionStore(Server server, DatabaseStore databaseStore) {
|
||||
mServer = server;
|
||||
this.databaseStore = databaseStore;
|
||||
mServer = server;
|
||||
this.databaseStore = databaseStore;
|
||||
|
||||
try {
|
||||
supportMultiEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_ENDPOINT));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -261,6 +284,21 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
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
|
||||
public void initStore() {
|
||||
}
|
||||
@@ -272,18 +310,82 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
|
||||
@Override
|
||||
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
|
||||
public Session createUserSession(String username, String clientID) {
|
||||
public void clearUserSession(String username) {
|
||||
LOG.info("Fooooooooo <{}>", username);
|
||||
|
||||
databaseStore.clearUserSessions(username);
|
||||
|
||||
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
|
||||
for (String clientID : sessionSet) {
|
||||
Session s = sessions.remove(clientID);
|
||||
mServer.getProcessor().kickoffSession(s);
|
||||
}
|
||||
userSessions.remove(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session createUserSession(String username, String clientID, int platform) {
|
||||
LOG.debug("createUserSession for client <{}>, user <{}>", clientID, username);
|
||||
|
||||
ClientSession clientSession = new ClientSession(clientID, this);
|
||||
Session session = databaseStore.getSession(username, clientID, clientSession);
|
||||
|
||||
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);
|
||||
if (s == null) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -291,34 +393,29 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
|
||||
|
||||
@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);
|
||||
|
||||
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);
|
||||
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);
|
||||
session = databaseStore.getSession(username, clientID, clientSession);
|
||||
|
||||
if (session == null) {
|
||||
if (!createWhenNoExist) {
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
|
||||
session = databaseStore.createSession(username, clientID, clientSession);
|
||||
if (session == null || session.getDeleted() > 0) {
|
||||
return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;
|
||||
}
|
||||
|
||||
sessions.put(clientID, session);
|
||||
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username);
|
||||
if (sessionSet == null) {
|
||||
sessionSet = new ConcurrentSkipListSet<>();
|
||||
userSessions.put(username, sessionSet);
|
||||
}
|
||||
sessionSet = userSessions.get(username);
|
||||
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
|
||||
sessionSet.add(clientID);
|
||||
|
||||
return ErrorCode.ERROR_CODE_SUCCESS;
|
||||
@@ -342,12 +439,7 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
session.setUsername(username);
|
||||
sessions.put(clientID, session);
|
||||
|
||||
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username);
|
||||
if (sessionSet == null) {
|
||||
sessionSet = new ConcurrentSkipListSet<>();
|
||||
userSessions.put(username, sessionSet);
|
||||
}
|
||||
sessionSet = userSessions.get(username);
|
||||
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
|
||||
sessionSet.add(clientID);
|
||||
|
||||
if (endpoint != null) {
|
||||
@@ -393,14 +485,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
|
||||
public Collection<Session> sessionForUser(String username) {
|
||||
ConcurrentSkipListSet<String> sessionSet = userSessions.get(username);
|
||||
if (sessionSet == null) {
|
||||
sessionSet = new ConcurrentSkipListSet<String>();
|
||||
userSessions.put(username, sessionSet);
|
||||
}
|
||||
sessionSet = userSessions.get(username);
|
||||
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);
|
||||
|
||||
ArrayList<Session> out = new ArrayList<>();
|
||||
for (String clientId : sessionSet
|
||||
) {
|
||||
@@ -466,7 +570,9 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
|
||||
@Override
|
||||
public void dropQueue(String clientID) {
|
||||
sessions.get(clientID).queue.clear();
|
||||
if (sessions.get(clientID) != null) {
|
||||
sessions.get(clientID).queue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -542,12 +648,7 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
LOG.error("Can't find the session for client <{}>", clientID);
|
||||
return;
|
||||
}
|
||||
ConcurrentSkipListSet<String> sessionSet = userSessions.get(session.username);
|
||||
if (sessionSet == null) {
|
||||
sessionSet = new ConcurrentSkipListSet<>();
|
||||
userSessions.put(session.username, sessionSet);
|
||||
}
|
||||
sessionSet = userSessions.get(session.username);
|
||||
ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);
|
||||
sessionSet.remove(clientID);
|
||||
|
||||
// remove also the messages stored of type QoS1/2
|
||||
|
||||
@@ -27,7 +27,7 @@ public class UserStatusLoader implements MapStore<String, Integer> {
|
||||
|
||||
@Override
|
||||
public void delete(String s) {
|
||||
getDatabaseStore().deleteUser(s);
|
||||
getDatabaseStore().deleteUserStatus(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,8 +24,10 @@ public final class Constants {
|
||||
public static final String ATTR_CLIENTID = "ClientID";
|
||||
public static final String CLEAN_SESSION = "cleanSession";
|
||||
public static final String KEEP_ALIVE = "keepAlive";
|
||||
public static final int MAX_MESSAGE_QUEUE = 1024; // number of messages
|
||||
public static final int MAX_CHATROOM_MESSAGE_QUEUE = 256; // number of chatroom messages
|
||||
|
||||
|
||||
public static int MAX_MESSAGE_QUEUE = 1024; // number of messages
|
||||
public static int MAX_CHATROOM_MESSAGE_QUEUE = 256; // number of chatroom messages
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
@@ -406,6 +406,7 @@ public class Server {
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
System.out.println("Server will flush data to db before shutting down, please wait 5 seconds!");
|
||||
LOG.info("Unbinding server from the configured ports");
|
||||
m_acceptor.close();
|
||||
LOG.trace("Stopping MQTT protocol processor");
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package io.moquette.server.netty;
|
||||
|
||||
import com.bugsnag.Bugsnag;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import static io.moquette.BrokerConstants.BUGSNAG_TOKEN_PROPERTY_NAME;
|
||||
|
||||
@Sharable
|
||||
public class BugSnagErrorsHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private Bugsnag bugsnag;
|
||||
|
||||
public void init(IConfig props) {
|
||||
final String token = props.getProperty(BUGSNAG_TOKEN_PROPERTY_NAME);
|
||||
this.bugsnag = new Bugsnag(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
bugsnag.notify(cause);
|
||||
ctx.fireExceptionCaught(cause);
|
||||
}
|
||||
}
|
||||
@@ -139,25 +139,11 @@ public class NettyAcceptor implements ServerAcceptor {
|
||||
|
||||
final NettyMQTTHandler mqttHandler = new NettyMQTTHandler(processor);
|
||||
|
||||
final boolean useFineMetrics = Boolean.parseBoolean(props.getProperty(METRICS_ENABLE_PROPERTY_NAME, "false"));
|
||||
if (useFineMetrics) {
|
||||
DropWizardMetricsHandler metricsHandler = new DropWizardMetricsHandler();
|
||||
metricsHandler.init(props);
|
||||
this.metrics = Optional.of(metricsHandler);
|
||||
} else {
|
||||
this.metrics = Optional.empty();
|
||||
}
|
||||
this.metrics = Optional.empty();
|
||||
|
||||
this.errorsCather = Optional.empty();
|
||||
|
||||
final boolean useBugSnag = Boolean.parseBoolean(props.getProperty(BUGSNAG_ENABLE_PROPERTY_NAME, "false"));
|
||||
if (useBugSnag) {
|
||||
BugSnagErrorsHandler bugSnagHandler = new BugSnagErrorsHandler();
|
||||
bugSnagHandler.init(props);
|
||||
this.errorsCather = Optional.of(bugSnagHandler);
|
||||
} else {
|
||||
this.errorsCather = Optional.empty();
|
||||
}
|
||||
initializePlainTCPTransport(mqttHandler, props);
|
||||
initializeWebSocketTransport(mqttHandler, props);
|
||||
String sslTcpPortProp = props.getProperty(BrokerConstants.SSL_PORT_PROPERTY_NAME);
|
||||
String wssPortProp = props.getProperty(BrokerConstants.WSS_PORT_PROPERTY_NAME);
|
||||
if (sslTcpPortProp != null || wssPortProp != null) {
|
||||
@@ -239,42 +225,6 @@ public class NettyAcceptor implements ServerAcceptor {
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeWebSocketTransport(final NettyMQTTHandler handler, IConfig props) throws IOException {
|
||||
LOG.info("Configuring Websocket MQTT transport");
|
||||
String webSocketPortProp = props.getProperty(WEB_SOCKET_PORT_PROPERTY_NAME, DISABLED_PORT_BIND);
|
||||
if (DISABLED_PORT_BIND.equals(webSocketPortProp)) {
|
||||
// Do nothing no WebSocket configured
|
||||
LOG.info("Property {} has been setted to {}. Websocket MQTT will be disabled",
|
||||
BrokerConstants.WEB_SOCKET_PORT_PROPERTY_NAME, DISABLED_PORT_BIND);
|
||||
return;
|
||||
}
|
||||
int port = Integer.parseInt(webSocketPortProp);
|
||||
|
||||
final MoquetteIdleTimeoutHandler timeoutHandler = new MoquetteIdleTimeoutHandler();
|
||||
|
||||
String host = props.getProperty(BrokerConstants.HOST_PROPERTY_NAME);
|
||||
initFactory(host, port, "Websocket MQTT", new PipelineInitializer() {
|
||||
|
||||
@Override
|
||||
void init(ChannelPipeline pipeline) {
|
||||
pipeline.addLast(new HttpServerCodec());
|
||||
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
|
||||
pipeline.addLast("webSocketHandler",
|
||||
new WebSocketServerProtocolHandler("/org/fusesource/mqtt", MQTT_SUBPROTOCOL_CSV_LIST));
|
||||
pipeline.addLast("ws2bytebufDecoder", new WebSocketFrameToByteBufDecoder());
|
||||
pipeline.addLast("bytebuf2wsEncoder", new ByteBufToWebSocketFrameEncoder());
|
||||
pipeline.addFirst("idleStateHandler", new IdleStateHandler(nettyChannelTimeoutSeconds, 0, 0));
|
||||
pipeline.addAfter("idleStateHandler", "idleEventHandler", timeoutHandler);
|
||||
pipeline.addFirst("bytemetrics", new BytesMetricsHandler(m_bytesMetricsCollector));
|
||||
pipeline.addLast("decoder", new MqttDecoder());
|
||||
pipeline.addLast("encoder", MqttEncoder.INSTANCE);
|
||||
pipeline.addLast("metrics", new MessageMetricsHandler(m_metricsCollector));
|
||||
pipeline.addLast("messageLogger", new MQTTMessageLogger());
|
||||
pipeline.addLast("handler", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeSSLTCPTransport(final NettyMQTTHandler handler, IConfig props, final SSLContext sslContext)
|
||||
throws IOException {
|
||||
LOG.info("Configuring SSL MQTT transport");
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
@@ -23,10 +24,15 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.moquette.server.netty.NettyUtils.ATTR_USERNAME;
|
||||
|
||||
public class BytesMetricsHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BytesMetricsHandler.class);
|
||||
private static final AttributeKey<BytesMetrics> ATTR_KEY_METRICS = AttributeKey.valueOf("BytesMetrics");
|
||||
private static final AttributeKey<String> ATTR_KEY_USERNAME = AttributeKey.valueOf(ATTR_USERNAME);
|
||||
|
||||
private BytesMetricsCollector m_collector;
|
||||
|
||||
@@ -59,6 +65,12 @@ public class BytesMetricsHandler extends ChannelDuplexHandler {
|
||||
@Override
|
||||
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
|
||||
BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
String userId = ctx.channel().attr(ATTR_KEY_USERNAME).get();
|
||||
if (userId == null) {
|
||||
userId = "";
|
||||
}
|
||||
|
||||
LOG.info("channel<{}> closing after read {} bytes and wrote {} bytes", userId, metrics.readBytes(), metrics.wroteBytes());
|
||||
m_collector.sumReadBytes(metrics.readBytes());
|
||||
m_collector.sumWroteBytes(metrics.wroteBytes());
|
||||
super.close(ctx, promise);
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2017 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package io.moquette.server.netty.metrics;
|
||||
|
||||
import com.codahale.metrics.Counter;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.librato.metrics.reporter.Librato;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.mqtt.MqttMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttMessageType;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.moquette.BrokerConstants.*;
|
||||
import static io.netty.channel.ChannelHandler.Sharable;
|
||||
|
||||
/**
|
||||
* Pipeline handler use to track some MQTT metrics.
|
||||
*/
|
||||
@Sharable
|
||||
public final class DropWizardMetricsHandler extends ChannelInboundHandlerAdapter {
|
||||
private MetricRegistry metrics;
|
||||
private Meter publishesMetrics;
|
||||
private Meter subscribeMetrics;
|
||||
private Counter connectedClientsMetrics;
|
||||
|
||||
public void init(IConfig props) {
|
||||
this.metrics = new MetricRegistry();
|
||||
this.publishesMetrics = metrics.meter("publish.requests");
|
||||
this.subscribeMetrics = metrics.meter("subscribe.requests");
|
||||
this.connectedClientsMetrics = metrics.counter("connect.num_clients");
|
||||
// ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
|
||||
// .convertRatesTo(TimeUnit.SECONDS)
|
||||
// .convertDurationsTo(TimeUnit.MILLISECONDS)
|
||||
// .build();
|
||||
// reporter.start(1, TimeUnit.MINUTES);
|
||||
final String email = props.getProperty(METRICS_LIBRATO_EMAIL_PROPERTY_NAME);
|
||||
final String token = props.getProperty(METRICS_LIBRATO_TOKEN_PROPERTY_NAME);
|
||||
final String source = props.getProperty(METRICS_LIBRATO_SOURCE_PROPERTY_NAME);
|
||||
|
||||
Librato.reporter(this.metrics, email, token)
|
||||
.setSource(source)
|
||||
.start(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object message) {
|
||||
MqttMessage msg = (MqttMessage) message;
|
||||
MqttMessageType messageType = msg.fixedHeader().messageType();
|
||||
switch (messageType) {
|
||||
case PUBLISH:
|
||||
this.publishesMetrics.mark();
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
this.subscribeMetrics.mark();
|
||||
break;
|
||||
case CONNECT:
|
||||
this.connectedClientsMetrics.inc();
|
||||
break;
|
||||
case DISCONNECT:
|
||||
this.connectedClientsMetrics.dec();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ctx.fireChannelRead(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
String clientID = NettyUtils.clientID(ctx.channel());
|
||||
if (clientID != null && !clientID.isEmpty()) {
|
||||
this.connectedClientsMetrics.dec();
|
||||
}
|
||||
ctx.fireChannelInactive();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,10 +22,16 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.moquette.server.netty.NettyUtils.ATTR_USERNAME;
|
||||
|
||||
public class MessageMetricsHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MessageMetricsHandler.class);
|
||||
private static final AttributeKey<MessageMetrics> ATTR_KEY_METRICS = AttributeKey.valueOf("MessageMetrics");
|
||||
private static final AttributeKey<String> ATTR_KEY_USERNAME = AttributeKey.valueOf(ATTR_USERNAME);
|
||||
|
||||
|
||||
private MessageMetricsCollector m_collector;
|
||||
|
||||
@@ -58,6 +64,12 @@ public class MessageMetricsHandler extends ChannelDuplexHandler {
|
||||
@Override
|
||||
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
|
||||
MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();
|
||||
String userId = ctx.channel().attr(ATTR_KEY_USERNAME).get();
|
||||
if (userId == null) {
|
||||
userId = "";
|
||||
}
|
||||
|
||||
LOG.info("channel<{}> closing after read {} messages and wrote {} messages", userId, metrics.messagesRead(), metrics.messagesWrote());
|
||||
m_collector.sumReadMessages(metrics.messagesRead());
|
||||
m_collector.sumWroteMessages(metrics.messagesWrote());
|
||||
super.close(ctx, promise);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package io.moquette.spi;
|
||||
|
||||
import cn.wildfirechat.pojos.SystemSettingPojo;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.xiaoleilu.loServer.model.FriendData;
|
||||
import cn.wildfirechat.pojos.InputOutputUserBlockStatus;
|
||||
@@ -96,26 +97,33 @@ public interface IMessagesStore {
|
||||
|
||||
DatabaseStore getDatabaseStore();
|
||||
WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message);
|
||||
int getNotifyReceivers(String fromUser, WFCMessage.Message message, Set<String> notifyReceivers);
|
||||
void storeSensitiveMessage(WFCMessage.Message message);
|
||||
int getNotifyReceivers(String fromUser, WFCMessage.Message.Builder message, Set<String> notifyReceivers);
|
||||
Set<String> getAllEnds();
|
||||
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);
|
||||
ErrorCode kickoffGroupMembers(String operator, String groupId, List<String> memberList);
|
||||
ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList);
|
||||
ErrorCode kickoffGroupMembers(String operator, boolean isAdmin, String groupId, List<String> memberList);
|
||||
ErrorCode quitGroup(String operator, String groupId);
|
||||
void clearUserGroups(String userId);
|
||||
ErrorCode dismissGroup(String operator, String groupId, boolean isAdmin);
|
||||
ErrorCode modifyGroupInfo(String operator, String groupId, int modifyType, String value);
|
||||
ErrorCode modifyGroupInfo(String operator, String groupId, int modifyType, String value, boolean isAdmin);
|
||||
ErrorCode modifyGroupAlias(String operator, String groupId, String alias);
|
||||
List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests);
|
||||
WFCMessage.GroupInfo getGroupInfo(String groupId);
|
||||
Set<String> getUserGroupIds(String userId);
|
||||
ErrorCode getGroupMembers(String groupId, long maxDt, List<WFCMessage.GroupMember> members);
|
||||
WFCMessage.GroupMember getGroupMember(String groupId, String memberId);
|
||||
ErrorCode transferGroup(String operator, String groupId, String newOwner, boolean isAdmin);
|
||||
ErrorCode setGroupManager(String operator, String groupId, int type, List<String> userList, boolean isAdmin);
|
||||
boolean isMemberInGroup(String member, String groupId);
|
||||
boolean isForbiddenInGroup(String member, String groupId);
|
||||
ErrorCode canSendMessageInGroup(String member, String groupId);
|
||||
|
||||
ErrorCode recallMessage(long messageUid, String operatorId);
|
||||
ErrorCode recallMessage(long messageUid, String operatorId, boolean isAdmin);
|
||||
|
||||
void clearUserMessages(String userId);
|
||||
|
||||
WFCMessage.Robot getRobot(String robotId);
|
||||
void addRobot(WFCMessage.Robot robot);
|
||||
@@ -127,11 +135,14 @@ public interface IMessagesStore {
|
||||
List<InputOutputUserBlockStatus> getUserStatusList();
|
||||
|
||||
void addUserInfo(WFCMessage.User user, String password);
|
||||
void destoryUser(String userId);
|
||||
WFCMessage.User getUserInfo(String userId);
|
||||
WFCMessage.User getUserInfoByName(String name);
|
||||
WFCMessage.User getUserInfoByMobile(String mobile);
|
||||
List<WFCMessage.User> searchUser(String keyword, boolean buzzy, int page);
|
||||
List<WFCMessage.User> searchUser(String keyword, int searchType, int page);
|
||||
|
||||
boolean updateSystemSetting(int id, String value, String desc);
|
||||
SystemSettingPojo getSystemSetting(int id);
|
||||
void createChatroom(String chatroomId, WFCMessage.ChatroomInfo chatroomInfo);
|
||||
void destoryChatroom(String chatroomId);
|
||||
WFCMessage.ChatroomInfo getChatroomInfo(String chatroomId);
|
||||
@@ -147,12 +158,13 @@ public interface IMessagesStore {
|
||||
ErrorCode verifyToken(String userId, String token, List<String> serverIPs, List<Integer> ports);
|
||||
ErrorCode login(String name, String password, List<String> userIdRet);
|
||||
|
||||
List<FriendData> getFriendList(String userId, long version);
|
||||
List<FriendData> getFriendList(String userId, String clientId, long version);
|
||||
void clearUserFriend(String userId);
|
||||
List<WFCMessage.FriendRequest> getFriendRequestList(String userId, long version);
|
||||
|
||||
ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head);
|
||||
ErrorCode handleFriendRequest(String userId, WFCMessage.HandleFriendRequest request, WFCMessage.Message.Builder msgBuilder, long[] heads, boolean isAdmin);
|
||||
ErrorCode deleteFriend(String userId, String friendUid);
|
||||
ErrorCode deleteFriend(String userId, String friendUid, long[] head);
|
||||
ErrorCode blackUserRequest(String fromUser, String targetUserId, int status, long[] head);
|
||||
ErrorCode SyncFriendRequestUnread(String userId, long unreadDt, long[] head);
|
||||
boolean isBlacked(String fromUser, String userId);
|
||||
@@ -165,12 +177,14 @@ public interface IMessagesStore {
|
||||
WFCMessage.UserSettingEntry getUserSetting(String userId, int scope, String key);
|
||||
List<WFCMessage.UserSettingEntry> getUserSetting(String userId, int scope);
|
||||
long updateUserSettings(String userId, WFCMessage.ModifyUserSettingReq request);
|
||||
void clearUserSettings(String userId);
|
||||
|
||||
boolean getUserGlobalSlient(String userId);
|
||||
boolean getUserPushHiddenDetail(String userId);
|
||||
boolean getUserConversationSlient(String userId, WFCMessage.Conversation conversation);
|
||||
|
||||
ErrorCode createChannel(String operator, WFCMessage.ChannelInfo channelInfo);
|
||||
void clearUserChannels(String userId);
|
||||
ErrorCode modifyChannelInfo(String operator, String channelId, int modifyType, String value);
|
||||
ErrorCode transferChannel(String operator, String channelId, String newOwner);
|
||||
ErrorCode distoryChannel(String operator, String channelId);
|
||||
|
||||
@@ -38,15 +38,19 @@ public interface ISessionsStore {
|
||||
*/
|
||||
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);
|
||||
|
||||
Session getSession(String clientID);
|
||||
|
||||
void cleanDuplatedToken(String cid, int pushType, String token, boolean isVoip);
|
||||
|
||||
void updateSessionToken(Session session, boolean voip);
|
||||
|
||||
void clearUserSession(String username);
|
||||
/**
|
||||
* @param clientID
|
||||
* the client owning the session.
|
||||
|
||||
@@ -308,7 +308,7 @@ public class MessagesPublisher {
|
||||
}
|
||||
|
||||
if (isSlient) {
|
||||
LOG.info("The conversation is slient");
|
||||
LOG.info("Slient of user or conversation");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package io.moquette.spi.impl;
|
||||
|
||||
import cn.wildfirechat.common.ErrorCode;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.interception.InterceptHandler;
|
||||
@@ -55,7 +56,24 @@ import static io.moquette.server.ConnectionDescriptor.ConnectionState.*;
|
||||
*
|
||||
* Used by the front facing class ProtocolProcessorBootstrapper.
|
||||
*/
|
||||
|
||||
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) {
|
||||
System.out.println("kickof user " + target);
|
||||
if (target.type == TargetEntry.Type.TARGET_TYPE_USER) {
|
||||
@@ -142,9 +160,8 @@ public class ProtocolProcessor {
|
||||
String clientId = payload.clientIdentifier();
|
||||
LOG.info("Processing CONNECT message. CId={}, username={}", clientId, payload.userName());
|
||||
|
||||
if (msg.variableHeader().version() != MqttVersion.MQTT_3_1.protocolLevel()
|
||||
&& msg.variableHeader().version() != MqttVersion.MQTT_3_1_1.protocolLevel()
|
||||
&& msg.variableHeader().version() != MqttVersion.Wildfire_1.protocolLevel()) {
|
||||
if (msg.variableHeader().version() < MqttVersion.MQTT_3_1_1.protocolLevel() ||
|
||||
msg.variableHeader().version() >= MqttVersion.Wildfire_Max.protocolLevel()) {
|
||||
MqttConnAckMessage badProto = connAck(CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION);
|
||||
|
||||
LOG.error("MQTT protocol version is not valid. CId={}", clientId);
|
||||
@@ -165,7 +182,11 @@ public class ProtocolProcessor {
|
||||
|
||||
MqttVersion mqttVersion = MqttVersion.fromProtocolLevel(msg.variableHeader().version());
|
||||
if (!login(channel, msg, clientId, mqttVersion)) {
|
||||
MqttConnAckMessage badId = connAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD);
|
||||
|
||||
channel.writeAndFlush(badId);
|
||||
channel.close();
|
||||
LOG.error("The MQTT login failure. Username={}", payload.userName());
|
||||
return;
|
||||
}
|
||||
if (!mServer.m_initialized) {
|
||||
@@ -254,9 +275,16 @@ public class ProtocolProcessor {
|
||||
|
||||
MemorySessionStore.Session session = m_sessionsStore.getSession(clientId);
|
||||
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);
|
||||
}
|
||||
|
||||
if (session.getDeleted() != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (session != null && session.getUsername().equals(msg.payload().userName())) {
|
||||
pwd = AES.AESDecrypt(pwd, session.getSecret(), true);
|
||||
@@ -502,15 +530,12 @@ public class ProtocolProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean stillPresent = this.connectionDescriptors.removeConnection(existingDescriptor);
|
||||
if (!stillPresent) {
|
||||
// another descriptor was inserted
|
||||
LOG.warn("Another descriptor has been inserted. CId={}", clientID);
|
||||
return;
|
||||
}
|
||||
this.connectionDescriptors.removeConnection(existingDescriptor);
|
||||
|
||||
LOG.info("The DISCONNECT message has been processed. CId={}", clientID);
|
||||
|
||||
channel.closeFuture();
|
||||
|
||||
//disconnect the session
|
||||
m_sessionsStore.sessionForClient(clientID).disconnect(clearSession);
|
||||
}
|
||||
@@ -623,7 +648,8 @@ public class ProtocolProcessor {
|
||||
|
||||
public void onRpcMsg(String fromUser, String clientId, byte[] message, int messageId, String from, String request, boolean isAdmin) {
|
||||
if(request.equals(RPCCenter.KICKOFF_USER_REQUEST)) {
|
||||
mServer.getImBusinessScheduler().execute(()->handleTargetRemovedFromCurrentNode(new TargetEntry(TargetEntry.Type.TARGET_TYPE_USER, from)));
|
||||
String userId = new String(message);
|
||||
mServer.getImBusinessScheduler().execute(()->handleTargetRemovedFromCurrentNode(new TargetEntry(TargetEntry.Type.TARGET_TYPE_USER, userId)));
|
||||
return;
|
||||
}
|
||||
qos1PublishHandler.onRpcMsg(fromUser, clientId, message, messageId, from, request, isAdmin);
|
||||
|
||||
@@ -178,7 +178,7 @@ public class Qos1PublishHandler extends QosPublishHandler {
|
||||
} else {
|
||||
MemorySessionStore.Session session = m_sessionStore.getSession(clientID);
|
||||
if (session != null && session.getUsername().equals(fromUser)) {
|
||||
if (data.length > 7*1024 && session.getMqttVersion() == MqttVersion.Wildfire_1) {
|
||||
if (data.length > 7*1024 && session.getMqttVersion().protocolLevel() >= MqttVersion.Wildfire_1.protocolLevel()) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzip;
|
||||
try {
|
||||
|
||||
@@ -43,7 +43,7 @@ final class MqttCodecUtil {
|
||||
return clientId != null && clientId.length() >= MIN_CLIENT_ID_LENGTH &&
|
||||
clientId.length() <= MAX_CLIENT_ID_LENGTH;
|
||||
}
|
||||
if (mqttVersion == MqttVersion.MQTT_3_1_1 || mqttVersion == MqttVersion.Wildfire_1) {
|
||||
if (mqttVersion.protocolLevel() >= MqttVersion.MQTT_3_1_1.protocolLevel()) {
|
||||
// In 3.1.3.1 Client Identifier of MQTT 3.1.1 specification, The Server MAY allow ClientId’s
|
||||
// that contain more than 23 encoded bytes. And, The Server MAY allow zero-length ClientId.
|
||||
return clientId != null;
|
||||
|
||||
@@ -223,7 +223,7 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
|
||||
final int willQos = (b1 & 0x18) >> 3;
|
||||
final boolean willFlag = (b1 & 0x04) == 0x04;
|
||||
final boolean cleanSession = (b1 & 0x02) == 0x02;
|
||||
if (mqttVersion == MqttVersion.MQTT_3_1_1 || mqttVersion == MqttVersion.Wildfire_1) {
|
||||
if (mqttVersion.protocolLevel() >= MqttVersion.MQTT_3_1_1.protocolLevel()) {
|
||||
final boolean zeroReservedFlag = (b1 & 0x01) == 0x0;
|
||||
if (!zeroReservedFlag) {
|
||||
// MQTT v3.1.1: The Server MUST validate that the reserved flag in the CONNECT Control Packet is
|
||||
|
||||
@@ -25,7 +25,9 @@ import io.netty.util.internal.ObjectUtil;
|
||||
public enum MqttVersion {
|
||||
MQTT_3_1("MQIsdp", (byte) 3),
|
||||
MQTT_3_1_1("MQTT", (byte) 4),
|
||||
Wildfire_1("MQTT", (byte) 5);
|
||||
Wildfire_1("MQTT", (byte) 5),
|
||||
Wildfire_2("MQTT", (byte) 6),
|
||||
Wildfire_Max("MQTT", (byte) 7);
|
||||
|
||||
private final String name;
|
||||
private final byte level;
|
||||
|
||||
@@ -52,7 +52,14 @@ public class HttpUtils {
|
||||
|
||||
@Override
|
||||
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());
|
||||
try {
|
||||
if (response.body() != null) {
|
||||
response.body().close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class IDUtils {
|
||||
return ch - 'a' + 26;
|
||||
} else if(ch >= '0' && ch <= '9') {
|
||||
return ch - '0' + 52;
|
||||
} else if(ch == '_') {
|
||||
} else if(ch == '+') {
|
||||
return 62;
|
||||
}
|
||||
return 63;
|
||||
|
||||
@@ -10,6 +10,7 @@ package win.liyufan.im;
|
||||
|
||||
public interface IMTopic {
|
||||
String SendMessageTopic = "MS";
|
||||
String MultiCastMessageTopic = "MMC";
|
||||
String RecallMessageTopic = "MR";
|
||||
String PullMessageTopic = "MP";
|
||||
String NotifyMessageTopic = "MN";
|
||||
@@ -30,7 +31,7 @@ public interface IMTopic {
|
||||
String GetGroupInfoTopic = "GPGI";
|
||||
String GetGroupMemberTopic = "GPGM";
|
||||
String TransferGroupTopic = "GTG";
|
||||
|
||||
String SetGroupManagerTopic = "GSM";
|
||||
|
||||
String GetUserInfoTopic = "UPUI";
|
||||
String ModifyMyInfoTopic = "MMI";
|
||||
@@ -70,6 +71,7 @@ public interface IMTopic {
|
||||
String ChannelPullTopic = "CHP";
|
||||
|
||||
String GetTokenTopic = "GETTOKEN";
|
||||
String DestroyUserTopic = "DESTROYUSER";
|
||||
|
||||
String LoadRemoteMessagesTopic = "LRM";
|
||||
}
|
||||
|
||||
@@ -54,10 +54,15 @@ public class MessageShardingUtil {
|
||||
return "t_messages";
|
||||
}
|
||||
|
||||
mid >>= (nodeIdWidth + rotateIdWidth);
|
||||
Date date = new Date(mid + T201801010000);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
if (mid != Long.MAX_VALUE) {
|
||||
mid >>= (nodeIdWidth + rotateIdWidth);
|
||||
Date date = new Date(mid + T201801010000);
|
||||
calendar.setTime(date);
|
||||
} else {
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
calendar.setTime(date);
|
||||
}
|
||||
int month = calendar.get(Calendar.MONTH);
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
year %= 3;
|
||||
|
||||
@@ -58,6 +58,7 @@ public class SensitiveFilter {
|
||||
return sensitiveWords;
|
||||
}
|
||||
|
||||
text = text.toLowerCase();
|
||||
for(int i=0;i<text.length();i++){
|
||||
int sensitiveWordLength = getSensitiveWordLength(text, i, matchType);
|
||||
if(sensitiveWordLength>0){
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?xml version ="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- # 本配置文件为debug使用,修改这里不会在Release包中生效。Release中包含的配置文件在 ${Porject_Path}/distribution/src/main/resources目录下-->
|
||||
|
||||
<c3p0-config>
|
||||
<!-- This is default config! -->
|
||||
<default-config>
|
||||
@@ -15,7 +18,7 @@
|
||||
<!--MySQL数据库驱动程序-->
|
||||
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
|
||||
<!--MySQL数据库地址-->
|
||||
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8</property>
|
||||
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8</property>
|
||||
<!--MySQL数据库用户名-->
|
||||
<property name="user">root</property>
|
||||
<!--MySQL数据库密码-->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user