Compare commits

...
91 Commits
Author SHA1 Message Date
heavyrain.lee 70bdebd4a0 update version to 0.27 2019-09-24 08:26:35 +08:00
heavyrain.lee 409078801e update 2019-09-24 08:23:25 +08:00
heavyrain2012 06fed7de52 update version to 0.26 2019-09-13 23:12:05 +08:00
heavyrain2012 da2428a9f9 modify windows bash error 2019-09-13 23:09:29 +08:00
heavyrain.lee 83b6ae5229 修改pc等平台pushtype越界问题 2019-09-07 14:50:34 +08:00
heavyrain.lee 4b7804cdfd update 2019-09-02 21:54:03 +08:00
heavyrain.lee d075b5212f 修改用户信息和频道信息时,改成同步修改 2019-09-01 22:16:49 +08:00
heavyrain.lee 636c8ce219 管理员撤回消息 2019-08-30 22:17:17 +08:00
heavyrain.lee 091d7fa3ec 解决乱码问题 2019-08-24 17:56:29 +08:00
heavyrain.lee 59356e5b52 获取敏感词列表按照逆序排列 2019-08-23 11:38:42 +08:00
heavyrain.lee 882bf29e63 1,更新群主时更新群成员信息中的群主状态
2,在敏感词列表中添加id列
2019-08-23 08:39:29 +08:00
heavyrain.lee f3eef4dd6b 添加修改群组信息接口 2019-08-17 10:30:39 +08:00
heavyrain.lee 898983c6e5 rm useless code 2019-08-10 22:14:46 +08:00
heavyrain.lee dae5d032fa 添加拉取历史消息开关。设置默认消息漫游和拉取都为关闭,这样无法删除问题就不会再出现 2019-08-09 13:44:44 +08:00
heavyrain.lee ff76622796 1, 修改撤回逻辑 2019-08-09 09:00:14 +08:00
heavyrain.lee a6fd11a243 修复部分接口 2019-08-08 08:28:00 +08:00
heavyrain2012 cf983be44c Update README.md 2019-08-07 23:48:59 +08:00
heavyrain.lee 1a72de0e85 修改群组反复添加删除群成员的问题 2019-08-06 22:55:52 +08:00
heavyrain.lee bf70a1e80e 退出群组时,删掉群相关用户设置 2019-08-06 22:55:41 +08:00
heavyrain.lee 512d797d4d Revert "jdbc character set to utf8mb4"
This reverts commit 608184ef9e.
2019-08-03 22:27:29 +08:00
heavyrain.lee 4a46dd1dde 添加组播消息 2019-08-03 20:43:27 +08:00
heavyrain lee 7494cdc071 update 2019-08-02 13:24:30 +08:00
heavyrain.lee 608184ef9e jdbc character set to utf8mb4 2019-08-02 13:16:15 +08:00
heavyrain2012 eb4d8a9b68 Update README.md 2019-07-30 18:22:03 +08:00
heavyrain.lee 6b92ae383c add weixin qrcode 2019-07-30 18:20:27 +08:00
heavyrain.lee 5fee857c4a add system settings 2019-07-30 07:54:49 +08:00
heavyrain2012 53b7139c30 Update README.md 2019-07-29 15:37:27 +08:00
imndx 83e864d667 update readme 2019-07-28 19:15:26 +08:00
imndx b88297e6de update readme 2019-07-26 22:52:39 +08:00
heavyrain lee 4aa2f46011 添加默认敏感词 2019-07-23 08:26:16 +08:00
heavyrain lee 1fb3c757e2 撤回消息时,先删除旧消息,再插入新消息 2019-07-21 22:29:24 +08:00
heavyrain lee 3f640b6c14 sync with commercial 2019-07-21 15:11:24 +08:00
heavyrain lee 49eb57af00 update version to 0.25 2019-07-21 13:09:07 +08:00
heavyrain lee 6bd6a80e71 添加是否接收历史消息的开关 2019-07-21 12:20:26 +08:00
heavyrain lee 38b84f0fa5 解决封禁用户无法踢用户下线的问题 2019-07-21 12:18:38 +08:00
heavyrain lee 1f46debd0c Fix test case error 2019-07-21 11:44:54 +08:00
heavyrain.lee 37998e76d1 添加漫游开关 2019-07-19 20:52:25 +08:00
heavyrain.lee 80b5508533 添加消息漫游开关 2019-07-19 20:51:52 +08:00
heavyrain lee a646cc8227 去掉启动时预读数据,加快启动速度 2019-07-17 00:36:17 +08:00
heavyrain lee 92692adf52 解决群组成员反复添加删除错误问题 2019-07-17 00:31:21 +08:00
heavyrain lee b2cfc2b99b add metrics for user channel 2019-07-16 21:56:51 +08:00
heavyrain lee 86e08f6151 Remove useless code 2019-07-16 21:32:55 +08:00
heavyrain lee 8d852eb2d1 退出群组时,删掉收藏的群组 2019-07-15 22:36:19 +08:00
heavyrain lee 8bef018911 转让群主后更新群组信息时间戳 2019-07-13 18:50:23 +08:00
heavyrain lee 5e13419c28 修改群管理逻辑错误 2019-07-13 18:31:08 +08:00
heavyrain.lee 503a7ae18f 取消管理员 2019-07-12 09:17:11 +08:00
heavyrain.lee dfb9638a38 update version to 0.24 2019-07-11 23:22:03 +08:00
heavyrain.lee 8452b0675b java10 not support this parameter 2019-07-11 23:21:48 +08:00
heavyrain.lee 930643706a 数据库message表中时间加8 2019-07-11 21:56:31 +08:00
heavyrain.lee a2eac1f721 update 2019-07-11 17:56:23 +08:00
heavyrain.lee 6e994cd694 update 2019-07-11 17:41:32 +08:00
heavyrain.lee c82869c631 群主可以在群禁言时发信息 2019-07-10 15:08:10 +08:00
heavyrain.lee f5a94868c4 remove useless code 2019-07-10 07:30:53 +08:00
heavyrain.lee c5628d613b 发送消息时,不能发送特殊类型的消息 2019-07-09 23:22:52 +08:00
heavyrain.lee 9509b1ffa8 敏感词大小写的问题 2019-07-09 23:22:52 +08:00
heavyrain2012 c1dac8a21e Update README.md 2019-07-09 14:07:31 +08:00
heavyrain.lee 950846df45 update 2019-07-09 08:50:14 +08:00
heavyrain.lee 31d96e2dc6 update 2019-07-09 08:08:04 +08:00
heavyrain.lee 031e96075e 群组权限 2019-07-08 23:08:04 +08:00
heavyrain.lee bf2caeac6c update 2019-07-06 16:56:08 +08:00
heavyrain.lee 12e523b37e 好友同步问题 2019-07-05 17:38:08 +08:00
heavyrain lee 576c985d8f 聊天室历史数据问题 2019-07-05 08:47:44 +08:00
heavyrain lee 9365807f47 群组踢人错误修改 2019-07-05 08:19:29 +08:00
heavyrain lee 25ce10fa61 删除好友通知 2019-07-04 10:19:07 +08:00
heavyrain lee 09c333501f Update 2019-07-04 08:54:34 +08:00
heavyrain.lee c51b09ee3a 修改用户关系逻辑错误问题 2019-07-04 08:23:55 +08:00
imndx 4d82eace86 quit group, then send notification 2019-07-04 07:07:36 +08:00
heavyrain.lee 385b03a163 add session table 2019-07-03 08:04:07 +08:00
heavyrain.lee 4b438afa69 fix issue 2019-06-30 10:31:12 +08:00
imndx 66961b94da route接口允许跨域访问 2019-06-29 16:42:55 +08:00
heavyrain lee 39b62e5942 Update to version 0.23 2019-06-29 12:20:58 +08:00
heavyrain.lee 5bb8ab3d95 update 2019-06-29 12:01:46 +08:00
heavyrain.lee 8dfc23b61d update code 2019-06-29 12:01:37 +08:00
heavyrain lee c8769808b5 Update proto 2019-06-29 12:01:11 +08:00
imndx 2fc106aa26 web route时,返回数据base64编码 2019-06-28 17:27:37 +08:00
imndx da0b725ff8 解决内存中好友备注错误 2019-06-24 22:04:05 +08:00
heavyrain.lee 15703d66fb 封禁用户问题修改 2019-06-23 18:30:58 +08:00
heavyrain.lee c68beeaa51 解决java客户端收消息的问题 2019-06-20 15:24:32 +08:00
heavyrain.lee 5ef8868916 接受新消息通知错误 2019-06-19 14:18:09 +08:00
heavyrain lee 24488cc985 Add group manage info 2019-06-18 08:26:29 +08:00
heavyrain.lee 1c9faaa1e6 apns推送在dev环境下也有voip证书,因此去掉voip一定是pro的假设 2019-06-16 20:25:33 +08:00
heavyrain.lee ac32875b14 fix migration error 2019-06-16 19:57:46 +08:00
heavyrain.lee 07c1dd29e0 alter table of token 2019-06-14 20:04:21 +08:00
imndx bd93233c34 update device token length 2019-06-14 18:43:50 +08:00
heavyrain.lee 20aec2fbcf 添加默认管理员 2019-06-12 23:21:21 +08:00
heavyrain.lee a149139143 添加敏感词命中消息表t_sensitive_messages 2019-06-12 22:57:30 +08:00
heavyrain.lee c857d1abb7 消息表中添加contenttype 2019-06-12 22:36:08 +08:00
heavyrain lee dde9da7006 用户表和群组表添加create_time字段 2019-06-12 21:48:57 +08:00
heavyrain2012 d18a1970e5 update script 2019-06-11 22:46:06 +08:00
heavyrain.lee 66b9aeec17 包名错误 2019-06-11 14:45:58 +08:00
heavyrain.lee ea301a3923 修改内部接口定义 2019-06-09 07:37:33 +08:00
1014 changed files with 9849 additions and 436899 deletions
+2
View File
@@ -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
+15 -5
View File
@@ -1,6 +1,6 @@
## 野火IM解决方案
野火IM是一套跨平台、全开源的即时通讯解决方案,主要包含以下内容。
野火IM是一套跨平台、核心功能开源的即时通讯解决方案,主要包含以下内容。
| 仓库 | 说明 | 备注 |
| ------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------- |
@@ -20,11 +20,21 @@
开发一套IM系统真的很艰辛,请路过的朋友们给点个star,支持我们坚持下去🙏🙏🙏🙏🙏
### 联系我们
问题讨论请加群:822762829
微信公众号:
> 商务合作请优先采用邮箱和我们联系。技术问题请到[野火IM论坛](http://bbs.wildfirechat.cn/)发帖交流
1. heavyrain.lee 邮箱: heavyrain.lee@wildfirechat.cn 微信:wildfirechat
2. imndx 邮箱: imndx@wildfirechat.cn 微信:wfchat
### 问题交流
1. 微信交流群(请先加我们好友,我们再邀请您进群)
![微信二维码](http://static.wildfirechat.cn/wx_qr_wildfirechat.jpeg) ![微信二维码](http://static.wildfirechat.cn/wx_qr_wfc.jpeg)
2. 如果大家发现bug,请在GitHub提issue
3. 其他问题,请到[野火IM论坛](http://bbs.wildfirechat.cn/)进行交流学习
4. 微信公众号
<img src="http://static.wildfirechat.cn/wx_wfc_qrcode.jpg" width = 50% height = 50% />
@@ -65,7 +75,7 @@
| 捐赠者 | 商标 | 金额 | 简介 |
| ----- | ---- | -------- | --- |
| [SAMOS](http://samos.io) | ![SAMOS](http://static.wildfirechat.cn/SAMOS.png) | 每月2000¥ | 一站式区块链解决方案服务商(http://samos.io) |
| [SAMOS](http://samos.io) | ![SAMOS](http://static.wildfirechat.cn/SAMOS.png) | 保密 | 一站式区块链解决方案服务商(http://samos.io) |
## 特别感谢
1. [moquette](https://github.com/moquette-io/moquette) 本项目是基于此项目二次开发而来,处理MQTT相关业务。
+19 -3
View File
@@ -26,8 +26,8 @@ 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
@@ -42,6 +42,12 @@ 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
#*********************************************************************
# hazelcase configuration
#*********************************************************************
@@ -95,10 +101,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
View File
@@ -0,0 +1,3 @@
insert into t_user (`_uid`,`_name`,`_display_name`,`_type`,`_dt`) values ('admin','admin','系统管理员',3,1);
+1
View File
@@ -0,0 +1 @@
ALTER TABLE t_user_session MODIFY _token VARCHAR(240) DEFAULT NULL;
+4
View File
@@ -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
View File
@@ -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', '最大群成员数量');
+1
View File
@@ -0,0 +1 @@
alter table `t_sensitiveword` add column `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT;
@@ -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;
+1
View File
@@ -0,0 +1 @@
alter table `t_messages` add column `_content_type` int(11) NOT NULL DEFAULT '0';
+15
View File
@@ -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
View File
@@ -0,0 +1,3 @@
insert into t_user (`_uid`,`_name`,`_display_name`,`_type`,`_dt`) values ('admin','admin','系统管理员',3,1);
+1
View File
@@ -0,0 +1 @@
ALTER TABLE t_user_session MODIFY _token VARCHAR(240) DEFAULT NULL;
+4
View File
@@ -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
View File
@@ -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();
+4
View File
@@ -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
View File
@@ -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);
File diff suppressed because it is too large Load Diff
+13
View File
@@ -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", "最大群成员数量");
+1
View File
@@ -0,0 +1 @@
alter table `t_sensitiveword` add column `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT;
@@ -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;
+36
View File
@@ -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
View File
@@ -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;
+8 -26
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.22</version>
<version>0.27</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -110,34 +110,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 +147,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 -->
@@ -256,6 +233,11 @@
<version>5.2.4</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
@@ -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;
@@ -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);
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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,12 @@ public final class BrokerConstants {
public static final String MESSAGE_Forward_Url = "message.forward.url";
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.reomte_history_message";
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;
}
}
@@ -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;
@@ -25,7 +26,11 @@ public class FriendPullHandler extends IMHandler<WFCMessage.Version> {
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()).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;
}
}
@@ -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;
@@ -233,13 +235,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);
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);
this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType);
return notifyReceivers.size();
}
@@ -249,4 +260,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;
@@ -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,7 +26,7 @@ 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,肯定是生产环境的推送
// session.setPushType(0);//如果有voip token,肯定是生产环境的推送
m_sessionsStore.updateSessionToken(session, true);
} else {
session.setDeviceToken(request.getDeviceToken());
@@ -8,6 +8,7 @@
package io.moquette.persistence;
import cn.wildfirechat.pojos.SystemSettingPojo;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import cn.wildfirechat.server.ThreadPoolExecutorWrapper;
@@ -76,6 +77,79 @@ public class DatabaseStore {
return out;
}
boolean updateSystemSetting(int id, String value, String desc) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "insert into t_settings " +
" (`id`, `value`, `desc`) values(?, ?, ?)" +
" ON DUPLICATE KEY UPDATE " +
"`value` = ?," +
"`desc` = ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setLong(index++, id);
statement.setString(index++, value);
statement.setString(index++, desc);
statement.setString(index++, value);
statement.setString(index++, desc);
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
return true;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
return false;
}
SystemSettingPojo getSystemSetting(int id) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = DBUtil.getConnection();
String sql = "select `value`, `desc` from t_settings where `id` = ?";
statement = connection.prepareStatement(sql);
int index = 1;
statement.setLong(index++, id);
rs = statement.executeQuery();
while (rs.next()) {
SystemSettingPojo out = new SystemSettingPojo();
index = 1;
out.id = id;
String value = rs.getString(index++);
value = (value == null ? "" : value);
out.value = value;
value = rs.getString(index++);
value = (value == null ? "" : value);
out.desc = value;
return out;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return null;
}
List<WFCMessage.User> searchUserFromDB(String keyword, boolean buzzy, int page) {
Connection connection = null;
PreparedStatement statement = null;
@@ -210,23 +284,27 @@ public class DatabaseStore {
return 0;
}
void reloadGroupMemberFromDB(HazelcastInstance hzInstance) {
synchronized Collection<WFCMessage.GroupMember> reloadGroupMemberFromDB(HazelcastInstance hzInstance, String groupId) {
MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(MemoryMessagesStore.GROUP_MEMBERS);
if (groupMembers.get(groupId).size() > 0) {
return groupMembers.get(groupId);
}
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = DBUtil.getConnection();
String sql = "select `_gid`" +
", `_mid`" +
String sql = "select `_mid`" +
", `_alias`" +
", `_type`" +
", `_dt` from t_group_member";
", `_dt` from t_group_member where _gid = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, groupId);
int index;
rs = statement.executeQuery();
while (rs.next()) {
WFCMessage.GroupMember.Builder builder = WFCMessage.GroupMember.newBuilder();
@@ -234,10 +312,6 @@ public class DatabaseStore {
String value = rs.getString(index++);
value = (value == null ? "" : value);
String groupId = value;
value = rs.getString(index++);
value = (value == null ? "" : value);
builder.setMemberId(value);
value = rs.getString(index++);
@@ -254,6 +328,7 @@ public class DatabaseStore {
WFCMessage.GroupMember member = builder.build();
groupMembers.put(groupId, member);
}
return groupMembers.get(groupId);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -261,6 +336,7 @@ public class DatabaseStore {
} finally {
DBUtil.closeDB(connection, statement, rs);
}
return new ArrayList<>();
}
void reloadFriendsFromDB(HazelcastInstance hzInstance) {
@@ -384,11 +460,12 @@ public class DatabaseStore {
try {
connection = DBUtil.getConnection();
String sql = "insert into " + MessageShardingUtil.getMessageTable(message.getMessageId()) +
" (`_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_searchable_key`, `_dt`) values(?, ?, ?, ?, ?, ?, ?, ?)" +
" (`_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_searchable_key`, `_dt`, `_content_type`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)" +
" ON DUPLICATE KEY UPDATE " +
"`_data` = ?," +
"`_searchable_key` = ?," +
"`_dt` = ?";
"`_dt` = ?," +
"`_content_type` = ?";
String searchableContent = message.getContent().getSearchableContent() == null ? "" : message.getContent().getSearchableContent();
@@ -404,10 +481,63 @@ public class DatabaseStore {
statement.setBlob(index++, blob);
statement.setString(index++, searchableContent);
statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));
statement.setInt(index++, message.getContent().getType());
statement.setBlob(index++, blob);
statement.setString(index++, searchableContent);
statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));
statement.setInt(index++, message.getContent().getType());
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
void persistSensitiveMessage(final WFCMessage.Message message) {
if(message.getContent().getPersistFlag() == Transparent) {
return;
}
mScheduler.execute(()-> {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "insert into " + "t_sensitive_messages" +
" (`_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_searchable_key`, `_dt`, `_content_type`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)" +
" ON DUPLICATE KEY UPDATE " +
"`_data` = ?," +
"`_searchable_key` = ?," +
"`_dt` = ?," +
"`_content_type` = ?";
String searchableContent = message.getContent().getSearchableContent() == null ? "" : message.getContent().getSearchableContent();
statement = connection.prepareStatement(sql);
int index = 1;
statement.setLong(index++, message.getMessageId());
statement.setString(index++, message.getFromUser());
statement.setInt(index++, message.getConversation().getType());
statement.setString(index++, message.getConversation().getTarget());
statement.setInt(index++, message.getConversation().getLine());
Blob blob = connection.createBlob();
blob.setBytes(1, message.getContent().toByteArray());
statement.setBlob(index++, blob);
statement.setString(index++, searchableContent);
statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));
statement.setInt(index++, message.getContent().getType());
statement.setBlob(index++, blob);
statement.setString(index++, searchableContent);
statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));
statement.setInt(index++, message.getContent().getType());
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
@@ -538,6 +668,25 @@ public class DatabaseStore {
return null;
}
void deleteMessage(long messageId) {
String sql = "delete from " + MessageShardingUtil.getMessageTable(messageId) + " where _mid = ?";
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
statement = connection.prepareStatement(sql);
statement.setLong(1, messageId);
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
}
List<WFCMessage.Message> loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count) {
List<WFCMessage.Message> messages = loadRemoteMessagesFromTable(user, conversation, beforeUid, count, MessageShardingUtil.getMessageTable(beforeUid));
if (messages != null && messages.size() < count) {
@@ -634,6 +783,43 @@ public class DatabaseStore {
});
}
void removeFavGroup(final String groupId, final List<String> memberIds) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
StringBuilder sb = new StringBuilder("update t_user_setting set _value = ?, _dt = ? where _uid in (");
for (int i = 0; i < memberIds.size(); i++) {
sb.append("?");
if (i != memberIds.size() - 1) {
sb.append(",");
}
}
sb.append(")");
sb.append(" and _scope = 6 and _key = ?");
statement = connection.prepareStatement(sb.toString());
int index = 1;
statement.setString(index++, "0");
statement.setLong(index++, System.currentTimeMillis());
for (int i = 0; i < memberIds.size(); i++) {
statement.setString(index++, memberIds.get(i));
}
statement.setString(index++, groupId);
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
}
void persistUserSetting(final String userId, WFCMessage.UserSettingEntry entry) {
mScheduler.execute(()->{
Connection connection = null;
@@ -725,6 +911,41 @@ public class DatabaseStore {
}
void removeGroupUserSettings(String groupId, List<String> users) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
StringBuilder sb = new StringBuilder("delete from t_user_setting where _scope in (1,3,5,7) and _uid in (");
for (int i = 0; i < users.size(); i++) {
sb.append("?");
if (i != users.size() - 1) {
sb.append(",");
}
}
sb.append(") and _key like '1-_-");
sb.append(groupId);
sb.append("'");
statement = connection.prepareStatement(sb.toString());
int index = 1;
for (String userId:users) {
statement.setString(index++, userId);
}
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
}
void persistGroupInfo(final WFCMessage.GroupInfo groupInfo) {
mScheduler.execute(()->{
Connection connection = null;
@@ -739,7 +960,11 @@ public class DatabaseStore {
", `_extra`" +
", `_dt`" +
", `_member_count`" +
", `_member_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)" +
", `_mute`" +
", `_join_type`" +
", `_private_chat`" +
", `_searchable`" +
", `_member_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" +
" ON DUPLICATE KEY UPDATE " +
"`_name` = ?," +
"`_portrait` = ?," +
@@ -748,6 +973,10 @@ public class DatabaseStore {
"`_extra` = ?," +
"`_dt` = ?," +
"`_member_count` = ?," +
"`_mute` = ?" +
", `_join_type` = ?" +
", `_private_chat` = ?" +
", `_searchable` = ?, " +
"`_member_dt` = ?";
@@ -762,6 +991,10 @@ public class DatabaseStore {
statement.setString(index++, groupInfo.getExtra());
statement.setLong(index++, groupInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());
statement.setInt(index++, groupInfo.getMemberCount());
statement.setInt(index++, groupInfo.getMute());
statement.setInt(index++, groupInfo.getJoinType());
statement.setInt(index++, groupInfo.getPrivateChat());
statement.setInt(index++, groupInfo.getSearchable());
statement.setLong(index++, groupInfo.getMemberUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());
statement.setString(index++, groupInfo.getName());
@@ -771,6 +1004,10 @@ public class DatabaseStore {
statement.setString(index++, groupInfo.getExtra());
statement.setLong(index++, groupInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());
statement.setInt(index++, groupInfo.getMemberCount());
statement.setInt(index++, groupInfo.getMute());
statement.setInt(index++, groupInfo.getJoinType());
statement.setInt(index++, groupInfo.getPrivateChat());
statement.setInt(index++, groupInfo.getSearchable());
statement.setLong(index++, groupInfo.getMemberUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
@@ -916,7 +1153,7 @@ public class DatabaseStore {
statement.setInt(index++, request.getPlatform());
}
if (session.getPushType() != request.getPushType()) {
statement.setInt(index++, request.getPushType());
statement.setInt(index++, request.getPushType() >= 32 ? 0 : request.getPushType());
}
if (!strEqual(session.getDeviceName(), request.getDeviceName())) {
statement.setString(index++, request.getDeviceName());
@@ -1028,7 +1265,6 @@ public class DatabaseStore {
}
void persistGroupMember(final String groupId, final List<WFCMessage.GroupMember> memberList) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
@@ -1084,7 +1320,70 @@ public class DatabaseStore {
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
int removeGroupMember(String groupId, List<String> groupMembers) {
Connection connection = null;
PreparedStatement statement = null;
PreparedStatement statement2 = null;
try {
connection = DBUtil.getConnection();
connection.setAutoCommit(false);
StringBuilder sqlBuilder = new StringBuilder("update t_group_member set `_type` = ?, `_dt` = ? where `_mid` in (");
for (int i = 0; i < groupMembers.size(); i++) {
sqlBuilder.append("?");
if (i != groupMembers.size()-1) {
sqlBuilder.append(",");
}
}
sqlBuilder.append(")");
sqlBuilder.append(" and _gid = ?");
statement = connection.prepareStatement(sqlBuilder.toString());
int index = 1;
long current = System.currentTimeMillis();
statement.setInt(index++, ProtoConstants.GroupMemberType.GroupMemberType_Removed);
statement.setLong(index++, current);
for (String memberId:groupMembers) {
statement.setString(index++, memberId);
}
statement.setString(index++, groupId);
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
String sql = "update t_group set `_member_count` = `_member_count` - ?, `_member_dt` = ? , `_dt` = ? where `_gid` = ?";
statement2 = connection.prepareStatement(sql);
index = 1;
statement2.setInt(index++, count);
statement2.setLong(index++, current);
statement2.setLong(index++, current);
statement2.setString(index++, groupId);
statement2.executeUpdate();
connection.commit();
connection.setAutoCommit(true);
} catch (SQLException e) {
// TODO Auto-generated catch block
if (connection != null) {
try {
connection.commit();
connection.setAutoCommit(true);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
DBUtil.closeDB(connection, statement2);
}
return 0;
}
WFCMessage.GroupInfo getPersistGroupInfo(String groupId) {
@@ -1101,6 +1400,10 @@ public class DatabaseStore {
", `_dt`" +
", `_member_count`" +
", `_member_dt`" +
", `_mute`" +
", `_join_type`" +
", `_private_chat`" +
", `_searchable`" +
" from t_group where `_gid` = ?";
statement = connection.prepareStatement(sql);
@@ -1136,18 +1439,27 @@ public class DatabaseStore {
strValue = (strValue == null ? "" : strValue);
builder.setExtra(strValue);
long longValue = rs.getLong(index++);
builder.setUpdateDt(longValue);
intValue = rs.getInt(index++);
builder.setMemberCount(intValue);
longValue = rs.getLong(index++);
builder.setMemberUpdateDt(longValue);
intValue = rs.getInt(index++);
builder.setMute(intValue);
intValue = rs.getInt(index++);
builder.setJoinType(intValue);
intValue = rs.getInt(index++);
builder.setPrivateChat(intValue);
intValue = rs.getInt(index++);
builder.setSearchable(intValue);
return builder.build();
}
} catch (SQLException e) {
@@ -1492,7 +1804,6 @@ public class DatabaseStore {
void updateUser(final WFCMessage.User user) {
LOG.info("Database update user info {} {}", user.getUid(), user.getUpdateDt());
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
LOG.info("Database update user info {}", user.getDisplayName());
@@ -1557,6 +1868,26 @@ public class DatabaseStore {
statement.setInt(index++, user.getType());
statement.setLong(index++, user.getUpdateDt() == 0 ? System.currentTimeMillis() : user.getUpdateDt());
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Utility.printExecption(LOG, e);
} finally {
DBUtil.closeDB(connection, statement);
}
}
void deleteUserStatus(String userId) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "delete from t_user_status where _uid = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, userId);
int count = statement.executeUpdate();
LOG.info("Update rows {}", count);
} catch (SQLException e) {
@@ -1903,7 +2234,6 @@ public class DatabaseStore {
}
void persistFriendRequestUnreadStatus(String userId, long readDt, long updateDt) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
@@ -1930,11 +2260,9 @@ public class DatabaseStore {
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
//
void persistOrUpdateFriendRequest(final WFCMessage.FriendRequest request) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
@@ -1971,11 +2299,9 @@ public class DatabaseStore {
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
void persistOrUpdateFriendData(final FriendData request) {
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
@@ -2006,7 +2332,6 @@ public class DatabaseStore {
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
boolean removeGroupInfoFromDB(String groupId) {
@@ -2054,7 +2379,6 @@ public class DatabaseStore {
void updateChannelInfo(final WFCMessage.ChannelInfo channelInfo) {
LOG.info("Database update channel info {} {}", channelInfo.getTargetId(), channelInfo.getUpdateDt());
mScheduler.execute(()->{
Connection connection = null;
PreparedStatement statement = null;
try {
@@ -2117,7 +2441,6 @@ public class DatabaseStore {
} finally {
DBUtil.closeDB(connection, statement);
}
});
}
void removeChannelInfo(final String channelId) {
@@ -2443,7 +2766,7 @@ public class DatabaseStore {
try {
connection = DBUtil.getConnection();
String sql = "select `_word` from t_sensitiveword";
String sql = "select `_word` from t_sensitiveword order by `id` desc";
statement = connection.prepareStatement(sql);
rs = statement.executeQuery();
File diff suppressed because it is too large Load Diff
@@ -27,7 +27,7 @@ public class UserStatusLoader implements MapStore<String, Integer> {
@Override
public void delete(String s) {
getDatabaseStore().deleteUser(s);
getDatabaseStore().deleteUserStatus(s);
}
@Override
@@ -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,29 @@ 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);
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);
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);
WFCMessage.Robot getRobot(String robotId);
void addRobot(WFCMessage.Robot robot);
@@ -132,6 +136,8 @@ public interface IMessagesStore {
WFCMessage.User getUserInfoByMobile(String mobile);
List<WFCMessage.User> searchUser(String keyword, boolean buzzy, 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);
@@ -152,7 +158,7 @@ public interface IMessagesStore {
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);
@@ -308,7 +308,7 @@ public class MessagesPublisher {
}
if (isSlient) {
LOG.info("The conversation is slient");
LOG.info("Slient of user or conversation");
continue;
}
@@ -623,7 +623,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);
@@ -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";
@@ -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){
+2 -2
View File
@@ -15,11 +15,11 @@
<!--MySQL数据库驱动程序-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!--MySQL数据库地址-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8</property>
<!--MySQL数据库用户名-->
<property name="user">root</property>
<!--MySQL数据库密码-->
<property name="password">123456</property>
<property name="password">lt123456</property>
<!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
<property name="initialPoolSize">10</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->
+1 -1
View File
@@ -6,7 +6,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.22</version>
<version>0.27</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,9 +1,10 @@
package cn.wildfirechat.client;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import cn.wildfirechat.pojos.InputRoute;
import com.xiaoleilu.loServer.pojos.InputRoute;
import io.moquette.spi.impl.security.AES;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
@@ -18,6 +19,7 @@ import org.fusesource.mqtt.client.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
@@ -280,15 +282,38 @@ public class IMClient implements Listener {
try {
WFCMessage.NotifyMessage notifyMessage = WFCMessage.NotifyMessage.parseFrom(body.toByteArray());
WFCMessage.PullMessageRequest request = WFCMessage.PullMessageRequest.newBuilder().setId(messageHead).setType(notifyMessage.getType()).build();
connection.publish("MP", request.toByteArray(), QoS.AT_LEAST_ONCE, false, new Callback<byte[]>(){
byte[] data = request.toByteArray();
data = AES.AESEncrypt(data, privateSecret);
connection.publish("MP", data, QoS.AT_LEAST_ONCE, false, new Callback<byte[]>(){
@Override
public void onSuccess(byte[] value) {
if (value == null || value.length == 0) {
System.out.println("Invalide data");
}
if (value[0] != 0) {
System.out.println("Pull message error with errorCode:" + value[0]);
}
byte[] data = new byte[value.length - 1];
for (int i = 0; i < data.length; i++) {
data[i] = value[i+1];
}
try {
byte[] data = AES.AESDecrypt(value, privateSecret, true);
data = AES.AESDecrypt(data, privateSecret, true);
try {
WFCMessage.PullMessageResult result = WFCMessage.PullMessageResult.parseFrom(data);
if (receiveMessageCallback != null) {
receiveMessageCallback.onReceiveMessages(result.getMessageList(), false);
if (receiveMessageCallback != null && result.getMessageList().size() > 0) {
List<WFCMessage.Message> messages = result.getMessageList();
List<WFCMessage.Message> out = new ArrayList<>();
for (WFCMessage.Message msg : messages) {
if (msg.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private && msg.getConversation().getTarget().equals(userId)) {
msg = msg.toBuilder().setConversation(msg.getConversation().toBuilder().setTarget(msg.getFromUser())).build();
}
out.add(msg);
}
receiveMessageCallback.onReceiveMessages(out, false);
}
messageHead = result.getHead();
} catch (InvalidProtocolBufferException e) {
@@ -355,23 +380,24 @@ public class IMClient implements Listener {
public static void main(String[] args) {
//token与userid和clientid是绑定的,使用时一定要传入正确的userid和clientid,不然会认为token非法
IMClient client = new IMClient("yzyOyOKK", "7SJk13q+YdHHe6EwDzry9BKogxTNf3UgtYj50cBTZgWNkNuxEkiqg2koKg0lXViONIX1LmwCR1jN0Mw8hvk6KGpiSKFi+IRaRkIb3mNzgIfrq4afhyIHaQfa2HOfsi6Ws+9YobkdDgdq7W70bEdVfiCSU9+JOIY449nxZzfg2Zw=", "DD72C212-26C7-4B38-A5FC-88550896B170", "192.168.1.101", 80);
//clientId唯一代表一个设备,只能有一个登录。如果使用同一个clientId登录多次,会出现不可预料问题。
IMClient client = new IMClient("KNK_K_00", "6I7UTfKSQT7VhsUJfU6UCvDeCyblLfcXPfajAFxgFGOcqvfFVQCvYy8A5vfAGUj2LSYgoM5W02MHh6jtG/otQs6ft8zLT4Efz315UlDLfrz+OSQYfwAuGFw9m0/x4ckrgiooprsKFxPMaNcCDact0qvp1dBhbeGUipdWVhI33b4=", "5B6DEB72-8A3D-45E2-A88A-47DC4E692B00", "192.168.0.193", 80);
client.setReceiveMessageCallback(new ReceiveMessageCallback() {
@Override
public void onReceiveMessages(List<WFCMessage.Message> messageList, boolean hasMore) {
System.out.println("recieved messages");
}
@Override
public void onRecallMessage(long messageUid) {
System.out.println("recalled messages");
}
});
client.setConnectionStatusCallback((ConnectionStatus newStatus) -> {
if (newStatus == ConnectionStatus_Connected) {
WFCMessage.Conversation conversation = WFCMessage.Conversation.newBuilder().setType(0).setTarget("yzyOyOKK").setLine(0).build();
WFCMessage.Conversation conversation = WFCMessage.Conversation.newBuilder().setType(0).setTarget("IMININnn").setLine(0).build();
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.newBuilder().setSearchableContent("helloworld").setType(1).build();
client.sendMessage(conversation, messageContent, new SendMessageCallback() {
@Override
@@ -1,4 +1,4 @@
package cn.wildfirechat.pojos;
package com.xiaoleilu.loServer.pojos;
public class InputRoute {
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.22</version>
<version>0.27</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -22,13 +22,13 @@ public class GroupNotificationBinaryContent {
//operator
private String o;
//name
//value1(name or something)
private String n;
//members
private List<String> ms;
//members
//value2(member or something)
private String m;
public GroupNotificationBinaryContent(String g, String o, String n, String m) {
@@ -124,4 +124,27 @@ public class GroupNotificationBinaryContent {
public WFCMessage.MessageContent getModifyGroupMemberAliasNotifyContent() {
return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS);
}
public WFCMessage.MessageContent getChangeGroupMuteNotifyContent() {
return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_MUTE);
}
public WFCMessage.MessageContent getChangeGroupJointypeNotifyContent() {
return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_JOINTYPE);
}
public WFCMessage.MessageContent getChangeGroupPrivatechatNotifyContent() {
return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_PRIVATECHAT);
}
public WFCMessage.MessageContent getChangeGroupSearchableNotifyContent() {
return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_SEARCHABLE);
}
public WFCMessage.MessageContent getSetGroupManagerNotifyContent() {
return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_SET_MANAGER);
}
}
@@ -0,0 +1,142 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import io.netty.util.internal.StringUtil;
public class InputCreateChannel {
private String owner;
private String name;
private String targetId;
private String callback;
private String portrait;
private int auto;
private String secret;
private String desc;
private int status;
private String extra;
private long updateDt;
public WFCMessage.ChannelInfo toProtoChannelInfo() {
WFCMessage.ChannelInfo.Builder builder = WFCMessage.ChannelInfo.newBuilder().setOwner(owner);
if (!StringUtil.isNullOrEmpty(name))
builder = builder.setName(name);
if (!StringUtil.isNullOrEmpty(targetId))
builder = builder.setTargetId(targetId);
if (!StringUtil.isNullOrEmpty(callback))
builder = builder.setCallback(callback);
if (!StringUtil.isNullOrEmpty(portrait))
builder = builder.setPortrait(portrait);
builder = builder.setAutomatic(auto);
if (!StringUtil.isNullOrEmpty(secret))
builder = builder.setSecret(secret);
if (!StringUtil.isNullOrEmpty(desc))
builder = builder.setDesc(desc);
builder = builder.setStatus(status);
if (!StringUtil.isNullOrEmpty(extra))
builder = builder.setExtra(extra);
if (!StringUtil.isNullOrEmpty(name))
builder = builder.setUpdateDt(updateDt);
else
builder = builder.setUpdateDt(System.currentTimeMillis());
return builder.build();
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTargetId() {
return targetId;
}
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public String getCallback() {
return callback;
}
public void setCallback(String callback) {
this.callback = callback;
}
public String getPortrait() {
return portrait;
}
public void setPortrait(String portrait) {
this.portrait = portrait;
}
public int getAuto() {
return auto;
}
public void setAuto(int auto) {
this.auto = auto;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
public long getUpdateDt() {
return updateDt;
}
public void setUpdateDt(long updateDt) {
this.updateDt = updateDt;
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
import io.netty.util.internal.StringUtil;
import java.util.Arrays;
import java.util.List;
public class InputModifyGroupInfo extends InputGroupBase {
private String group_id;
//ModifyGroupInfoType
private int type;
private String value;
public boolean isValide() {
return !StringUtil.isNullOrEmpty(group_id);
}
public String getGroup_id() {
return group_id;
}
public void setGroup_id(String group_id) {
this.group_id = group_id;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public WFCMessage.ModifyGroupInfoRequest toProtoGroupRequest() {
return WFCMessage.ModifyGroupInfoRequest.newBuilder()
.setGroupId(group_id)
.setType(type)
.setValue(value)
.addAllToLine(to_lines == null || to_lines.isEmpty() ? Arrays.asList(0) : to_lines)
.build();
}
}
@@ -0,0 +1,38 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
public class MultiMessageResult {
private long messageUid;
private long timestamp;
public MultiMessageResult() {
}
public MultiMessageResult(long messageUid, long timestamp) {
this.messageUid = messageUid;
this.timestamp = timestamp;
}
public long getMessageUid() {
return messageUid;
}
public void setMessageUid(long messageUid) {
this.messageUid = messageUid;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}
@@ -0,0 +1,71 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import io.netty.util.internal.StringUtil;
import java.util.List;
public class MulticastMessageData {
private String sender;
private int line;
private MessagePayload payload;
private List<String> targets;
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public int getLine() {
return line;
}
public void setLine(int line) {
this.line = line;
}
public MessagePayload getPayload() {
return payload;
}
public void setPayload(MessagePayload payload) {
this.payload = payload;
}
public static boolean isValide(MulticastMessageData sendMessageData) {
if(sendMessageData == null ||
StringUtil.isNullOrEmpty(sendMessageData.getSender()) ||
sendMessageData.getPayload() == null) {
return false;
}
return true;
}
public WFCMessage.MultiCastMessage toProtoMessage() {
return WFCMessage.MultiCastMessage.newBuilder().setFromUser(sender)
.setLine(line)
.setContent(payload.toProtoMessageContent())
.addAllTo(targets)
.build();
}
public List<String> getTargets() {
return targets;
}
public void setTargets(List<String> targets) {
this.targets = targets;
}
}
@@ -0,0 +1,28 @@
/*
* This file is part of the Wildfire Chat package.
* (c) Heavyrain2012 <heavyrain.lee@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package cn.wildfirechat.pojos;
import cn.wildfirechat.proto.WFCMessage;
public class OutputCreateChannel {
private String targetId;
public OutputCreateChannel(String targetId) {
this.targetId = targetId;
}
public String getTargetId() {
return targetId;
}
public void setTargetId(String targetId) {
this.targetId = targetId;
}
}
@@ -0,0 +1,7 @@
package cn.wildfirechat.pojos;
public class SystemSettingPojo {
public int id;
public String value;
public String desc;
}
@@ -26,16 +26,23 @@ public interface APIPath {
String Msg_Send = "/admin/message/send";
String Msg_Recall = "/admin/message/recall";
String Msg_Broadcast = "/admin/message/broadcast";
String Msg_Multicast = "/admin/message/multicast";
String Create_Group = "/admin/group/create";
String Group_Dismiss = "/admin/group/del";
String Group_Transfer = "/admin/group/transfer";
String Group_Get_Info = "/admin/group/get_info";
String Group_Modify_Info = "/admin/group/modify";
String Group_Member_List = "/admin/group/member/list";
String Group_Member_Add = "/admin/group/member/add";
String Group_Member_Kickoff = "/admin/group/member/del";
String Create_Channel = "/admin/channel/create";
String Get_System_Setting = "/admin/system/get_setting";
String Put_System_Setting = "/admin/system/put_setting";
String Channel_Message_Send = "/channel/message/send";
String Robot_User_Info = "/robot/user_info";
@@ -42,6 +42,7 @@ public enum ErrorCode {
ERROR_CODE_NOT_IN_CHANNEL(21, "not in channel"),
ERROR_CODE_GROUP_MUTED(241, "group is muted"),
ERROR_CODE_SENSITIVE_MATCHED(242, "sensitive matched"),
ERROR_CODE_SIGN_EXPIRED(243, "sign expired"),
ERROR_CODE_AUTH_FAILURE(244, "auth failure"),
@@ -87,6 +87,10 @@ public class ProtoConstants {
int Modify_Group_Name = 0;
int Modify_Group_Portrait = 1;
int Modify_Group_Extra = 2;
int Modify_Group_Mute = 3;
int Modify_Group_JoinType = 4;
int Modify_Group_PrivateChat = 5;
int Modify_Group_Searchable = 6;
}
//ModifyGroupInfoRequest -> type
@@ -124,6 +128,9 @@ public class ProtoConstants {
}
public interface SystemSettingType {
int Group_Max_Member_Count = 1;
}
@@ -137,5 +144,12 @@ public class ProtoConstants {
public static final int MESSAGE_CONTENT_TYPE_CHANGE_GROUP_NAME = 110;
public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS = 111;
public static final int MESSAGE_CONTENT_TYPE_CHANGE_GROUP_PORTRAIT = 112;
public static final int MESSAGE_CONTENT_TYPE_CHANGE_MUTE = 113;
public static final int MESSAGE_CONTENT_TYPE_CHANGE_JOINTYPE = 114;
public static final int MESSAGE_CONTENT_TYPE_CHANGE_PRIVATECHAT = 115;
public static final int MESSAGE_CONTENT_TYPE_CHANGE_SEARCHABLE = 116;
public static final int MESSAGE_CONTENT_TYPE_SET_MANAGER = 117;
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.22</version>
<version>0.27</version>
</parent>
<artifactId>distribution</artifactId>
@@ -15,7 +15,7 @@
<!--MySQL数据库驱动程序-->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!--MySQL数据库地址-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8</property>
<!--MySQL数据库用户名-->
<property name="user">root</property>
<!--MySQL数据库密码-->
@@ -26,7 +26,7 @@ host 0.0.0.0
##本地绑定端口
local_port 80
##是否使用内置DB。0使用mysql;1使用h2db
##是否使用内置DB。0使用mysql;1使用h2db;2使用mysql+mongodb。社区版只支持0和1,专业版支持2
embed.db 1
##服务器管理接口密钥
@@ -42,6 +42,12 @@ 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
#*********************************************************************
# hazelcase configuration
#*********************************************************************
@@ -96,6 +102,15 @@ 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
#*********************************************************************
# Netty Configuration
@@ -17,9 +17,9 @@ goto end
rem Set JavaHome if it exists
if exist { "%JAVA_HOME%\bin\java" } (
set "JAVA="%JAVA_HOME%\bin\java""
) else {
) else (
set "JAVA="java""
}
)
echo Using JAVA_HOME: "%JAVA_HOME%"
echo Using WILDFIRECHAT_HOME: "%WILDFIRECHAT_HOME%"
@@ -30,6 +30,8 @@ set JAVA_OPTS=
set JAVA_OPTS_SCRIPT=-XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true
set WILDFIRECHAT_PATH=%WILDFIRECHAT_HOME%
set LOG_FILE=%WILDFIRECHAT_HOME%\config\log4j.properties
set HZ_CONF_FILE=%WILDFIRECHAT_HOME%\config\hazelcast.xml
set C3P0_CONF_FILE=%WILDFIRECHAT_HOME%\config\c3p0-config.xml
rem Use the Hotspot garbage-first collector.
set JAVA_OPTS=%JAVA_OPTS% -XX:+UseG1GC
@@ -71,4 +73,4 @@ rem set JAVA_OPTS=%JAVA_OPTS% -XX:+UseGCLogFileRotation
rem set JAVA_OPTS=%JAVA_OPTS% -XX:NumberOfGCLogFiles=10
rem set JAVA_OPTS=%JAVA_OPTS% -XX:GCLogFileSize=10M"
%JAVA% -server %JAVA_OPTS% %JAVA_OPTS_SCRIPT% -Dlog4j.configuration=file:%LOG_FILE% -Dwildfirechat.path=%WILDFIRECHAT_PATH% -cp %WILDFIRECHAT_HOME%\lib\* cn.wildfirechat.server.Server
%JAVA% -server %JAVA_OPTS% %JAVA_OPTS_SCRIPT% -Dlog4j.configuration=file:%LOG_FILE% -Dcom.mchange.v2.c3p0.cfg.xml=%C3P0_CONF_FILE% -Dhazelcast.configuration=file:%HZ_CONF_FILE% -Dwildfirechat.path=%WILDFIRECHAT_PATH% -cp %WILDFIRECHAT_HOME%\lib\* cn.wildfirechat.server.Server
@@ -70,7 +70,7 @@ JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=500"
### GC logging options -- uncomment to enable
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintTenuringDistribution"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCApplicationStoppedTime"
+1 -2
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>0.22</version>
<version>0.27</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
@@ -30,7 +30,6 @@
</licenses>
<modules>
<module>broker</module>
<module>wildfire_jmeter</module>
-35
View File
@@ -1,35 +0,0 @@
## Run follow command by sequence:
To build protobuf from source, the following tools are needed:
On Ubuntu, you can install them with:
$ sudo apt-get install autoconf automake libtool curl make g++ unzip
On Mac, you can install them with:
$ brew install autoconf automake libtool
Then run the cmd.
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig # refresh shared library cache.
## Javascript 生成方法
1. 安装nodejs
2. 安装protobufjs
```
sudo npm install protobufjs@5 -g
```
3. 生成JS
```
pbjs -t static-module -w commonjs -o protocol.js wfcmessage.proto
```
> [参考1](http://dcode.io/protobuf.js/#pbjs-for-javascript)
> [参考2](https://blog.csdn.net/yyf1990cs/article/details/78942157)
-528
View File
@@ -1,528 +0,0 @@
2013-02-27 version 2.5.0:
General
* New notion "import public" that allows a proto file to forward the content
it imports to its importers. For example,
// foo.proto
import public "bar.proto";
import "baz.proto";
// qux.proto
import "foo.proto";
// Stuff defined in bar.proto may be used in this file, but stuff from
// baz.proto may NOT be used without importing it explicitly.
This is useful for moving proto files. To move a proto file, just leave
a single "import public" in the old proto file.
* New enum option "allow_alias" that specifies whether different symbols can
be assigned the same numeric value. Default value is "true". Setting it to
false causes the compiler to reject enum definitions where multiple symbols
have the same numeric value.
C++
* New generated method set_allocated_foo(Type* foo) for message and string
fields. This method allows you to set the field to a pre-allocated object
and the containing message takes the ownership of that object.
* Added SetAllocatedExtension() and ReleaseExtension() to extensions API.
* Custom options are now formatted correctly when descriptors are printed in
text format.
* Various speed optimizations.
Java
* Comments in proto files are now collected and put into generated code as
comments for corresponding classes and data members.
* Added Parser to parse directly into messages without a Builder. For
example,
Foo foo = Foo.getParser().ParseFrom(input);
Using Parser is ~25% faster than using Builder to parse messages.
* Added getters/setters to access the underlying ByteString of a string field
directly.
* ByteString now supports more operations: substring(), prepend(), and
append(). The implementation of ByteString uses a binary tree structure
to support these operations efficiently.
* New method findInitializationErrors() that lists all missing required
fields.
* Various code size and speed optimizations.
Python
* Added support for dynamic message creation. DescriptorDatabase,
DescriptorPool, and MessageFactory work like their C++ couterparts to
simplify Descriptor construction from *DescriptorProtos, and MessageFactory
provides a message instance from a Descriptor.
* Added pickle support for protobuf messages.
* Unknown fields are now preserved after parsing.
* Fixed bug where custom options were not correctly populated. Custom
options can be accessed now.
* Added EnumTypeWrapper that provides better accessibility to enum types.
* Added ParseMessage(descriptor, bytes) to generate a new Message instance
from a descriptor and a byte string.
2011-05-01 version 2.4.1:
C++
* Fixed the frendship problem for old compilers to make the library now gcc 3
compatible again.
* Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h.
Java
* Removed usages of JDK 1.6 only features to make the library now JDK 1.5
compatible again.
* Fixed a bug about negative enum values.
* serialVersionUID is now defined in generated messages for java serializing.
* Fixed protoc to use java.lang.Object, which makes "Object" now a valid
message name again.
Python
* Experimental C++ implementation now requires C++ protobuf library installed.
See the README.txt in the python directory for details.
2011-02-02 version 2.4.0:
General
* The RPC (cc|java|py)_generic_services default value is now false instead of
true.
* Custom options can have aggregate types. For example,
message MyOption {
optional string comment = 1;
optional string author = 2;
}
extend google.protobuf.FieldOptions {
optional MyOption myoption = 12345;
}
This option can now be set as follows:
message SomeType {
optional int32 field = 1 [(myoption) = { comment:'x' author:'y' }];
}
C++
* Various speed and code size optimizations.
* Added a release_foo() method on string and message fields.
* Fixed gzip_output_stream sub-stream handling.
Java
* Builders now maintain sub-builders for sub-messages. Use getFooBuilder() to
get the builder for the sub-message "foo". This allows you to repeatedly
modify deeply-nested sub-messages without rebuilding them.
* Builder.build() no longer invalidates the Builder for generated messages
(You may continue to modify it and then build another message).
* Code generator will generate efficient equals() and hashCode()
implementations if new option java_generate_equals_and_hash is enabled.
(Otherwise, reflection-based implementations are used.)
* Generated messages now implement Serializable.
* Fields with [deprecated=true] will be marked with @Deprecated in Java.
* Added lazy conversion of UTF-8 encoded strings to String objects to improve
performance.
* Various optimizations.
* Enum value can be accessed directly, instead of calling getNumber() on the
enum member.
* For each enum value, an integer constant is also generated with the suffix
_VALUE.
Python
* Added an experimental C++ implementation for Python messages via a Python
extension. Implementation type is controlled by an environment variable
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION (valid values: "cpp" and "python")
The default value is currently "python" but will be changed to "cpp" in
future release.
* Improved performance on message instantiation significantly.
Most of the work on message instantiation is done just once per message
class, instead of once per message instance.
* Improved performance on text message parsing.
* Allow add() to forward keyword arguments to the concrete class.
E.g. instead of
item = repeated_field.add()
item.foo = bar
item.baz = quux
You can do:
repeated_field.add(foo=bar, baz=quux)
* Added a sort() interface to the BaseContainer.
* Added an extend() method to repeated composite fields.
* Added UTF8 debug string support.
2010-01-08 version 2.3.0:
General
* Parsers for repeated numeric fields now always accept both packed and
unpacked input. The [packed=true] option only affects serializers.
Therefore, it is possible to switch a field to packed format without
breaking backwards-compatibility -- as long as all parties are using
protobuf 2.3.0 or above, at least.
* The generic RPC service code generated by the C++, Java, and Python
generators can be disabled via file options:
option cc_generic_services = false;
option java_generic_services = false;
option py_generic_services = false;
This allows plugins to generate alternative code, possibly specific to some
particular RPC implementation.
protoc
* Now supports a plugin system for code generators. Plugins can generate
code for new languages or inject additional code into the output of other
code generators. Plugins are just binaries which accept a protocol buffer
on stdin and write a protocol buffer to stdout, so they may be written in
any language. See src/google/protobuf/compiler/plugin.proto.
**WARNING**: Plugins are experimental. The interface may change in a
future version.
* If the output location ends in .zip or .jar, protoc will write its output
to a zip/jar archive instead of a directory. For example:
protoc --java_out=myproto_srcs.jar --python_out=myproto.zip myproto.proto
Currently the archive contents are not compressed, though this could change
in the future.
* inf, -inf, and nan can now be used as default values for float and double
fields.
C++
* Various speed and code size optimizations.
* DynamicMessageFactory is now fully thread-safe.
* Message::Utf8DebugString() method is like DebugString() but avoids escaping
UTF-8 bytes.
* Compiled-in message types can now contain dynamic extensions, through use
of CodedInputStream::SetExtensionRegistry().
* Now compiles shared libraries (DLLs) by default on Cygwin and MinGW, to
match other platforms. Use --disable-shared to avoid this.
Java
* parseDelimitedFrom() and mergeDelimitedFrom() now detect EOF and return
false/null instead of throwing an exception.
* Fixed some initialization ordering bugs.
* Fixes for OpenJDK 7.
Python
* 10-25 times faster than 2.2.0, still pure-Python.
* Calling a mutating method on a sub-message always instantiates the message
in its parent even if the mutating method doesn't actually mutate anything
(e.g. parsing from an empty string).
* Expanded descriptors a bit.
2009-08-11 version 2.2.0:
C++
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler
to generate code which only depends libprotobuf-lite, which is much smaller
than libprotobuf but lacks descriptors, reflection, and some other features.
* Fixed bug where Message.Swap(Message) was only implemented for
optimize_for_speed. Swap now properly implemented in both modes
(Issue 91).
* Added RemoveLast and SwapElements(index1, index2) to Reflection
interface for repeated elements.
* Added Swap(Message) to Reflection interface.
* Floating-point literals in generated code that are intended to be
single-precision now explicitly have 'f' suffix to avoid pedantic warnings
produced by some compilers.
* The [deprecated=true] option now causes the C++ code generator to generate
a GCC-style deprecation annotation (no-op on other compilers).
* google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the
EnumDescriptor for that type -- useful for templates which cannot call
SomeGeneratedEnumType_descriptor().
* Various optimizations and obscure bug fixes.
Java
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler
to generate code which only depends libprotobuf-lite, which is much smaller
than libprotobuf but lacks descriptors, reflection, and some other features.
* Lots of style cleanups.
Python
* Fixed endianness bug with floats and doubles.
* Text format parsing support.
* Fix bug with parsing packed repeated fields in embedded messages.
* Ability to initialize fields by passing keyword args to constructor.
* Support iterators in extend and __setslice__ for containers.
2009-05-13 version 2.1.0:
General
* Repeated fields of primitive types (types other that string, group, and
nested messages) may now use the option [packed = true] to get a more
efficient encoding. In the new encoding, the entire list is written
as a single byte blob using the "length-delimited" wire type. Within
this blob, the individual values are encoded the same way they would
be normally except without a tag before each value (thus, they are
tightly "packed").
* For each field, the generated code contains an integer constant assigned
to the field number. For example, the .proto file:
message Foo { optional int bar_baz = 123; }
would generate the following constants, all with the integer value 123:
C++: Foo::kBarBazFieldNumber
Java: Foo.BAR_BAZ_FIELD_NUMBER
Python: Foo.BAR_BAZ_FIELD_NUMBER
Constants are also generated for extensions, with the same naming scheme.
These constants may be used as switch cases.
* Updated bundled Google Test to version 1.3.0. Google Test is now bundled
in its verbatim form as a nested autoconf package, so you can drop in any
other version of Google Test if needed.
* optimize_for = SPEED is now the default, by popular demand. Use
optimize_for = CODE_SIZE if code size is more important in your app.
* It is now an error to define a default value for a repeated field.
Previously, this was silently ignored (it had no effect on the generated
code).
* Fields can now be marked deprecated like:
optional int32 foo = 1 [deprecated = true];
Currently this does not have any actual effect, but in the future the code
generators may generate deprecation annotations in each language.
* Cross-compiling should now be possible using the --with-protoc option to
configure. See README.txt for more info.
protoc
* --error_format=msvs option causes errors to be printed in Visual Studio
format, which should allow them to be clicked on in the build log to go
directly to the error location.
* The type name resolver will no longer resolve type names to fields. For
example, this now works:
message Foo {}
message Bar {
optional int32 Foo = 1;
optional Foo baz = 2;
}
Previously, the type of "baz" would resolve to "Bar.Foo", and you'd get
an error because Bar.Foo is a field, not a type. Now the type of "baz"
resolves to the message type Foo. This change is unlikely to make a
difference to anyone who follows the Protocol Buffers style guide.
C++
* Several optimizations, including but not limited to:
- Serialization, especially to flat arrays, is 10%-50% faster, possibly
more for small objects.
- Several descriptor operations which previously required locking no longer
do.
- Descriptors are now constructed lazily on first use, rather than at
process startup time. This should save memory in programs which do not
use descriptors or reflection.
- UnknownFieldSet completely redesigned to be more efficient (especially in
terms of memory usage).
- Various optimizations to reduce code size (though the serialization speed
optimizations increased code size).
* Message interface has method ParseFromBoundedZeroCopyStream() which parses
a limited number of bytes from an input stream rather than parsing until
EOF.
* GzipInputStream and GzipOutputStream support reading/writing gzip- or
zlib-compressed streams if zlib is available.
(google/protobuf/io/gzip_stream.h)
* DescriptorPool::FindAllExtensions() and corresponding
DescriptorDatabase::FindAllExtensions() can be used to enumerate all
extensions of a given type.
* For each enum type Foo, protoc will generate functions:
const string& Foo_Name(Foo value);
bool Foo_Parse(const string& name, Foo* result);
The former returns the name of the enum constant corresponding to the given
value while the latter finds the value corresponding to a name.
* RepeatedField and RepeatedPtrField now have back-insertion iterators.
* String fields now have setters that take a char* and a size, in addition
to the existing ones that took char* or const string&.
* DescriptorPool::AllowUnknownDependencies() may be used to tell
DescriptorPool to create placeholder descriptors for unknown entities
referenced in a FileDescriptorProto. This can allow you to parse a .proto
file without having access to other .proto files that it imports, for
example.
* Updated gtest to latest version. The gtest package is now included as a
nested autoconf package, so it should be able to drop new versions into the
"gtest" subdirectory without modification.
Java
* Fixed bug where Message.mergeFrom(Message) failed to merge extensions.
* Message interface has new method toBuilder() which is equivalent to
newBuilderForType().mergeFrom(this).
* All enums now implement the ProtocolMessageEnum interface.
* Setting a field to null now throws NullPointerException.
* Fixed tendency for TextFormat's parsing to overflow the stack when
parsing large string values. The underlying problem is with Java's
regex implementation (which unfortunately uses recursive backtracking
rather than building an NFA). Worked around by making use of possesive
quantifiers.
* Generated service classes now also generate pure interfaces. For a service
Foo, Foo.Interface is a pure interface containing all of the service's
defined methods. Foo.newReflectiveService() can be called to wrap an
instance of this interface in a class that implements the generic
RpcService interface, which provides reflection support that is usually
needed by RPC server implementations.
* RPC interfaces now support blocking operation in addition to non-blocking.
The protocol compiler generates separate blocking and non-blocking stubs
which operate against separate blocking and non-blocking RPC interfaces.
RPC implementations will have to implement the new interfaces in order to
support blocking mode.
* New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and
writeDelimitedTo() read and write "delemited" messages from/to a stream,
meaning that the message size precedes the data. This way, you can write
multiple messages to a stream without having to worry about delimiting
them yourself.
* Throw a more descriptive exception when build() is double-called.
* Add a method to query whether CodedInputStream is at the end of the input
stream.
* Add a method to reset a CodedInputStream's size counter; useful when
reading many messages with the same stream.
* equals() and hashCode() now account for unknown fields.
Python
* Added slicing support for repeated scalar fields. Added slice retrieval and
removal of repeated composite fields.
* Updated RPC interfaces to allow for blocking operation. A client may
now pass None for a callback when making an RPC, in which case the
call will block until the response is received, and the response
object will be returned directly to the caller. This interface change
cannot be used in practice until RPC implementations are updated to
implement it.
* Changes to input_stream.py should make protobuf compatible with appengine.
2008-11-25 version 2.0.3:
protoc
* Enum values may now have custom options, using syntax similar to field
options.
* Fixed bug where .proto files which use custom options but don't actually
define them (i.e. they import another .proto file defining the options)
had to explicitly import descriptor.proto.
* Adjacent string literals in .proto files will now be concatenated, like in
C.
* If an input file is a Windows absolute path (e.g. "C:\foo\bar.proto") and
the import path only contains "." (or contains "." but does not contain
the file), protoc incorrectly thought that the file was under ".", because
it thought that the path was relative (since it didn't start with a slash).
This has been fixed.
C++
* Generated message classes now have a Swap() method which efficiently swaps
the contents of two objects.
* All message classes now have a SpaceUsed() method which returns an estimate
of the number of bytes of allocated memory currently owned by the object.
This is particularly useful when you are reusing a single message object
to improve performance but want to make sure it doesn't bloat up too large.
* New method Message::SerializeAsString() returns a string containing the
serialized data. May be more convenient than calling
SerializeToString(string*).
* In debug mode, log error messages when string-type fields are found to
contain bytes that are not valid UTF-8.
* Fixed bug where a message with multiple extension ranges couldn't parse
extensions.
* Fixed bug where MergeFrom(const Message&) didn't do anything if invoked on
a message that contained no fields (but possibly contained extensions).
* Fixed ShortDebugString() to not be O(n^2). Durr.
* Fixed crash in TextFormat parsing if the first token in the input caused a
tokenization error.
* Fixed obscure bugs in zero_copy_stream_impl.cc.
* Added support for HP C++ on Tru64.
* Only build tests on "make check", not "make".
* Fixed alignment issue that caused crashes when using DynamicMessage on
64-bit Sparc machines.
* Simplify template usage to work with MSVC 2003.
* Work around GCC 4.3.x x86_64 compiler bug that caused crashes on startup.
(This affected Fedora 9 in particular.)
* Now works on "Solaris 10 using recent Sun Studio".
Java
* New overload of mergeFrom() which parses a slice of a byte array instead
of the whole thing.
* New method ByteString.asReadOnlyByteBuffer() does what it sounds like.
* Improved performance of isInitialized() when optimizing for code size.
Python
* Corrected ListFields() signature in Message base class to match what
subclasses actually implement.
* Some minor refactoring.
* Don't pass self as first argument to superclass constructor (no longer
allowed in Python 2.6).
2008-09-29 version 2.0.2:
General
* License changed from Apache 2.0 to New BSD.
* It is now possible to define custom "options", which are basically
annotations which may be placed on definitions in a .proto file.
For example, you might define a field option called "foo" like so:
import "google/protobuf/descriptor.proto"
extend google.protobuf.FieldOptions {
optional string foo = 12345;
}
Then you annotate a field using the "foo" option:
message MyMessage {
optional int32 some_field = 1 [(foo) = "bar"]
}
The value of this option is then visible via the message's
Descriptor:
const FieldDescriptor* field =
MyMessage::descriptor()->FindFieldByName("some_field");
assert(field->options().GetExtension(foo) == "bar");
This feature has been implemented and tested in C++ and Java.
Other languages may or may not need to do extra work to support
custom options, depending on how they construct descriptors.
C++
* Fixed some GCC warnings that only occur when using -pedantic.
* Improved static initialization code, making ordering more
predictable among other things.
* TextFormat will no longer accept messages which contain multiple
instances of a singular field. Previously, the latter instance
would overwrite the former.
* Now works on systems that don't have hash_map.
Java
* Print @Override annotation in generated code where appropriate.
Python
* Strings now use the "unicode" type rather than the "str" type.
String fields may still be assigned ASCII "str" values; they will
automatically be converted.
* Adding a property to an object representing a repeated field now
raises an exception. For example:
# No longer works (and never should have).
message.some_repeated_field.foo = 1
Windows
* We now build static libraries rather than DLLs by default on MSVC.
See vsprojects/readme.txt for more information.
2008-08-15 version 2.0.1:
protoc
* New flags --encode and --decode can be used to convert between protobuf text
format and binary format from the command-line.
* New flag --descriptor_set_out can be used to write FileDescriptorProtos for
all parsed files directly into a single output file. This is particularly
useful if you wish to parse .proto files from programs written in languages
other than C++: just run protoc as a background process and have it output
a FileDescriptorList, then parse that natively.
* Improved error message when an enum value's name conflicts with another
symbol defined in the enum type's scope, e.g. if two enum types declared
in the same scope have values with the same name. This is disallowed for
compatibility with C++, but this wasn't clear from the error.
* Fixed absolute output paths on Windows.
* Allow trailing slashes in --proto_path mappings.
C++
* Reflection objects are now per-class rather than per-instance. To make this
possible, the Reflection interface had to be changed such that all methods
take the Message instance as a parameter. This change improves performance
significantly in memory-bandwidth-limited use cases, since it makes the
message objects smaller. Note that source-incompatible interface changes
like this will not be made again after the library leaves beta.
* Heuristically detect sub-messages when printing unknown fields.
* Fix static initialization ordering bug that caused crashes at startup when
compiling on Mac with static linking.
* Fixed TokenizerTest when compiling with -DNDEBUG on Linux.
* Fixed incorrect definition of kint32min.
* Fix bytes type setter to work with byte sequences with embedded NULLs.
* Other irrelevant tweaks.
Java
* Fixed UnknownFieldSet's parsing of varints larger than 32 bits.
* Fixed TextFormat's parsing of "inf" and "nan".
* Fixed TextFormat's parsing of comments.
* Added info to Java POM that will be required when we upload the
package to a Maven repo.
Python
* MergeFrom(message) and CopyFrom(message) are now implemented.
* SerializeToString() raises an exception if the message is missing required
fields.
* Code organization improvements.
* Fixed doc comments for RpcController and RpcChannel, which had somehow been
swapped.
* Fixed text_format_test on Windows where floating-point exponents sometimes
contain extra zeros.
* Fix Python service CallMethod() implementation.
Other
* Improved readmes.
* VIM syntax highlighting improvements.
2008-07-07 version 2.0.0:
* First public release.
-90
View File
@@ -1,90 +0,0 @@
This file contains a list of people who have made large contributions
to the public version of Protocol Buffers.
Original Protocol Buffers design and implementation:
Sanjay Ghemawat <[email protected]>
Jeff Dean <[email protected]>
Daniel Dulitz <[email protected]>
Craig Silverstein
Paul Haahr <[email protected]>
Corey Anderson <[email protected]>
(and many others)
Proto2 C++ and Java primary author:
Kenton Varda <[email protected]>
Proto2 Python primary authors:
Will Robinson <[email protected]>
Petar Petrov <[email protected]>
Large code contributions:
Jason Hsueh <[email protected]>
Joseph Schorr <[email protected]>
Wenbo Zhu <[email protected]>
Large quantity of code reviews:
Scott Bruce <[email protected]>
Frank Yellin
Neal Norwitz <[email protected]>
Jeffrey Yasskin <[email protected]>
Ambrose Feinstein <[email protected]>
Documentation:
Lisa Carey <[email protected]>
Maven packaging:
Gregory Kick <[email protected]>
Patch contributors:
Kevin Ko <[email protected]>
* Small patch to handle trailing slashes in --proto_path flag.
Johan Euphrosine <[email protected]>
* Small patch to fix Python CallMethod().
Ulrich Kunitz <[email protected]>
* Small optimizations to Python serialization.
Leandro Lucarella <[email protected]>
* VI syntax highlighting tweaks.
* Fix compiler to not make output executable.
Dilip Joseph <[email protected]>
* Heuristic detection of sub-messages when printing unknown fields in
text format.
Brian Atkinson <[email protected]>
* Added @Override annotation to generated Java code where appropriate.
Vincent Choinière <[email protected]>
* Tru64 support.
Monty Taylor <[email protected]>
* Solaris 10 + Sun Studio fixes.
Alek Storm <[email protected]>
* Slicing support for repeated scalar fields for the Python API.
Oleg Smolsky <[email protected]>
* MS Visual Studio error format option.
* Detect unordered_map in stl_hash.m4.
Brian Olson <[email protected]>
* gzip/zlib I/O support.
Michael Poole <[email protected]>
* Fixed warnings about generated constructors not explicitly initializing
all fields (only present with certain compiler settings).
* Added generation of field number constants.
Wink Saville <[email protected]>
* Fixed initialization ordering problem in logging code.
Will Pierce <[email protected]>
* Small patch improving performance of in Python serialization.
Alexandre Vassalotti <[email protected]>
* Emacs mode for Protocol Buffers (editors/protobuf-mode.el).
Scott Stafford <[email protected]>
* Added Swap(), SwapElements(), and RemoveLast() to Reflection interface.
Alexander Melnikov <[email protected]>
* HPUX support.
Oliver Jowett <[email protected]>
* Detect whether zlib is new enough in configure script.
* Fixes for Solaris 10 32/64-bit confusion.
Evan Jones <[email protected]>
* Optimize Java serialization code when writing a small message to a stream.
* Optimize Java serialization of strings so that UTF-8 encoding happens only
once per string per serialization call.
* Clean up some Java warnings.
* Fix bug with permanent callbacks that delete themselves when run.
Michael Kucharski <[email protected]>
* Added CodedInputStream.getTotalBytesRead().
Kacper Kowalik <[email protected]>
* Fixed m4/acx_pthread.m4 problem for some Linux distributions.
-33
View File
@@ -1,33 +0,0 @@
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Code generated by the Protocol Buffer compiler is owned by the owner
of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This
support library is itself covered by the above license.
-237
View File
@@ -1,237 +0,0 @@
This file contains detailed but generic information on building and
installing the C++ part of this project. For shorter instructions,
as well as instructions for compiling and installing the Java or
Python parts, see README.
======================================================================
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
-225
View File
@@ -1,225 +0,0 @@
## Process this file with automake to produce Makefile.in
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = foreign
# Build . before src so that our all-local and clean-local hooks kicks in at
# the right time.
SUBDIRS = . src
# Always include gtest in distributions.
DIST_SUBDIRS = $(subdirs) src
# Build gtest before we build protobuf tests. We don't add gtest to SUBDIRS
# because then "make check" would also build and run all of gtest's own tests,
# which takes a lot of time and is generally not useful to us. Also, we don't
# want "make install" to recurse into gtest since we don't want to overwrite
# the installed version of gtest if there is one.
check-local:
@echo "Making lib/libgtest.a lib/libgtest_main.a in gtest"
@cd gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.la lib/libgtest_main.la
# We would like to clean gtest when "make clean" is invoked. But we have to
# be careful because clean-local is also invoked during "make distclean", but
# "make distclean" already recurses into gtest because it's listed among the
# DIST_SUBDIRS. distclean will delete gtest/Makefile, so if we then try to
# cd to the directory again and "make clean" it will fail. So, check that the
# Makefile exists before recursing.
clean-local:
@if test -e gtest/Makefile; then \
echo "Making clean in gtest"; \
cd gtest && $(MAKE) $(AM_MAKEFLAGS) clean; \
fi
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = protobuf.pc protobuf-lite.pc
EXTRA_DIST = \
autogen.sh \
generate_descriptor_proto.sh \
README.txt \
INSTALL.txt \
COPYING.txt \
CONTRIBUTORS.txt \
CHANGES.txt \
editors/README.txt \
editors/proto.vim \
editors/protobuf-mode.el \
vsprojects/config.h \
vsprojects/extract_includes.bat \
vsprojects/libprotobuf.vcproj \
vsprojects/libprotobuf-lite.vcproj \
vsprojects/libprotoc.vcproj \
vsprojects/protobuf.sln \
vsprojects/protoc.vcproj \
vsprojects/readme.txt \
vsprojects/test_plugin.vcproj \
vsprojects/tests.vcproj \
vsprojects/lite-test.vcproj \
vsprojects/convert2008to2005.sh \
examples/README.txt \
examples/Makefile \
examples/addressbook.proto \
examples/add_person.cc \
examples/list_people.cc \
examples/AddPerson.java \
examples/ListPeople.java \
examples/add_person.py \
examples/list_people.py \
java/src/main/java/com/google/protobuf/AbstractMessage.java \
java/src/main/java/com/google/protobuf/AbstractMessageLite.java \
java/src/main/java/com/google/protobuf/AbstractParser.java \
java/src/main/java/com/google/protobuf/BlockingRpcChannel.java \
java/src/main/java/com/google/protobuf/BlockingService.java \
java/src/main/java/com/google/protobuf/BoundedByteString.java \
java/src/main/java/com/google/protobuf/ByteString.java \
java/src/main/java/com/google/protobuf/CodedInputStream.java \
java/src/main/java/com/google/protobuf/CodedOutputStream.java \
java/src/main/java/com/google/protobuf/Descriptors.java \
java/src/main/java/com/google/protobuf/DynamicMessage.java \
java/src/main/java/com/google/protobuf/ExtensionRegistry.java \
java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
java/src/main/java/com/google/protobuf/FieldSet.java \
java/src/main/java/com/google/protobuf/GeneratedMessage.java \
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java \
java/src/main/java/com/google/protobuf/Internal.java \
java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
java/src/main/java/com/google/protobuf/LazyField.java \
java/src/main/java/com/google/protobuf/LazyStringArrayList.java \
java/src/main/java/com/google/protobuf/LazyStringList.java \
java/src/main/java/com/google/protobuf/LiteralByteString.java \
java/src/main/java/com/google/protobuf/Message.java \
java/src/main/java/com/google/protobuf/MessageLite.java \
java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java \
java/src/main/java/com/google/protobuf/MessageOrBuilder.java \
java/src/main/java/com/google/protobuf/Parser.java \
java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java \
java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java \
java/src/main/java/com/google/protobuf/RopeByteString.java \
java/src/main/java/com/google/protobuf/RpcCallback.java \
java/src/main/java/com/google/protobuf/RpcChannel.java \
java/src/main/java/com/google/protobuf/RpcController.java \
java/src/main/java/com/google/protobuf/RpcUtil.java \
java/src/main/java/com/google/protobuf/ServiceException.java \
java/src/main/java/com/google/protobuf/Service.java \
java/src/main/java/com/google/protobuf/SingleFieldBuilder.java \
java/src/main/java/com/google/protobuf/SmallSortedMap.java \
java/src/main/java/com/google/protobuf/TextFormat.java \
java/src/main/java/com/google/protobuf/UninitializedMessageException.java \
java/src/main/java/com/google/protobuf/UnknownFieldSet.java \
java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java \
java/src/main/java/com/google/protobuf/Utf8.java \
java/src/main/java/com/google/protobuf/WireFormat.java \
java/src/test/java/com/google/protobuf/AbstractMessageTest.java \
java/src/test/java/com/google/protobuf/BoundedByteStringTest.java \
java/src/test/java/com/google/protobuf/ByteStringTest.java \
java/src/test/java/com/google/protobuf/CodedInputStreamTest.java \
java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java \
java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java \
java/src/test/java/com/google/protobuf/DescriptorsTest.java \
java/src/test/java/com/google/protobuf/DynamicMessageTest.java \
java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java \
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java \
java/src/test/java/com/google/protobuf/IsValidUtf8Test.java \
java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java \
java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java \
java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java \
java/src/test/java/com/google/protobuf/LiteralByteStringTest.java \
java/src/test/java/com/google/protobuf/LiteTest.java \
java/src/test/java/com/google/protobuf/MessageTest.java \
java/src/test/java/com/google/protobuf/NestedBuildersTest.java \
java/src/test/java/com/google/protobuf/ParserTest.java \
java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java \
java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java \
java/src/test/java/com/google/protobuf/RopeByteStringTest.java \
java/src/test/java/com/google/protobuf/ServiceTest.java \
java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java \
java/src/test/java/com/google/protobuf/SmallSortedMapTest.java \
java/src/test/java/com/google/protobuf/TestBadIdentifiers.java \
java/src/test/java/com/google/protobuf/TestUtil.java \
java/src/test/java/com/google/protobuf/TextFormatTest.java \
java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java \
java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java \
java/src/test/java/com/google/protobuf/WireFormatTest.java \
java/src/test/java/com/google/protobuf/multiple_files_test.proto \
java/src/test/java/com/google/protobuf/nested_builders_test.proto \
java/src/test/java/com/google/protobuf/nested_extension_lite.proto \
java/src/test/java/com/google/protobuf/nested_extension.proto \
java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto \
java/src/test/java/com/google/protobuf/non_nested_extension.proto \
java/src/test/java/com/google/protobuf/test_bad_identifiers.proto \
java/pom.xml \
java/README.txt \
python/google/protobuf/internal/generator_test.py \
python/google/protobuf/internal/containers.py \
python/google/protobuf/internal/decoder.py \
python/google/protobuf/internal/descriptor_database_test.py \
python/google/protobuf/internal/descriptor_pool_test.py \
python/google/protobuf/internal/descriptor_test.py \
python/google/protobuf/internal/encoder.py \
python/google/protobuf/internal/enum_type_wrapper.py \
python/google/protobuf/internal/factory_test1.proto \
python/google/protobuf/internal/factory_test2.proto \
python/google/protobuf/internal/message_cpp_test.py \
python/google/protobuf/internal/message_factory_test.py \
python/google/protobuf/internal/message_listener.py \
python/google/protobuf/internal/message_test.py \
python/google/protobuf/internal/more_extensions.proto \
python/google/protobuf/internal/more_extensions_dynamic.proto \
python/google/protobuf/internal/more_messages.proto \
python/google/protobuf/internal/python_message.py \
python/google/protobuf/internal/cpp_message.py \
python/google/protobuf/internal/api_implementation.py \
python/google/protobuf/internal/reflection_test.py \
python/google/protobuf/internal/reflection_cpp_generated_test.py \
python/google/protobuf/internal/service_reflection_test.py \
python/google/protobuf/internal/test_bad_identifiers.proto \
python/google/protobuf/internal/test_util.py \
python/google/protobuf/internal/text_format_test.py \
python/google/protobuf/internal/type_checkers.py \
python/google/protobuf/internal/unknown_fields_test.py \
python/google/protobuf/internal/wire_format.py \
python/google/protobuf/internal/wire_format_test.py \
python/google/protobuf/internal/__init__.py \
python/google/protobuf/pyext/python-proto2.cc \
python/google/protobuf/pyext/python_descriptor.cc \
python/google/protobuf/pyext/python_descriptor.h \
python/google/protobuf/pyext/python_protobuf.cc \
python/google/protobuf/pyext/python_protobuf.h \
python/google/protobuf/descriptor.py \
python/google/protobuf/descriptor_database.py \
python/google/protobuf/descriptor_pool.py \
python/google/protobuf/message.py \
python/google/protobuf/message_factory.py \
python/google/protobuf/reflection.py \
python/google/protobuf/service.py \
python/google/protobuf/service_reflection.py \
python/google/protobuf/text_format.py \
python/google/protobuf/__init__.py \
python/google/__init__.py \
python/ez_setup.py \
python/setup.py \
python/mox.py \
python/stubout.py \
python/README.txt
# Deletes all the files generated by autogen.sh.
MAINTAINERCLEANFILES = \
aclocal.m4 \
config.guess \
config.sub \
configure \
depcomp \
install-sh \
ltmain.sh \
Makefile.in \
missing \
mkinstalldirs \
config.h.in \
stamp.h.in \
m4/ltsugar.m4 \
m4/libtool.m4 \
m4/ltversion.m4 \
m4/lt~obsolete.m4 \
m4/ltoptions.m4
File diff suppressed because it is too large Load Diff
-152
View File
@@ -1,152 +0,0 @@
Protocol Buffers - Google's data interchange format
Copyright 2008 Google Inc.
http://code.google.com/apis/protocolbuffers/
C++ Installation - Unix
=======================
To build and install the C++ Protocol Buffer runtime and the Protocol
Buffer compiler (protoc) execute the following:
$ ./configure
$ make
$ make check
$ make install
If "make check" fails, you can still install, but it is likely that
some features of this library will not work correctly on your system.
Proceed at your own risk.
"make install" may require superuser privileges.
For advanced usage information on configure and make, see INSTALL.txt.
** Hint on install location **
By default, the package will be installed to /usr/local. However,
on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
You can add it, but it may be easier to just install to /usr
instead. To do this, invoke configure as follows:
./configure --prefix=/usr
If you already built the package with a different prefix, make sure
to run "make clean" before building again.
** Compiling dependent packages **
To compile a package that uses Protocol Buffers, you need to pass
various flags to your compiler and linker. As of version 2.2.0,
Protocol Buffers integrates with pkg-config to manage this. If you
have pkg-config installed, then you can invoke it to get a list of
flags like so:
pkg-config --cflags protobuf # print compiler flags
pkg-config --libs protobuf # print linker flags
pkg-config --cflags --libs protobuf # print both
For example:
c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf`
Note that packages written prior to the 2.2.0 release of Protocol
Buffers may not yet integrate with pkg-config to get flags, and may
not pass the correct set of flags to correctly link against
libprotobuf. If the package in question uses autoconf, you can
often fix the problem by invoking its configure script like:
configure CXXFLAGS="$(pkg-config --cflags protobuf)" \
LIBS="$(pkg-config --libs protobuf)"
This will force it to use the correct flags.
If you are writing an autoconf-based package that uses Protocol
Buffers, you should probably use the PKG_CHECK_MODULES macro in your
configure script like:
PKG_CHECK_MODULES([protobuf], [protobuf])
See the pkg-config man page for more info.
If you only want protobuf-lite, substitute "protobuf-lite" in place
of "protobuf" in these examples.
** Note for cross-compiling **
The makefiles normally invoke the protoc executable that they just
built in order to build tests. When cross-compiling, the protoc
executable may not be executable on the host machine. In this case,
you must build a copy of protoc for the host machine first, then use
the --with-protoc option to tell configure to use it instead. For
example:
./configure --with-protoc=protoc
This will use the installed protoc (found in your $PATH) instead of
trying to execute the one built during the build process. You can
also use an executable that hasn't been installed. For example, if
you built the protobuf package for your host machine in ../host,
you might do:
./configure --with-protoc=../host/src/protoc
Either way, you must make sure that the protoc executable you use
has the same version as the protobuf source code you are trying to
use it with.
** Note for Solaris users **
Solaris 10 x86 has a bug that will make linking fail, complaining
about libstdc++.la being invalid. We have included a work-around
in this package. To use the work-around, run configure as follows:
./configure LDFLAGS=-L$PWD/src/solaris
See src/solaris/libstdc++.la for more info on this bug.
** Note for HP C++ Tru64 users **
To compile invoke configure as follows:
./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM"
Also, you will need to use gmake instead of make.
C++ Installation - Windows
==========================
If you are using Microsoft Visual C++, see vsprojects/readme.txt.
If you are using Cygwin or MinGW, follow the Unix installation
instructions, above.
Binary Compatibility Warning
============================
Due to the nature of C++, it is unlikely that any two versions of the
Protocol Buffers C++ runtime libraries will have compatible ABIs.
That is, if you linked an executable against an older version of
libprotobuf, it is unlikely to work with a newer version without
re-compiling. This problem, when it occurs, will normally be detected
immediately on startup of your app. Still, you may want to consider
using static linkage. You can configure this package to install
static libraries only using:
./configure --disable-shared
Java and Python Installation
============================
The Java and Python runtime libraries for Protocol Buffers are located
in the java and python directories. See the README file in each
directory for more information on how to compile and install them.
Note that both of them require you to first install the Protocol
Buffer compiler (protoc), which is part of the C++ package.
Usage
=====
The complete documentation for Protocol Buffers is available via the
web at:
http://code.google.com/apis/protocolbuffers/
-1020
View File
File diff suppressed because it is too large Load Diff
-41
View File
@@ -1,41 +0,0 @@
#!/bin/sh
# Run this script to generate the configure script and other files that will
# be included in the distribution. These files are not checked in because they
# are automatically generated.
set -e
# Check that we're being run from the right directory.
if test ! -f src/google/protobuf/stubs/common.h; then
cat >&2 << __EOF__
Could not find source code. Make sure you are running this script from the
root of the distribution tree.
__EOF__
exit 1
fi
# Check that gtest is present. Usually it is already there since the
# directory is set up as an SVN external.
if test ! -e gtest; then
echo "Google Test not present. Fetching gtest-1.5.0 from the web..."
curl http://googletest.googlecode.com/files/gtest-1.5.0.tar.bz2 | tar jx
mv gtest-1.5.0 gtest
fi
set -ex
# Temporary hack: Must change C runtime library to "multi-threaded DLL",
# otherwise it will be set to "multi-threaded static" when MSVC upgrades
# the project file to MSVC 2005/2008. vladl of Google Test says gtest will
# probably change their default to match, then this will be unnecessary.
# One of these mappings converts the debug configuration and the other
# converts the release configuration. I don't know which is which.
sed -i -e 's/RuntimeLibrary="5"/RuntimeLibrary="3"/g;
s/RuntimeLibrary="4"/RuntimeLibrary="2"/g;' gtest/msvc/*.vcproj
# TODO(kenton): Remove the ",no-obsolete" part and fix the resulting warnings.
autoreconf -f -i -Wall,no-obsolete
rm -rf autom4te.cache config.h.in~
exit 0
File diff suppressed because it is too large Load Diff
-149
View File
@@ -1,149 +0,0 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* the name of <hash_map> */
#undef HASH_MAP_CLASS
/* the location of <unordered_map> or <hash_map> */
#undef HASH_MAP_H
/* the namespace of hash_map/hash_set */
#undef HASH_NAMESPACE
/* the name of <hash_set> */
#undef HASH_SET_CLASS
/* the location of <unordered_set> or <hash_set> */
#undef HASH_SET_H
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `ftruncate' function. */
#undef HAVE_FTRUNCATE
/* define if the compiler has hash_map */
#undef HAVE_HASH_MAP
/* define if the compiler has hash_set */
#undef HAVE_HASH_SET
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if you have the `mkdir' function. */
#undef HAVE_MKDIR
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strchr' function. */
#undef HAVE_STRCHR
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strtol' function. */
#undef HAVE_STRTOL
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Enable classes using zlib compression. */
#undef HAVE_ZLIB
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Version number of package */
#undef VERSION
/* Define to 1 if on MINIX. */
#undef _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#undef _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
-1773
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More