!30 fix: 调整videoChat中获取房间人员的逻辑

Merge pull request !30 from 云裂痕/dev
This commit is contained in:
云裂痕
2025-10-20 12:35:42 +00:00
committed by Gitee
204 changed files with 1572 additions and 1079 deletions

View File

@@ -64,6 +64,7 @@ services:
volumes:
- ./rocketmq/broker/logs:/home/rocketmq/logs
- ./rocketmq/broker/store:/home/rocketmq/store
- ./rocketmq/timerwheel:/home/rocketmq/timerwheel
- ./rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.3.2/conf/broker.conf
- ./rocketmq/broker/conf/plain_acl.yml:/home/rocketmq/rocketmq-5.3.2/conf/plain_acl.yml
depends_on:
@@ -94,4 +95,24 @@ services:
volumes:
- /home/jenkins/work:/var/jenkins_home # 数据持久化
- /var/run/docker.sock:/var/run/docker.sock # 宿主机 Docker 控制
- /usr/bin/docker:/usr/bin/docker # 宿主机 Docker 命令
- /usr/bin/docker:/usr/bin/docker # 宿主机 Docker 命令
srs:
image: ossrs/srs:5
container_name: srs
restart: always
ports:
- "1935:1935/tcp" # RTMP 推流
- "1985:1985/tcp" # HTTP API
- "7088:7088/tcp" # H5播放器/信令
- "8000:8000/udp" # WebRTC媒体传输
- "1989:1989/tcp" # WebRTC信令
- "8443:8443/tcp" # HTTPS/WSS
- "61100-61200:61100-61200/udp" # WebRTC动态端口范围
environment:
- CANDIDATE=192.168.1.37 # 公网ip
- SRS_LISTEN=8000 # WebRTC监听端口
- SRS_HTTP_SERVER_PORT=7088
- SRS_HTTP_API_PORT=1985
volumes:
- "/home/docker/srs:/usr/local/srs/conf"
command: [ "./objs/srs", "-c", "conf/srs_conf_7088.conf" ]

View File

@@ -2,10 +2,20 @@
上传目录下的docker文件夹到服务器/home/docker下面, 需要修改env文件夹rocketmq文件夹里面的配置, 特别是[broker.conf](docker/rocketmq/broker/conf/broker.conf)里面brokerIP1的值
```bash
# 授权目录
mkdir /home/docker/rocketmq/broker/conf/ /home/docker/rocketmq/broker/logs/ /home/docker/rocketmq/broker/store/ -p
chmod 777 /home/docker/rocketmq/broker/conf/
chmod 777 /home/docker/rocketmq/broker/logs/
chmod 777 /home/docker/rocketmq/broker/store/
chmod 777 /home/docker/rocketmq/timerwheel/
```
## 🛠️ 启动命令
- **仔细阅读**: docker-compose.yml 的内容redis的密码也在这里面设置的、./env 文件夹下面的内容,里面包含了账号密码等信息
- **打开目录**: 当前文件夹下输入 cmd 回车
- **执行命令**: docker-compose up -d
- **导入nacos数据库**: [mysql-schema.sql](../mysql-schema.sql)
- **导入nacos命名空间数据**: [nacos_config_export_20250816090745.zip](../../nacos/nacos_config_export_20250816090745.zip)
- **导入nacos命名空间数据**: [nacos_config_export_20251019194635.zip](../nacos/nacos_config_export_20251019194635.zip)

View File

@@ -20,7 +20,7 @@ namesrvAddr=rocketmq-namesrv:9876
#启动IP,如果 docker 报 com.alibaba.rocketmq.remoting.exception.RemotingConnectException: connect to <192.168.0.120:10909> failed
# 解决方式1 加上一句producer.setVipChannelEnabled(false);解决方式2 brokerIP1 设置宿主机IP不要使用docker 内部IP
brokerIP1=rocketmq-broker
brokerIP1=192.168.1.37
#在发送消息时自动创建服务器不存在的topic默认创建的队列数
defaultTopicQueueNums=4
@@ -71,14 +71,19 @@ abortFile=/home/rocketmq/store/abort
maxMessageSize=65536
# 延迟消息配置
#timerWheelEnable=false
#enableScheduleMessage=false
timerWheelEnable=true
# 启用延迟消息功能
enableScheduleMessage=true
# 定义延迟级别
messageDelayLevel=1s 3s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
# 确保此目录存在且可写
#timerStorePath=/home/rocketmq/store/timerwheel
#timerFlushIntervalMs=1000
#timerPrecisionMs=1000
#scheduleMessageServiceThreadPoolNums=4
timerStorePath=/home/docker/rocketmq/timerwheel
# 时间轮刷新间隔
timerFlushIntervalMs=1000
# 时间轮精度
timerPrecisionMs=1000
# 调度消息服务线程数
scheduleMessageServiceThreadPoolNums=4
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2

View File

@@ -1,33 +1,64 @@
# 基础运行配置
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
# 低延迟优化
vhost __defaultVhost__ {
tcp_nodelay on;
min_latency on;
}
# HTTP API 服务(用于服务器状态管理)
http_api {
enabled on;
listen 1985;
crossdomain on;
}
# HTTP 服务器用于H5播放器拉流
http_server {
enabled on;
listen 7088;
dir ./objs/nginx/html;
}
# WebRTC 信令服务器配置
rtc_server {
enabled on;
listen 8000;
candidate 公网ip;
listen 8000; # WebRTC信令端口
candidate 192.168.1.37; # 公网IP
}
# 虚拟主机配置
vhost __defaultVhost__ {
# WebRTC 模式配置
rtc {
enabled on;
rtmp_to_rtc on;
rtc_to_rtmp on;
# 关闭 RTMP 转 WebRTC避免强制中转因为要实现P2P打视频
rtmp_to_rtc off; # on表示支持RTMP推流转WebRTC播放
rtc_to_rtmp off; # on表示支持WebRTC推流转RTMP播放
# P2P模式必须开启NACK
nack on;
# 开启TWCC带宽估计
twcc on;
}
# HTTP-FLV 流配置
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
mount [vhost]/webrtc/;
}
# HLS 流配置(用于兼容性)
hls {
enabled off;
}
# 低延迟播放配置
play {
gop_cache off; # 关闭GOP缓存降低延迟
queue_length 10; # 减小播放队列长度
}
}

View File

@@ -20,6 +20,12 @@ no-tcp6
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
dh-file=/etc/coturn/dhparam.pem
# 认证配置(使用长期凭证)
verbose
fingerprint
lt-cred-mech
# Coturn TURN SERVER configuration file
#
# Boolean values note: where boolean value is supposed to be used,

View File

@@ -77,7 +77,12 @@ turnserver -a -o -f -r hulaspark.com
```
### 6. 测试服务
测试地址https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
host 本地直连测试,用在局域网
srflx公网直连也叫打洞测试不过图中只有一个srflx返回正常应该有两个
relay是中继测试我们这次测试意思就是我们所在网络使用中继模式才能成功
![img_13.png](../image/img_13.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@@ -25,6 +25,7 @@ services:
volumes:
- ./rocketmq/broker/logs:/home/rocketmq/logs
- ./rocketmq/broker/store:/home/rocketmq/store
- ./rocketmq/timerwheel:/home/rocketmq/timerwheel
- ./rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.3.2/conf/broker.conf
- ./rocketmq/broker/conf/plain_acl.yml:/home/rocketmq/rocketmq-5.3.2/conf/plain_acl.yml
depends_on:

View File

@@ -71,14 +71,19 @@ abortFile=/home/rocketmq/store/abort
maxMessageSize=65536
# 延迟消息配置
#timerWheelEnable=false
#enableScheduleMessage=false
timerWheelEnable=true
# 启用延迟消息功能
enableScheduleMessage=true
# 定义延迟级别
messageDelayLevel=1s 3s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
# 确保此目录存在且可写
#timerStorePath=/home/rocketmq/store/timerwheel
#timerFlushIntervalMs=1000
#timerPrecisionMs=1000
#scheduleMessageServiceThreadPoolNums=4
timerStorePath=/home/docker/rocketmq/timerwheel
# 时间轮刷新间隔
timerFlushIntervalMs=1000
# 时间轮精度
timerPrecisionMs=1000
# 调度消息服务线程数
scheduleMessageServiceThreadPoolNums=4
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2

View File

@@ -11,7 +11,7 @@
Target Server Version : 80030 (8.0.30)
File Encoding : 65001
Date: 11/10/2025 18:27:50
Date: 20/10/2025 17:27:06
*/
SET NAMES utf8mb4;
@@ -1126,15 +1126,6 @@ CREATE TABLE `def_login_log` (
-- ----------------------------
-- Records of def_login_log
-- ----------------------------
INSERT INTO `def_login_log` VALUES (83160717456896, NULL, NULL, NULL, '192.168.1.37', '', '1046762075', '04', '用户不存在!', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 11:31:00', NULL, '2025-10-11 11:31:00', NULL, 0);
INSERT INTO `def_login_log` VALUES (83160742622720, NULL, NULL, NULL, '192.168.1.37', '', 'Dawn', '04', '用户不存在!', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 11:31:06', NULL, '2025-10-11 11:31:06', NULL, 0);
INSERT INTO `def_login_log` VALUES (83160776177152, NULL, 10937855681024, 61170828519937, '192.168.1.37', 'Dawn', '2439646234', '01', '登录成功', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 11:31:15', 61170828519937, '2025-10-11 11:31:15', NULL, 0);
INSERT INTO `def_login_log` VALUES (83161032029696, NULL, 10937855681024, 61170828519937, '192.168.1.37', 'Dawn', '2439646234', '01', '登录成功', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 11:32:15', 61170828519937, '2025-10-11 11:32:15', NULL, 0);
INSERT INTO `def_login_log` VALUES (83162239989248, NULL, 10937855681024, 61170828519937, '192.168.1.37', 'Dawn', '2439646234', '01', '登录成功', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 11:37:04', 61170828519937, '2025-10-11 11:37:04', NULL, 0);
INSERT INTO `def_login_log` VALUES (83263746340352, NULL, NULL, NULL, '192.168.1.37', '', '1046762075', '04', '用户不存在!', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 18:20:24', NULL, '2025-10-11 18:20:24', NULL, 0);
INSERT INTO `def_login_log` VALUES (83265226929664, NULL, NULL, NULL, '192.168.1.37', '', '1046762075', '04', '用户不存在!', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 18:26:17', NULL, '2025-10-11 18:26:17', NULL, 0);
INSERT INTO `def_login_log` VALUES (83265235318272, NULL, NULL, NULL, '192.168.1.37', '', '1046762075', '04', '用户不存在!', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 18:26:20', NULL, '2025-10-11 18:26:20', NULL, 0);
INSERT INTO `def_login_log` VALUES (83265403090432, NULL, 10937855681024, 61170828519937, '192.168.1.37', 'Dawn', '2439646234', '01', '登录成功', '2025-10-11', 'ReactorNetty/1.2.2', 'Unknown', '', 'Unknown', '0|0|0|内网IP|内网IP', '2025-10-11 18:27:00', 61170828519937, '2025-10-11 18:27:00', NULL, 0);
-- ----------------------------
-- Table structure for def_msg_template
@@ -1802,7 +1793,7 @@ CREATE TABLE `def_user` (
-- Records of def_user
-- ----------------------------
INSERT INTO `def_user` VALUES (61170828519936, 2, 'bot', 'HuLa小管家', '', '022', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.139', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": null, \"updateIpDetail\": null}', '2025-08-19 10:05:05', 1, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-07-07 15:27:02', 1, '2025-03-27 04:23:08', NULL, '2025-07-16 12:26:15', 0, 1);
INSERT INTO `def_user` VALUES (61170828519937, 2, '2439646234', 'Dawn', '2439646234@qq.com', 'https://cdn.hulaspark.com/avatar/2439646234/6ec99d37b8ba1296c325d2d36b46a14d.webp', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.189', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"192.168.1.37\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"192.168.1.37\", \"isp\": \"内网IP\", \"area\": \"\", \"city\": \"内网IP\", \"isp_id\": \"local\", \"region\": \"\", \"city_id\": \"local\", \"country\": \"\", \"region_id\": \"\", \"country_id\": \"\"}}', NULL, 0, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-10-11 18:27:00', 1, '2025-03-27 04:23:08', NULL, '2025-10-11 18:27:00', 0, 1);
INSERT INTO `def_user` VALUES (61170828519937, 2, '2439646234', 'Dawn', '2439646234@qq.com', 'https://cdn.hulaspark.com/avatar/2439646234/6ec99d37b8ba1296c325d2d36b46a14d.webp', NULL, NULL, '', NULL, b'0', '', '', '1', b'1', '', '2025-08-11 11:11:03.189', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"192.168.1.26\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"192.168.1.26\", \"isp\": \"内网IP\", \"area\": \"\", \"city\": \"内网IP\", \"isp_id\": \"local\", \"region\": \"\", \"city_id\": \"local\", \"country\": \"\", \"region_id\": \"\", \"country_id\": \"\"}}', NULL, 0, NULL, 'a4d5c225e6709ba025272a31c7e90e0121d5e5ba16695afe0b61370bedb677d0', 'Dawn', '2025-10-20 16:12:56', 1, '2025-03-27 04:23:08', NULL, '2025-10-20 16:25:36', 0, 1);
-- ----------------------------
-- Table structure for def_user_application
@@ -1887,7 +1878,7 @@ CREATE TABLE `extend_interface_log` (
-- Records of extend_interface_log
-- ----------------------------
INSERT INTO `extend_interface_log` VALUES (66567882983426, 244439130119864323, '阿里短信', 0, 1, '2025-08-26 16:37:01', '2025-08-26 16:37:00', NULL, '2025-08-26 16:37:00', NULL, 0, 0);
INSERT INTO `extend_interface_log` VALUES (655249535051914248, 244881451621810192, '腾讯邮件', 222, 37, '2025-10-10 09:11:17', '2025-07-16 18:41:01', NULL, '2025-07-16 18:41:01', NULL, 0, 0);
INSERT INTO `extend_interface_log` VALUES (655249535051914248, 244881451621810192, '腾讯邮件', 340, 51, '2025-10-20 12:13:08', '2025-07-16 18:41:01', NULL, '2025-07-16 18:41:01', NULL, 0, 0);
-- ----------------------------
-- Table structure for extend_interface_logging
@@ -2031,6 +2022,39 @@ CREATE TABLE `secure_invoke_record` (
-- Records of secure_invoke_record
-- ----------------------------
-- ----------------------------
-- Table structure for sys_model
-- ----------------------------
DROP TABLE IF EXISTS `sys_model`;
CREATE TABLE `sys_model` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`model_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型唯一键',
`model_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型名称',
`model_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型文件URL',
`description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模型描述',
`version` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模型版本号',
`status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态0-禁用1-启用',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
`create_by` bigint NOT NULL DEFAULT 1 COMMENT '创建者',
`update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_model_key`(`model_key` ASC) USING BTREE,
INDEX `idx_model_name`(`model_name` ASC) USING BTREE,
INDEX `idx_status`(`status` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统模型表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_model
-- ----------------------------
INSERT INTO `sys_model` VALUES (1, 'hula-20251022', 'HuLa_模型', 'https://cdn.hulaspark.com/models/hula.glb', 'HuLa 模型基础模型', '20251022', 1, '2025-10-20 04:09:29', '2025-10-20 06:08:10', 1, 0, 1, NULL);
INSERT INTO `sys_model` VALUES (2, 't1_yongen', 't1_永恩', 'https://cdn.hulaspark.com/models/t1_%E6%B0%B8%E6%81%A9.glb', 'T1战队主题永恩模型', '20251022', 1, '2025-10-20 06:00:24', NULL, 1, 0, 1, NULL);
INSERT INTO `sys_model` VALUES (3, 'sea_devil_aatrox', '海魔至尊_亚托克斯', 'https://cdn.hulaspark.com/models/%E6%B5%B7%E9%AD%94%E8%87%B3%E5%B0%8A_%E4%BA%9A%E6%89%98%E5%85%8B%E6%96%AF.glb', '海魔至尊主题亚托克斯模型', '20251022', 1, '2025-10-20 06:00:24', NULL, 1, 0, 1, NULL);
INSERT INTO `sys_model` VALUES (4, 'victory_sona', '胜利女神_娑娜', 'https://cdn.hulaspark.com/models/%E8%83%9C%E5%88%A9%E5%A5%B3%E7%A5%9E_%E5%A8%91%E5%A8%9C.glb', '胜利女神主题娑娜模型', '20251022', 1, '2025-10-20 06:00:24', NULL, 1, 0, 1, NULL);
INSERT INTO `sys_model` VALUES (5, 'ultimate_miss_fortune', '至臻_绝息圣堂_厄运小姐', 'https://cdn.hulaspark.com/models/%E8%87%B3%E8%87%BB_%E7%BB%9D%E6%81%AF%E5%9C%A3%E5%A0%82_%E5%8E%84%E8%BF%90%E5%B0%8F%E5%A7%90.glb', '至臻绝息圣堂主题厄运小姐模型', '20251022', 1, '2025-10-20 06:00:24', NULL, 1, 0, 1, NULL);
-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
@@ -2068,15 +2092,10 @@ CREATE TABLE `worker_node` (
`created` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`is_del` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 765 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 845 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of worker_node
-- ----------------------------
INSERT INTO `worker_node` VALUES (760, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153290834-59563', 2, '2025-10-11', '2025-10-11 11:28:11', '2025-10-11 11:28:11', 0);
INSERT INTO `worker_node` VALUES (761, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153295768-6425', 2, '2025-10-11', '2025-10-11 11:28:16', '2025-10-11 11:28:16', 0);
INSERT INTO `worker_node` VALUES (762, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153296437-43886', 2, '2025-10-11', '2025-10-11 11:28:16', '2025-10-11 11:28:16', 0);
INSERT INTO `worker_node` VALUES (763, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153304108-67251', 2, '2025-10-11', '2025-10-11 11:28:24', '2025-10-11 11:28:24', 0);
INSERT INTO `worker_node` VALUES (764, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153319987-85683', 2, '2025-10-11', '2025-10-11 11:28:40', '2025-10-11 11:28:40', 0);
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -11,7 +11,7 @@
Target Server Version : 80030 (8.0.30)
File Encoding : 65001
Date: 11/10/2025 18:27:42
Date: 20/10/2025 17:27:01
*/
SET NAMES utf8mb4;
@@ -412,7 +412,7 @@ CREATE TABLE `im_announcements` (
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 1,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82552736018433 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '聊天公告表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 84990645864449 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_ci COMMENT = '聊天公告表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_announcements
@@ -489,14 +489,14 @@ CREATE TABLE `im_contact` (
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE,
INDEX `idx_contact_room_uid_hide`(`room_id` ASC, `uid` ASC, `hide` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 69082079229806 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会话列表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 69082079587433 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会话列表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_contact
-- ----------------------------
INSERT INTO `im_contact` VALUES (10937855681025, 10937855681024, 1, 0, 0, '2025-10-11 18:27:03.193', 1, 0, '2025-10-10 18:46:37.156', 82907955820032, '2025-03-27 04:23:08.420', '2025-10-11 18:27:03.194', 1, 0, 61170828519937, 0);
INSERT INTO `im_contact` VALUES (10937855681025, 10937855681024, 1, 0, 0, '2025-10-11 11:38:14.092', 1, 0, '2025-10-10 18:46:37.156', 82907955820032, '2025-03-27 04:23:08.420', '2025-10-11 11:38:14.092', 1, 0, 61170828519937, 0);
INSERT INTO `im_contact` VALUES (10937855681525, 1, 1, 0, 0, '2025-07-07 14:49:04.239', 1, 0, '2025-10-10 18:46:37.156', 82907955820032, '2025-03-27 04:23:08.420', '2025-10-10 10:46:38.197', 1, 0, NULL, 0);
INSERT INTO `im_contact` VALUES (10937855681526, 10937855681024, 11229133317122, 0, 0, '2025-10-11 11:58:14.001', 1, 0, '2025-10-10 18:46:37.156', 82907955820032, '2025-03-27 04:23:08.420', '2025-10-11 11:58:14.001', 1, 0, 61170828519937, 0);
INSERT INTO `im_contact` VALUES (10937855681526, 10937855681024, 11229133317122, 0, 0, '2025-10-11 11:38:15.691', 1, 0, '2025-10-10 18:46:37.156', 82907955820032, '2025-03-27 04:23:08.420', '2025-10-11 11:38:15.692', 1, 0, 61170828519937, 0);
-- ----------------------------
-- Table structure for im_feed
@@ -579,7 +579,7 @@ CREATE TABLE `im_group_invite` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_invitee_state`(`invitee_uid` ASC, `state` ASC) USING BTREE,
INDEX `idx_group`(`group_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 62581624628737 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '群组邀请记录表' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 62581624628737 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '群组邀请记录表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_group_invite
@@ -609,7 +609,7 @@ CREATE TABLE `im_group_member` (
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE,
INDEX `idx_group_member_uid_isdel_groupid`(`uid` ASC, `is_del` ASC, `group_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82522826436610 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群成员表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86501702603272 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群成员表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_group_member
@@ -672,7 +672,7 @@ CREATE TABLE `im_message` (
INDEX `idx_from_uid`(`from_uid` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82910984107521 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86500645638657 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_message
@@ -702,7 +702,7 @@ CREATE TABLE `im_message_mark` (
INDEX `idx_uid`(`uid` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82582746263553 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息标记表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86186840395265 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息标记表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_message_mark
@@ -718,9 +718,9 @@ CREATE TABLE `im_notice` (
`type` tinyint NOT NULL DEFAULT 1 COMMENT '通知类型 1群聊 2加好友',
`sender_id` bigint NOT NULL COMMENT '发起人UID',
`receiver_id` bigint NOT NULL COMMENT '接收人UID',
`room_id` bigint NOT NULL COMMENT '房间ID',
`apply_id` bigint NULL DEFAULT NULL COMMENT '申请ID',
`operate_id` bigint NOT NULL COMMENT '房间ID',
`name` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '0' COMMENT '群昵称',
`content` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '0' COMMENT '通知消息 [申请时填写]',
`status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '处理状态:0-未处理;1-已同意;2-已拒绝',
`is_read` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否已读',
@@ -734,7 +734,7 @@ CREATE TABLE `im_notice` (
INDEX `idx_receiver_type`(`receiver_id` ASC, `event_type` ASC) USING BTREE,
INDEX `idx_sender`(`sender_id` ASC) USING BTREE,
INDEX `idx_related`(`apply_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 83150193654275 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86491313312259 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_notice
@@ -784,13 +784,12 @@ CREATE TABLE `im_room` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82522826436611 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '房间表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86501702603265 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '房间表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_room
-- ----------------------------
INSERT INTO `im_room` VALUES (1, 1, 1, '2025-10-10 18:46:37.156', 82907955820032, NULL, '2024-07-10 11:17:15.521', '2025-10-10 10:46:37.155', 1, 1, NULL, 0);
INSERT INTO `im_room` VALUES (11229133317122, 2, 0, '2025-10-10 18:46:37.156', 82907955820032, NULL, '2024-07-10 11:17:15.521', '2025-10-11 03:35:25.988', 1, 1, NULL, 0);
INSERT INTO `im_room` VALUES (1, 1, 1, '2025-10-20 16:42:41.743', 86500645638656, NULL, '2024-07-10 11:17:15.521', '2025-10-20 08:42:41.629', 1, 1, NULL, 0);
-- ----------------------------
-- Table structure for im_room_friend
@@ -815,7 +814,7 @@ CREATE TABLE `im_room_friend` (
INDEX `idx_room_id`(`room_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82522826436612 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '单聊房间表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86432953765380 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '单聊房间表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_room_friend
@@ -844,7 +843,7 @@ CREATE TABLE `im_room_group` (
INDEX `idx_room_id`(`room_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 74879168766467 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群聊房间表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86501702603267 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '群聊房间表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_room_group
@@ -901,7 +900,7 @@ CREATE TABLE `im_user` (
`user_id` bigint NOT NULL DEFAULT 3 COMMENT 'def_user 的id',
`user_type` tinyint NOT NULL DEFAULT 3 COMMENT '1: 系统用户2机器人3普通用户',
`name` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户昵称',
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户头像',
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '用户头像',
`email` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '用户邮箱',
`account` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '用户账号',
`sex` int NULL DEFAULT NULL COMMENT '性别 1为男性2为女性',
@@ -927,13 +926,13 @@ CREATE TABLE `im_user` (
INDEX `idx_update_time`(`update_time` ASC) USING BTREE,
INDEX `idx_active_status_last_opt_time`(`last_opt_time` ASC) USING BTREE,
INDEX `account_UNIQUE`(`account` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82522826436609 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86432953765377 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_user
-- ----------------------------
INSERT INTO `im_user` VALUES (1, 61170828519936, 2, 'HuLa小管家', '022', '', 'bot', NULL, '', 17, '2025-07-07 15:27:01.711', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": {\"ip\": \"206.237.119.215\", \"isp\": \"\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"\", \"region\": \"\", \"city_id\": \"\", \"country\": \"美国\", \"region_id\": \"\", \"country_id\": \"US\"}, \"updateIpDetail\": {\"ip\": \"120.231.232.41\", \"isp\": \"移动\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"100025\", \"region\": \"广东\", \"city_id\": \"\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-09-17 02:34:06.481', 'k.23772439646234', 0, NULL, 0, '2025-05-09 18:24:37.089', 99978, 0, 1);
INSERT INTO `im_user` VALUES (10937855681024, 61170828519937, 3, 'Dawn', 'https://cdn.hulaspark.com/avatar/2439646234/97320189485dca88dcc7a70054445a56.webp', '2439646234@qq.com', '2439646234', NULL, '', 4, '2025-07-30 15:31:57.651', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"192.168.1.37\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"192.168.1.37\", \"isp\": \"内网IP\", \"area\": \"\", \"city\": \"内网IP\", \"isp_id\": \"local\", \"region\": \"\", \"city_id\": \"local\", \"country\": \"\", \"region_id\": \"\", \"country_id\": \"\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-11 10:27:11.457', 'k.2439646234', 0, NULL, 0, '2025-09-20 21:35:31.415', 99978, 0, 1);
INSERT INTO `im_user` VALUES (1, 61170828519936, 2, 'HuLa小管家', '022', '', 'bot', NULL, '', 0, '2025-07-07 15:27:01.711', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"120.231.232.41\", \"createIpDetail\": {\"ip\": \"206.237.119.215\", \"isp\": \"\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"\", \"region\": \"\", \"city_id\": \"\", \"country\": \"美国\", \"region_id\": \"\", \"country_id\": \"US\"}, \"updateIpDetail\": {\"ip\": \"120.231.232.41\", \"isp\": \"移动\", \"area\": \"\", \"city\": \"\", \"isp_id\": \"100025\", \"region\": \"广东\", \"city_id\": \"\", \"country\": \"中国\", \"region_id\": \"440000\", \"country_id\": \"CN\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-11 10:14:24.150', 'k.23772439646234', 0, NULL, 0, '2025-05-09 18:24:37.089', 99978, 0, 1);
INSERT INTO `im_user` VALUES (10937855681024, 61170828519937, 3, 'Dawn', 'https://cdn.hulaspark.com/avatar/2439646234/97320189485dca88dcc7a70054445a56.webp', '2439646234@qq.com', '2439646234', NULL, '', 26, '2025-07-30 15:31:57.651', '{\"createIp\": \"206.237.119.215\", \"updateIp\": \"192.168.1.26\", \"createIpDetail\": null, \"updateIpDetail\": {\"ip\": \"192.168.1.26\", \"isp\": \"内网IP\", \"area\": \"\", \"city\": \"内网IP\", \"isp_id\": \"local\", \"region\": \"\", \"city_id\": \"local\", \"country\": \"\", \"region_id\": \"\", \"country_id\": \"\"}}', 6, 0, '', '2025-03-27 04:23:08.393', '2025-10-20 14:27:30.170', 'k.2439646234', 0, NULL, 0, '2025-09-20 21:35:31.415', 99978, 0, 1);
-- ----------------------------
-- Table structure for im_user_apply
@@ -962,7 +961,7 @@ CREATE TABLE `im_user_apply` (
INDEX `idx_target_id`(`target_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82880386659841 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户申请表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86491313312257 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户申请表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_user_apply
@@ -989,7 +988,7 @@ CREATE TABLE `im_user_backpack` (
INDEX `idx_uid`(`uid` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82522826436619 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户背包表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86432953765387 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户背包表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_user_backpack
@@ -1032,7 +1031,7 @@ CREATE TABLE `im_user_emoji` (
`update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
PRIMARY KEY (`id`) USING BTREE,
INDEX `IDX_USER_EMOJIS_UID`(`uid` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 80580641386497 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表情包' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 85336302651905 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表情包' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_user_emoji
@@ -1065,7 +1064,7 @@ CREATE TABLE `im_user_friend` (
INDEX `idx_uid_friend_uid`(`uid` ASC, `friend_uid` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE,
INDEX `idx_update_time`(`update_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82881355544066 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户联系人表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86489446846978 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户联系人表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of im_user_friend
@@ -1243,7 +1242,7 @@ CREATE TABLE `secure_invoke_record` (
`is_del` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_next_retry_time`(`next_retry_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 82910984107522 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '本地消息表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 86500645638658 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '本地消息表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of secure_invoke_record
@@ -1262,12 +1261,10 @@ CREATE TABLE `worker_node` (
`modified` timestamp NULL DEFAULT NULL COMMENT '修改时间',
`created` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 192 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 202 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'DB;WorkerID Assigner for UID Generator' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of worker_node
-- ----------------------------
INSERT INTO `worker_node` VALUES (190, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153294125-92616', 2, '2025-10-11', '2025-10-11 11:28:14', '2025-10-11 11:28:14');
INSERT INTO `worker_node` VALUES (191, '240e:3b3:30b4:1f60:d382:ae04:eb18:d48', '1760153797714-77047', 2, '2025-10-11', '2025-10-11 11:36:38', '2025-10-11 11:36:38');
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -2,6 +2,8 @@
上传目录下的docker文件夹到服务器/home/docker下面, 需要修改env文件夹rocketmq文件夹里面的配置, 特别是[broker.conf](docker/rocketmq/broker/conf/broker.conf)里面brokerIP1的值
## 🛠️ 注册时需要的邮箱功能
- **配置邮箱密钥**: ![login.png](image/login.png)
## 🛠️ 启动命令
- **提高权限**: sudo chmod -R 777 /home/docker/rocketmq

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
</parent>
<artifactId>luohuo-ai-controller</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
</parent>
<artifactId>luohuo-ai-entity</artifactId>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-ai</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
</parent>
<artifactId>luohuo-ai-facade</artifactId>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-ai</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../luohuo-dependencies-parent/pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-base</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -35,7 +35,6 @@ import java.util.Collection;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class DefDictItemServiceImpl extends SuperServiceImpl<DefDictManager, Long, DefDict> implements DefDictItemService {
private final CachePlusOps cachePlusOps;

View File

@@ -216,15 +216,16 @@ public class DefUserServiceImpl extends SuperCacheServiceImpl<DefUserManager, Lo
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updatePassword(DefUserPasswordUpdateVO data) {
// ArgumentAssert.notEmpty(data.getOldPassword(), "请输入旧密码");
ArgumentAssert.notEmpty(data.getOldPassword(), "请输入旧密码");
DefUser user = superManager.getUserByEmail(2, data.getEmail());
ArgumentAssert.notNull(user, "用户不存在");
// ArgumentAssert.equals(user.getId(), ContextUtil.getUid(), "只能修改自己的密码");
ArgumentAssert.equals(user.getId(), ContextUtil.getUid(), "只能修改自己的密码");
// String oldPassword = SecureUtil.sha256(data.getOldPassword() + user.getSalt());
// ArgumentAssert.equals(user.getPassword(), oldPassword, "旧密码错误");
CacheKey cacheKey = new CaptchaCacheKeyBuilder().key(data.getEmail(), data.getKey());
CacheResult<String> code = cacheOps.get(cacheKey);
ArgumentAssert.equals(code.getValue(), data.getCode(), "验证码不正确");
cacheOps.del(cacheKey);
return updateUserPassword(user.getId(), data.getPassword(), user.getSalt());
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-base</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-base</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-base-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-base-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-base-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-base</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-base</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../luohuo-dependencies-parent/pom.xml</relativePath>
</parent>

View File

@@ -6,13 +6,13 @@
<parent>
<groupId>com.luohuo.basic</groupId>
<artifactId>luohuo-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath/>
</parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
@@ -21,8 +21,8 @@
<description>luohuo项目业务父pom</description>
<url>https://gitee.com/HuLaSpark/HuLa-Server</url>
<properties>
<luohuo-util.version>2.6.15</luohuo-util.version>
<luohuo-project.version>2.6.15</luohuo-project.version>
<luohuo-util.version>3.0.0</luohuo-util.version>
<luohuo-project.version>3.0.0</luohuo-project.version>
<docker.image.prefix>hula</docker.image.prefix>
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
</properties>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-gateway</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-gateway</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../luohuo-dependencies-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-generator</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -22,7 +22,7 @@ public class ProjectUtilsTest {
vo.setParent("com.luohuo.flex");
vo.setGroupId("com.luohuo.flex");
vo.setUtilParent("com.luohuo.basic");
vo.setVersion("2.6.15");
vo.setVersion("3.0.0");
vo.setDescription("测试服务");
vo.setServerPort(8080);
ProjectUtils.generator(vo, new DatabaseProperties());

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-generator</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-generator</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-generator</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../luohuo-dependencies-parent/pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-im</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -129,12 +129,6 @@
<artifactId>luohuo-im-cloud-impl</artifactId>
<version>${luohuo-project.version}</version>
</dependency>
<dependency>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-presence-cloud-impl</artifactId>
<version>${luohuo-project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,30 +0,0 @@
package com.luohuo.flex.im.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.stream.Stream;
/**
* 幂等类型 TODO 需要删除
* @author nyh
*/
@AllArgsConstructor
@Getter
public enum LoginTypeEnum {
PC("pc", "PC端"),
MOBILE("mobile", "移动端"),
;
private final String type;
private final String desc;
public static LoginTypeEnum match(String val, LoginTypeEnum def) {
return Stream.of(values()).parallel().filter((item) -> item.getType().equals(val)).findAny().orElse(def);
}
public static LoginTypeEnum get(String val) {
return match(val, null);
}
}

View File

@@ -1,6 +1,6 @@
package com.luohuo.flex.im.common.event.listener;
import com.luohuo.flex.im.api.PresenceApi;
import com.luohuo.flex.common.OnlineService;
import com.luohuo.flex.im.common.event.GroupMemberAddEvent;
import com.luohuo.flex.im.core.chat.dao.GroupMemberDao;
import com.luohuo.flex.im.core.chat.service.adapter.MemberAdapter;
@@ -33,7 +33,7 @@ public class GroupMemberAddListener {
private UserCache userCache;
private GroupMemberDao groupMemberDao;
private GroupMemberCache groupMemberCache;
private PresenceApi presenceApi;
private OnlineService onlineService;
private PushService pushService;
/**
@@ -47,7 +47,7 @@ public class GroupMemberAddListener {
Long roomId = event.getRoomId();
List<Long> memberUidList = groupMemberCache.getMemberExceptUidList(roomId);
// 在线的用户
List<Long> onlineUids = presenceApi.getGroupOnlineMembers(roomId).getData();
List<Long> onlineUids = onlineService.getGroupOnlineMembers(roomId);
Map<Long, User> map = userCache.getBatch(event.getMemberList());
List<ChatMember> memberResps = groupMemberDao.getMemberListByUid(event.getMemberList());

View File

@@ -1,6 +1,7 @@
package com.luohuo.flex.im.common.event.listener;
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
import com.luohuo.flex.im.core.user.service.cache.UserCache;
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -30,6 +31,8 @@ public class ItemReceiveListener {
private UserDao userDao;
@Resource
private ItemCache itemCache;
@Resource
private UserCache userCache;
@Resource
private UserSummaryCache userSummaryCache;
@@ -47,6 +50,7 @@ public class ItemReceiveListener {
User user = userDao.getById(userBackpack.getUid());
if (Objects.isNull(user.getItemId())) {
userDao.wearingBadge(userBackpack.getUid(), userBackpack.getItemId());
userCache.delete(userBackpack.getUid());
userSummaryCache.delete(userBackpack.getUid());
}
}

View File

@@ -30,7 +30,6 @@ public class MessageRecallListener {
@TransactionalEventListener(classes = MessageRecallEvent.class, fallbackExecution = true)
public void evictMsg(MessageRecallEvent event) {
ChatMsgRecallDTO recallDTO = event.getRecallDTO();
// msgCache.evictMsg(recallDTO.getMsgId());
msgCache.delete(recallDTO.getMsgId());
}

View File

@@ -0,0 +1,50 @@
package com.luohuo.flex.im.core.chat.consumer;
import com.luohuo.basic.cache.repository.CachePlusOps;
import com.luohuo.flex.common.cache.PassageMsgCacheKeyBuilder;
import com.luohuo.flex.common.constant.MqConstant;
import com.luohuo.flex.im.core.chat.dao.ContactDao;
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
import com.luohuo.flex.im.domain.entity.Message;
import com.luohuo.flex.model.ws.AckMessageDTO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 目前架构ws服务无法处理业务客户端回执给ws服务之后进行mq跳转至此
* @author 乾乾
*/
@Slf4j
@RocketMQMessageListener(consumerGroup = MqConstant.MSG_PUSH_ACK_TOPIC_GROUP, topic = MqConstant.MSG_PUSH_ACK_TOPIC, messageModel = MessageModel.CLUSTERING)
@Component
@AllArgsConstructor
public class AckConsumer implements RocketMQListener<AckMessageDTO> {
private MsgCache msgCache;
private ContactDao contactDao;
private CachePlusOps cachePlusOps;
/**
* 通过mq的方式 回调进行回执
* @param dto
*/
@Override
public void onMessage(AckMessageDTO dto) {
Message message = msgCache.get(dto.getMsgId());
if(message == null){
return;
}
// 1. 更新收到消息的状态
contactDao.refreshOrCreateActiveTime(message.getRoomId(), Arrays.asList(dto.getUid()), message.getId(), message.getCreateTime());
// 2. 删除在途消息
cachePlusOps.sRem(PassageMsgCacheKeyBuilder.build(dto.getUid()), message.getId());
}
}

View File

@@ -1,8 +1,10 @@
package com.luohuo.flex.im.core.chat.consumer;
import com.luohuo.basic.cache.repository.CachePlusOps;
import com.luohuo.basic.context.ContextUtil;
import com.luohuo.flex.common.OnlineService;
import com.luohuo.flex.common.cache.PassageMsgCacheKeyBuilder;
import com.luohuo.flex.common.constant.MqConstant;
import com.luohuo.flex.im.core.chat.dao.ContactDao;
import com.luohuo.flex.im.core.chat.dao.MessageDao;
import com.luohuo.flex.im.core.chat.dao.RoomDao;
import com.luohuo.flex.im.core.chat.dao.RoomFriendDao;
@@ -27,15 +29,18 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/**
* 发送消息更新房间收信箱,并同步给房间成员信箱
* 加入 在途消息缓存,三秒没有回执则再次推送
* @author 乾乾
*/
@Slf4j
@@ -50,8 +55,9 @@ public class MsgSendConsumer implements RocketMQListener<MsgSendMessageDTO> {
private RoomDao roomDao;
private GroupMemberCache groupMemberCache;
private RoomFriendDao roomFriendDao;
private ContactDao contactDao;
private OnlineService onlineService;
private PushService pushService;
private CachePlusOps cachePlusOps;
@Override
public void onMessage(MsgSendMessageDTO dto) {
@@ -74,8 +80,8 @@ public class MsgSendConsumer implements RocketMQListener<MsgSendMessageDTO> {
memberUidList.add(roomFriend.getUid2());
}
// 2. 更新所有群成员的会话时间, 并推送房间成
contactDao.refreshOrCreateActiveTime(room.getId(), memberUidList, message.getId(), message.getCreateTime());
// 2. 过滤出在线的人
Set<Long> onlineUsersList = onlineService.getOnlineUsersList(memberUidList);
// 3. 与在线人员交集并进行路由
switch (MessageTypeEnum.of(message.getType())) {
@@ -85,6 +91,7 @@ public class MsgSendConsumer implements RocketMQListener<MsgSendMessageDTO> {
// 3.1 给自己推送原始消息
WsBaseResp<ChatMessageResp> selfResp = WsAdapter.buildMsgSend(chatService.getMsgResp(message, null));
pushService.sendPushMsg(selfResp, uid, dto.getUid());
asyncSavePassageMsg(message.getId(), selfResp, Set.of(uid), dto.getUid());
// 3.2 修改消息发送者为通话创建者(用于其他人接收)
Long originalFromUid = message.getFromUid();
@@ -101,20 +108,42 @@ public class MsgSendConsumer implements RocketMQListener<MsgSendMessageDTO> {
message.setFromUid(creator);
// 3.3 推送给其他成员
List<Long> otherMembers = new ArrayList<>(memberUidList);
otherMembers.remove(uid);
onlineUsersList.remove(uid);
List<Long> otherMembers = new ArrayList<>(onlineUsersList);
WsBaseResp<ChatMessageResp> othersResp = WsAdapter.buildMsgSend(chatService.getMsgResp(message, null));
// 恢复原始发送者显示
othersResp.getData().getFromUser().setUid(originalFromUid + "");
pushService.sendPushMsg(othersResp, otherMembers, dto.getUid());
asyncSavePassageMsg(message.getId(), othersResp, onlineUsersList, dto.getUid());
message.setFromUid(originalFromUid);
}
default -> {
// 常规消息处理
WsBaseResp<ChatMessageResp> wsBaseResp = WsAdapter.buildMsgSend(chatService.getMsgResp(message, null));
pushService.sendPushMsg(wsBaseResp, memberUidList, dto.getUid());
pushService.sendPushMsg(wsBaseResp, new ArrayList<>(onlineUsersList), dto.getUid());
asyncSavePassageMsg(message.getId(), wsBaseResp, onlineUsersList, dto.getUid());
}
}
}
/**
* 这里理论上一定会比 pushService 到达前端后在ack给后端 先执行完成
* @param messageId 消息的id [唯一标识未来升级为hash之后的值]
* @param wsBaseResp 推送的消息
* @param memberUidList 推送的列表
* @param cuid 操作人
*/
@Async
public void asyncSavePassageMsg(Long messageId, WsBaseResp<?> wsBaseResp, Set<Long> memberUidList, Long cuid) {
// 1. 发送重试消息
pushService.sendPushMsgWithRetry(wsBaseResp, new ArrayList<>(memberUidList), messageId, cuid);
// 2. 给每条消息加入 在途的状态
memberUidList.forEach(memberUid -> {
// 添加在途消息
cachePlusOps.sAdd(PassageMsgCacheKeyBuilder.build(memberUid), messageId);
});
}
}

View File

@@ -0,0 +1,56 @@
package com.luohuo.flex.im.core.chat.consumer;
import com.luohuo.basic.cache.repository.CachePlusOps;
import com.luohuo.flex.common.cache.PassageMsgCacheKeyBuilder;
import com.luohuo.flex.common.constant.MqConstant;
import com.luohuo.flex.im.core.chat.dao.ContactDao;
import com.luohuo.flex.im.core.user.service.impl.PushService;
import com.luohuo.flex.model.entity.dto.NodePushDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 消息推送延迟二次推送专属消费者 [系统自己发起]
* 收到重试消息之后判断路由的uid是否传递的消息是否还在途中再途的话再次发送
* @author 乾乾
*/
@Slf4j
@RocketMQMessageListener(
topic = MqConstant.PUSH_DELAY_TOPIC,
consumerGroup = MqConstant.PUSH_DELAY_GROUP,
messageModel = MessageModel.CLUSTERING,
maxReconsumeTimes = 3
)
@Component
@RequiredArgsConstructor
public class RetryPushConsumer implements RocketMQListener<NodePushDTO> {
private final CachePlusOps cachePlusOps;
private final PushService pushService;
private final ContactDao contactDao;
@Override
public void onMessage(NodePushDTO message) {
Map<String, Long> deviceUserMap = message.getDeviceUserMap();
deviceUserMap.values().forEach(uid -> {
Boolean exist = cachePlusOps.sIsMember(PassageMsgCacheKeyBuilder.build(uid), message.getHashId());
if (exist) {
log.info("ack失败重新发送消息: {}", message);
pushService.sendPushMsg(message.getWsBaseMsg(), Arrays.asList(uid), message.getUid());
// 直接更新会话的最后一条消息的id
LinkedHashMap<String, Object> dataMap = (LinkedHashMap<String, Object>) message.getWsBaseMsg().getData();
LinkedHashMap<String, Object> msg = (LinkedHashMap<String, Object>) dataMap.get("message");
LinkedHashMap<String, Object> user = (LinkedHashMap<String, Object>) dataMap.get("fromUser");
contactDao.refreshOrCreateActive(msg.get("roomId"), Arrays.asList(Long.parseLong(user.get("uid").toString())), msg.get("id"), msg.get("sendTime"));
}
});
}
}

View File

@@ -38,7 +38,14 @@ public class ContactDao extends ServiceImpl<ContactMapper, Contact> {
.one();
}
public Integer getReadCount(Message message) {
public List<Contact> get(Long uid, List<Long> roomIdList) {
return lambdaQuery()
.eq(Contact::getUid, uid)
.in(Contact::getRoomId, roomIdList)
.list();
}
public Integer getReadCount(Message message) {
return Math.toIntExact(lambdaQuery()
.eq(Contact::getHide, false)
.eq(Contact::getRoomId, message.getRoomId())
@@ -96,6 +103,11 @@ public class ContactDao extends ServiceImpl<ContactMapper, Contact> {
baseMapper.refreshOrCreateActiveTime(roomId, memberUidList, msgId, activeTime);
}
@TenantIgnore
public void refreshOrCreateActive(Object roomId, List<Long> memberUidList, Object msgId, Object activeTime) {
baseMapper.refreshOrCreateActive(roomId, memberUidList, msgId, activeTime);
}
public void refreshOrCreate(Long roomId, Long uid) {
baseMapper.refreshOrCreate(roomId, uid);
}

View File

@@ -82,15 +82,6 @@ public class MessageDao extends ServiceImpl<MessageMapper, Message> {
return this.update(wrapper);
}
@TenantIgnore
public Integer getUnReadCount(Long roomId, LocalDateTime readTime, Long uid) {
return Math.toIntExact(lambdaQuery()
.eq(Message::getRoomId, roomId)
.gt(Objects.nonNull(readTime), Message::getCreateTime, readTime)
.ne(Message::getFromUid, uid)
.count());
}
public Map<Long, Integer> batchGetUnReadCount(Collection<Contact> contactList) {
return baseMapper.batchGetUnReadCount(contactList);
}

View File

@@ -20,5 +20,15 @@ public interface ContactMapper extends BaseMapper<Contact> {
void refreshOrCreateActiveTime(@Param("roomId") Long roomId, @Param("memberUidList") List<Long> memberUidList, @Param("msgId") Long msgId, @Param("activeTime") LocalDateTime activeTime);
/**
* 刷新会话状态ack专用
*/
void refreshOrCreateActive(@Param("roomId") Object roomId, @Param("memberUidList") List<Long> memberUidList, @Param("msgId") Object msgId, @Param("activeTime") Object activeTime);
/**
* 刷新或创建会话
* @param roomId 房间id
* @param uid 用户id
*/
void refreshOrCreate(@Param("roomId") Long roomId, @Param("uid") Long uid);
}

View File

@@ -63,7 +63,6 @@ public class ChatServiceImpl implements ChatService {
private ContactDao contactDao;
private RoomCache roomCache;
private GroupMemberDao groupMemberDao;
/**
* 发送消息
*/
@@ -188,6 +187,47 @@ public class ChatServiceImpl implements ChatService {
return Stream.concat(groupRoomIds.stream(), friendRoomIds.stream()).distinct().collect(Collectors.toList());
}
/**
* 更新会话的最后一条消息ID
*/
@Async
public void updateContactLastMsgIds(Long receiveUid, Map<Long, List<Message>> groupedMessages) {
// 获取每个房间的最大消息ID
Map<Long, Long> roomMaxMsgIds = new HashMap<>();
for (Map.Entry<Long, List<Message>> entry : groupedMessages.entrySet()) {
Long roomId = entry.getKey();
List<Message> roomMessages = entry.getValue();
if (CollUtil.isNotEmpty(roomMessages)) {
// 找到房间中最大的消息ID
Long maxMsgId = roomMessages.stream()
.map(Message::getId)
.max(Long::compareTo)
.orElse(null);
if (maxMsgId != null) {
roomMaxMsgIds.put(roomId, maxMsgId);
}
}
}
// 批量更新会话的最后一条消息ID
if (!roomMaxMsgIds.isEmpty()) {
List<Long> roomIds = new ArrayList<>(roomMaxMsgIds.keySet());
List<Contact> contacts = contactDao.get(receiveUid, roomIds);
for (Contact contact : contacts) {
Long maxMsgId = roomMaxMsgIds.get(contact.getRoomId());
if (maxMsgId != null && (contact.getLastMsgId() == null || maxMsgId > contact.getLastMsgId())) {
contact.setLastMsgId(maxMsgId);
}
}
contactDao.updateBatchById(contacts);
log.info("已更新{}个会话的最后消息ID", contacts.size());
}
}
@Override
public List<ChatMessageResp> getMsgList(MsgReq msgReq, Long receiveUid) {
List<Message> messages;
@@ -198,21 +238,40 @@ public class ChatServiceImpl implements ChatService {
return Collections.emptyList();
}
// 2. 计算查询的时间范围最多15天
LocalDateTime effectiveStartTime = calculateStartTime(msgReq.getLastOptTime());
messages = messageDao.list(new LambdaQueryWrapper<Message>().in(Message::getRoomId, roomIds)
.between(Message::getCreateTime, effectiveStartTime, LocalDateTime.now()));
// 2. 如果开启同步功能那么把最近N天的消息拉回去, 否则获取所有未ack的消息 [要排除屏蔽的房间的消息]
if(msgReq.getAsync()){
LocalDateTime effectiveStartTime = calculateStartTime(TimeUtils.getTime(LocalDateTime.now().minusDays(14)));
messages = messageDao.list(new LambdaQueryWrapper<Message>().in(Message::getRoomId, roomIds)
.between(Message::getCreateTime, effectiveStartTime, LocalDateTime.now()));
} else {
// 3. 获取到需要拉取的消息的会话根据会话拿到最后一个ack的消息id TODO 需要走缓存
List<Contact> contacts = contactDao.get(receiveUid, roomIds);
// 查询每个房间中消息id 之后的所有消息
LambdaQueryWrapper<Message> batchWrapper = new LambdaQueryWrapper<>();
for (Contact contact : contacts) {
Long lastMsgId = contact.getLastMsgId() != null ? contact.getLastMsgId() : 0;
batchWrapper.or(w -> w.eq(Message::getRoomId, contact.getRoomId()).ge(Message::getId, lastMsgId));
}
batchWrapper.orderByAsc(Message::getId);
messages = messageDao.list(batchWrapper);
}
} else {
messages = getMsgByIds(msgReq.getMsgIds());
}
Map<Long, List<Message>> groupedMessages = messages.stream().collect(Collectors.groupingBy(Message::getRoomId));
// 3. 转换为响应对象并返回
// 5. 转换为响应对象并返回
List<ChatMessageResp> baseMessages = new ArrayList<>();
for (Long roomId : groupedMessages.keySet()) {
baseMessages.addAll(getMsgRespBatch(groupedMessages.get(roomId), receiveUid));
}
// 6. 更新会话的最后一条消息ID [不是查询消息、不是同步数据; 只有是登录获取会话id差额数据的时候才更新会话最后的id]
if (CollUtil.isEmpty(msgReq.getMsgIds()) && !msgReq.getAsync()) {
updateContactLastMsgIds(receiveUid, groupedMessages);
}
return baseMessages;
}
@@ -267,7 +326,7 @@ public class ChatServiceImpl implements ChatService {
public void recallMsg(Long uid, ChatMessageBaseReq request) {
Message message = messageDao.getById(request.getMsgId());
//校验能不能执行撤回
Integer roleId = checkRecall(uid, message);
checkRecall(uid, message);
recallMsgHandler.recall(uid, getRoomHowPeople(uid, message.getRoomId()), message);
}
@@ -345,19 +404,22 @@ public class ChatServiceImpl implements ChatService {
/**
* @return 返回撤回人的权限
*/
private Integer checkRecall(Long uid, Message message) {
private void checkRecall(Long uid, Message message) {
AssertUtil.isNotEmpty(message, "消息有误");
AssertUtil.notEqual(message.getType(), MessageTypeEnum.RECALL.getType(), "消息无法撤回");
GroupMember member = groupMemberCache.getMemberDetail(message.getRoomId(), uid);
if (member.getRoleId().equals(GroupRoleEnum.LEADER.getType()) || member.getRoleId().equals(GroupRoleEnum.MANAGER.getType())) {
return member.getRoleId();
}
Room room = roomCache.get(message.getRoomId());
if(room.getType().equals(RoomTypeEnum.GROUP.getType())){
GroupMember member = groupMemberCache.getMemberDetail(message.getRoomId(), uid);
if (member.getRoleId().equals(GroupRoleEnum.LEADER.getType()) || member.getRoleId().equals(GroupRoleEnum.MANAGER.getType())) {
return;
}
}
boolean self = Objects.equals(uid, message.getFromUid());
AssertUtil.isTrue(self, "抱歉,您没有权限");
long between = Duration.between(message.getCreateTime(), LocalDateTime.now()).toMinutes();
AssertUtil.isTrue(between < 2, "超过2分钟的消息不能撤回");
return member.getRoleId();
}
public List<ChatMessageResp> getMsgRespBatch(List<Message> messages, Long receiveUid) {

View File

@@ -12,8 +12,9 @@ import com.luohuo.basic.exception.code.ResponseEnum;
import com.luohuo.basic.model.cache.CacheKey;
import com.luohuo.basic.utils.SpringUtils;
import com.luohuo.basic.utils.TimeUtils;
import com.luohuo.flex.common.OnlineService;
import com.luohuo.flex.common.cache.PresenceCacheKeyBuilder;
import com.luohuo.flex.im.api.PresenceApi;
import com.luohuo.flex.common.constant.DefValConstants;
import com.luohuo.flex.im.core.chat.dao.RoomFriendDao;
import com.luohuo.flex.im.core.chat.dao.RoomGroupDao;
import com.luohuo.flex.im.core.user.dao.NoticeDao;
@@ -142,7 +143,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
private GroupMemberCache groupMemberCache;
private PushService pushService;
private FriendService friendService;
private PresenceApi presenceApi;
private OnlineService onlineService;
private TransactionTemplate transactionTemplate;
private void warmUpGroupMemberCache(Long roomId) {
@@ -279,7 +280,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
Set<Long> groupIdList = voList.stream().map(MemberResp::getGroupId).collect(Collectors.toSet());
List<Long> roomIdList = voList.stream().map(MemberResp::getRoomId).collect(Collectors.toList());
Map<Long, Long> onlineMap = presenceApi.getBatchGroupOnlineCounts(roomIdList).getData();
Map<Long, Long> onlineMap = onlineService.getBatchGroupOnlineCounts(roomIdList);
List<GroupMember> members = groupMemberDao.getGroupMemberByGroupIdListAndUid(uid, groupIdList);
Map<Long, GroupMember> map = members.stream().collect(Collectors.toMap(GroupMember::getGroupId, Function.identity()));
@@ -331,10 +332,10 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
groupMemberDao.addAdmin(roomGroup.getId(), request.getUidList());
// 每个被邀请的人都要收到邀请进群的消息
setAdminNotice(NoticeTypeEnum.GROUP_SET_ADMIN, uid, request.getUidList(), manageUidList, roomGroup.getName());
setAdminNotice(NoticeTypeEnum.GROUP_SET_ADMIN, uid, request.getUidList(), manageUidList, roomGroup.getRoomId());
}
private void setAdminNotice(NoticeTypeEnum noticeTypeEnum, Long uid, List<Long> uidList, List<Long> manageUidList, String content) {
private void setAdminNotice(NoticeTypeEnum noticeTypeEnum, Long uid, List<Long> uidList, List<Long> manageUidList, Long roomId) {
long uuid = uidGenerator.getUid();
uidList.stream().filter(id -> !manageUidList.contains(id)).forEach(id -> {
// 通知被操作的人
@@ -345,7 +346,8 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
id,
uuid,
id,
content
roomId,
""
);
// 通知群主
@@ -356,7 +358,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
// uid,
// uuid,
// id,
// content
// roomId
// );
});
}
@@ -385,7 +387,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
// 4. 撤销管理员
groupMemberDao.revokeAdmin(roomGroup.getId(), request.getUidList());
setAdminNotice(NoticeTypeEnum.GROUP_RECALL_ADMIN, uid, request.getUidList(), new ArrayList<>(), roomGroup.getName());
setAdminNotice(NoticeTypeEnum.GROUP_RECALL_ADMIN, uid, request.getUidList(), new ArrayList<>(), roomGroup.getRoomId());
}
/**
@@ -416,7 +418,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
*/
// @Async(LUOHUO_EXECUTOR)
public void asyncOnline(List<Long> uidList, Long roomId, boolean online) {
Set<Long> onlineList = presenceApi.getOnlineUsersList(uidList).getData();
Set<Long> onlineList = onlineService.getOnlineUsersList(uidList);
if (CollUtil.isEmpty(onlineList)) {
return;
}
@@ -770,7 +772,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
Room room = roomCache.get(roomId);
AssertUtil.isNotEmpty(roomGroup, "roomId有误");
Map<Long, Long> map = presenceApi.getBatchGroupOnlineCounts(Arrays.asList(room.getId())).getData();
Map<Long, Long> map = onlineService.getBatchGroupOnlineCounts(Arrays.asList(room.getId()));
// 获取群成员数、在线人员、备注、我的群名称
Long onlineNum = map.get(room.getId());
@@ -808,7 +810,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
Map<Long, SummeryInfoDTO> batch = userSummaryCache.getBatch(uids);
// 5. 批量获取在线状态
Set<Long> onlineList = presenceApi.getOnlineUsersList(new ArrayList<>(uids)).getData();
Set<Long> onlineList = onlineService.getOnlineUsersList(new ArrayList<>(uids));
// 6. 填充用户信息和在线状态
chatMemberResps.forEach(item -> {
@@ -917,7 +919,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
removedUid,
uuid,
removedUid,
roomGroup.getName(),
roomGroup.getRoomId(),
roomGroup.getName()
);
@@ -930,7 +932,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
managerId,
uuid,
removedUid,
roomGroup.getName(),
roomGroup.getRoomId(),
roomGroup.getName()
));
}
@@ -979,7 +981,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
invite.getTargetId(),
invite.getId(),
invite.getTargetId(),
roomGroup.getName(),
roomGroup.getRoomId(),
roomGroup.getName()
);
@@ -991,7 +993,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
managerId,
invite.getId(),
invite.getTargetId(),
roomGroup.getName(),
roomGroup.getRoomId(),
roomGroup.getName()
));
});
@@ -1033,6 +1035,8 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
ChatMessageReq messageReq = new ChatMessageReq();
messageReq.setBody(StrUtil.format("{}解散了群聊", user.getName()));
messageReq.setMsgType(MessageTypeEnum.SYSTEM.getType());
messageReq.setSkip(true);
messageReq.setRoomId(roomId);
chatService.sendMsg(messageReq, uid);
// 4.1 删除房间和群并清除缓存
@@ -1056,6 +1060,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
return true;
});
// 4.5 告知所有人群已经被解散, 这里要走groupMemberDao查询缓存中可能没有屏蔽群的用户
roomCache.delete(roomId);
groupMemberCache.evictMemberList(room.getId());
groupMemberCache.evictExceptMemberList(room.getId());
groupMemberCache.evictAllMemberDetails();
@@ -1063,7 +1068,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(uid);
cachePlusOps.del(uKey, gKey);
asyncOnline(memberUidList, room.getId(), false);
// pushService.sendPushMsg(RoomAdapter.buildGroupDissolution(roomGroup.getRoomId()), memberUidList, uid);
pushService.sendPushMsg(RoomAdapter.buildGroupDissolution(roomGroup.getRoomId()), memberUidList, uid);
} else {
// 如果房间人员小于3人 那么直接解散群聊
if (cachePlusOps.sCard(gKey) <= 3) {
@@ -1091,11 +1096,11 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
asyncOnline(Arrays.asList(uid), room.getId(), false);
// 4.8 发送移除事件告知群成员
WsBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId()))), Arrays.asList(uid), WSMemberChange.CHANGE_TYPE_QUIT);
pushService.sendPushMsg(ws, memberUidList, uid);
groupMemberCache.evictMemberList(room.getId());
groupMemberCache.evictExceptMemberList(room.getId());
groupMemberCache.evictMemberDetail(room.getId(), uid);
WsBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId()))), Arrays.asList(uid), WSMemberChange.CHANGE_TYPE_QUIT);
pushService.sendPushMsg(ws, memberUidList, uid);
}
}
}
@@ -1106,6 +1111,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
Map<Long, SummeryInfoDTO> userMap = userSummaryCache.getBatch(request.getUidList());
AssertUtil.isTrue(userMap.size() > 1, "群聊人数应大于2人");
userMap.remove(DefValConstants.DEF_BOT_ID);
List<Long> uidList = new ArrayList<>(userMap.keySet());
AtomicReference<Long> roomIdAtomic = new AtomicReference(0L);
@@ -1115,13 +1121,19 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
// 批量保存群成员
List<GroupMember> groupMembers = RoomAdapter.buildGroupMemberBatch(uidList, roomGroup.getId());
groupMemberDao.saveBatch(groupMembers);
// 添加所有人的会话
uidList.add(uid);
for (Long memberId : uidList) {
contactDao.refreshOrCreate(roomGroup.getRoomId(), memberId);
}
roomIdAtomic.set(roomGroup.getRoomId());
return true;
})) {
// 发送邀请加群消息 ==> 触发每个人的会话
roomGroupCache.evictAllCaches();
// 处理新房间里面所有在线人员
uidList.add(uid);
groupMemberCache.evictMemberList(roomIdAtomic.get());
groupMemberCache.evictExceptMemberList(roomIdAtomic.get());

View File

@@ -1,10 +1,14 @@
package com.luohuo.flex.im.core.chat.service.strategy.msg;
import com.luohuo.basic.context.ContextUtil;
import com.luohuo.basic.utils.SpringUtils;
import com.luohuo.basic.utils.TimeUtils;
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
import com.luohuo.flex.im.core.chat.service.cache.GroupMemberCache;
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
import com.luohuo.flex.im.domain.entity.GroupMember;
import com.luohuo.flex.im.domain.enums.GroupRoleEnum;
import com.luohuo.flex.im.vo.result.tenant.MsgRecallVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import com.luohuo.flex.im.common.event.MessageRecallEvent;
@@ -27,48 +31,83 @@ import java.util.Objects;
@AllArgsConstructor
public class RecallMsgHandler extends AbstractMsgHandler<Object> {
private MessageDao messageDao;
private MessageDao messageDao;
private UserSummaryCache userSummaryCache;
private MsgCache msgCache;
private GroupMemberCache groupMemberCache;
@Override
MessageTypeEnum getMsgTypeEnum() {
return MessageTypeEnum.RECALL;
}
@Override
MessageTypeEnum getMsgTypeEnum() {
return MessageTypeEnum.RECALL;
}
@Override
public void saveMsg(Message msg, Object body) {
throw new UnsupportedOperationException();
}
@Override
public void saveMsg(Message msg, Object body) {
throw new UnsupportedOperationException();
}
@Override
public Object showMsg(Message msg) {
MsgRecallDTO recall = msg.getExtra().getRecall();
SummeryInfoDTO userInfo = userSummaryCache.get(recall.getRecallUid());
if (!Objects.equals(recall.getRecallUid(), msg.getFromUid())) {
return "管理员\"" + userInfo.getName() + "\"撤回了一条成员消息";
}
return "\"" + userInfo.getName() + "\"撤回了一条消息";
}
@Override
public Object showMsg(Message msg) {
MsgRecallDTO recall = msg.getExtra().getRecall();
Long recallerUid = recall.getRecallUid();
Long senderUid = msg.getFromUid();
Long currentUserUid = ContextUtil.getUid();
@Override
public Object showReplyMsg(Message msg) {
return "原消息已被撤回";
}
// 获取撤回者的群成员信息和用户信息
GroupMember recallerMember = groupMemberCache.getMemberDetail(msg.getRoomId(), recallerUid);
SummeryInfoDTO recallerUserInfo = userSummaryCache.get(recallerUid);
public void recall(Long recallUid, List<Long> uidList, Message message) {//todo 消息覆盖问题用版本号解决
MessageExtra extra = message.getExtra();
extra.setRecall(new MsgRecallDTO(recallUid, TimeUtils.getTime(LocalDateTime.now())));
Message update = new Message();
update.setId(message.getId());
update.setType(MessageTypeEnum.RECALL.getType());
update.setExtra(extra);
messageDao.updateById(update);
// 获取被撤回消息发送者的用户信息(用于显示成员名称)
SummeryInfoDTO senderUserInfo = userSummaryCache.get(senderUid);
// 判断关键关系
boolean isRecallerCurrentUser = Objects.equals(recallerUid, currentUserUid);
boolean isSenderCurrentUser = Objects.equals(senderUid, currentUserUid);
String roleName = GroupRoleEnum.get(recallerMember.getRoleId());
String messageText;
if (isRecallerCurrentUser) {
// 当前用户是撤回操作执行者
if (Objects.equals(recallerUid, senderUid)) {
// 撤回自己的消息:自己视角
messageText = "你撤回了一条消息";
} else {
// 撤回他人的消息:群主/管理员视角
messageText = "你撤回了成员" + senderUserInfo.getName() + "的一条消息";
}
} else {
// 当前用户不是撤回操作执行者
if (isSenderCurrentUser) {
// 当前用户是被撤回消息的发送者(被撤回者视角)
messageText = roleName + recallerUserInfo.getName() + "撤回了你的一条消息";
} else {
// 当前用户是旁观者(其他成员视角)
messageText = roleName + recallerUserInfo.getName() + "撤回了一条消息";
}
}
return new MsgRecallVo(messageText);
}
@Override
public Object showReplyMsg(Message msg) {
return "原消息已被撤回";
}
public void recall(Long recallUid, List<Long> uidList, Message message) {//todo 消息覆盖问题用版本号解决
MessageExtra extra = message.getExtra();
extra.setRecall(new MsgRecallDTO(recallUid, TimeUtils.getTime(LocalDateTime.now())));
Message update = new Message();
update.setId(message.getId());
update.setType(MessageTypeEnum.RECALL.getType());
update.setExtra(extra);
messageDao.updateById(update);
SpringUtils.publishEvent(new MessageRecallEvent(this, uidList, new ChatMsgRecallDTO(message.getId(), message.getRoomId(), recallUid)));
}
}
@Override
public String showContactMsg(Message msg) {
return "撤回了一条消息";
}
@Override
public String showContactMsg(Message msg) {
return "撤回了一条消息";
// return ((MsgRecallVo) showMsg(msg)).getContent();
}
}

View File

@@ -147,6 +147,13 @@ public class UserFriendDao extends ServiceImpl<UserFriendMapper, UserFriend> {
.one();
}
public UserFriend getByFriend2(Long uid1, Long uid2) {
return lambdaQuery()
.eq(UserFriend::getUid, uid1)
.eq(UserFriend::getFriendUid, uid2)
.one();
}
/**
* 当好友关系变更时清除缓存
* @param roomId 房间ID

View File

@@ -24,7 +24,7 @@ public interface NoticeService {
*/
void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, String content);
void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, String name, String content);
void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, Long roomId, String content);
/**
* 更新通知状态

View File

@@ -176,7 +176,7 @@ public class ApplyServiceImpl implements ApplyService {
uid,
applyId,
uid,
roomGroup.getName(),
roomGroup.getRoomId(),
req.getMsg()
);
@@ -188,7 +188,7 @@ public class ApplyServiceImpl implements ApplyService {
groupAdminId,
applyId,
uid,
roomGroup.getName(),
roomGroup.getRoomId(),
req.getMsg()
);
}

View File

@@ -6,10 +6,10 @@ import com.google.common.collect.Lists;
import com.luohuo.basic.cache.redis.BaseRedis;
import com.luohuo.basic.cache.repository.CachePlusOps;
import com.luohuo.basic.model.cache.CacheKey;
import com.luohuo.flex.common.OnlineService;
import com.luohuo.flex.common.cache.FriendCacheKeyBuilder;
import com.luohuo.flex.common.cache.PresenceCacheKeyBuilder;
import com.luohuo.flex.common.constant.DefValConstants;
import com.luohuo.flex.im.api.PresenceApi;
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
import com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum;
@@ -71,7 +71,7 @@ public class FriendServiceImpl implements FriendService, InitializingBean {
private BaseRedis baseRedis;
private final PushService pushService;
private CachePlusOps cachePlusOps;
private PresenceApi presenceApi;
private OnlineService onlineService;
/**
* 注入好友关系
@@ -205,6 +205,9 @@ public class FriendServiceImpl implements FriendService, InitializingBean {
log.info("没有好友关系:{},{}", uid, friendUid);
return;
}
if (DefValConstants.DEF_BOT_ID.equals(friendUid)) {
return;
}
List<Long> friendRecordIds = userFriends.stream().map(UserFriend::getId).collect(Collectors.toList());
userFriendDao.removeByIds(friendRecordIds);
// 禁用房间
@@ -226,7 +229,7 @@ public class FriendServiceImpl implements FriendService, InitializingBean {
}
List<Long> friendUids = friendPage.getList().stream().map(UserFriend::getFriendUid).collect(Collectors.toList());
Set<Long> onlineList = presenceApi.getOnlineUsersList(friendUids).getData();
Set<Long> onlineList = onlineService.getOnlineUsersList(friendUids);
return CursorPageBaseResp.init(friendPage, FriendAdapter.buildFriend(friendPage.getList(), onlineList), 0L);
}

View File

@@ -38,7 +38,7 @@ public class NoticeServiceImpl implements NoticeService {
private void pushNoticeToUser(Long receiverId, Notice notice) {
WsBaseResp<NoticeVO> wsMsg = new WsBaseResp<>();
wsMsg.setData(convertToVO(notice));
wsMsg.setType(WSRespTypeEnum.NOTICE.getType());
wsMsg.setType(WSRespTypeEnum.NOTIFY_EVENT.getType());
pushService.sendPushMsg(wsMsg, Collections.singletonList(receiverId), notice.getSenderId());
}
@@ -49,11 +49,11 @@ public class NoticeServiceImpl implements NoticeService {
@Override
public void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, String content) {
createNotice(applyType, type, senderId, receiverId, applyId, operate, "", content);
createNotice(applyType, type, senderId, receiverId, applyId, operate, 0L, content);
}
@Override
public void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, String name, String content) {
public void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, Long roomId, String content) {
Notice notice = new Notice();
notice.setType(applyType.getType());
notice.setEventType(type.getType());
@@ -61,7 +61,7 @@ public class NoticeServiceImpl implements NoticeService {
notice.setReceiverId(receiverId);
notice.setApplyId(applyId);
notice.setOperateId(operate);
notice.setName(name);
notice.setRoomId(roomId);
notice.setContent(content);
notice.setIsRead(UNREAD.getCode());
notice.setStatus(NoticeStatusEnum.UNTREATED.getStatus());
@@ -102,7 +102,9 @@ public class NoticeServiceImpl implements NoticeService {
public PageBaseResp<NoticeVO> getUserNotices(Long uid, PageBaseReq request) {
IPage<Notice> noticeIPage = noticeDao.getUserNotices(uid, true, request.plusPage());
// 将这些通知设为已读
readNotices(uid, noticeIPage);
if(request.getClick()){
readNotices(uid, noticeIPage);
}
return PageBaseResp.init(noticeIPage, noticeIPage.getRecords().stream().map(notice -> convertToVO(notice)).collect(Collectors.toList()));
}
@@ -113,7 +115,7 @@ public class NoticeServiceImpl implements NoticeService {
vo.setSenderId(notice.getSenderId());
vo.setReceiverId(notice.getReceiverId());
vo.setOperateId(notice.getOperateId());
vo.setName(notice.getName());
vo.setRoomId(notice.getRoomId());
vo.setContent(notice.getContent());
vo.setEventType(notice.getEventType());
vo.setType(notice.getType());

View File

@@ -8,6 +8,7 @@ import com.luohuo.basic.model.cache.CacheKey;
import com.luohuo.basic.service.MQProducer;
import com.luohuo.flex.common.cache.PresenceCacheKeyBuilder;
import com.luohuo.flex.common.constant.MqConstant;
import com.luohuo.flex.im.domain.DelayRetryTask;
import com.luohuo.flex.model.entity.dto.NodePushDTO;
import com.luohuo.flex.model.entity.WsBaseResp;
import com.luohuo.flex.router.NacosRouterService;
@@ -23,7 +24,9 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
@@ -50,6 +53,18 @@ public class PushService {
@Value("${luohuo.thread.min:4}")
private int minThreads;
@Value("${luohuo.thread.retry.max-count:3}")
private Integer maxRetryCount;
@Value("${luohuo.thread.retry.delay-seconds:3}")
private Integer delaySeconds;
// 延迟任务线程池
private ScheduledExecutorService retryScheduler;
// 重试次数记录
private final Map<String, AtomicInteger> messageRetryCountMap = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
int poolSize = Math.max(minThreads, Runtime.getRuntime().availableProcessors() * threadMultiplier);
@@ -62,6 +77,13 @@ public class PushService {
.build()
);
}
retryScheduler = Executors.newScheduledThreadPool(2,
new ThreadFactoryBuilder()
.setNameFormat("push-retry-scheduler")
.setDaemon(true)
.build());
log.info("初始化推送线程池, size={}", poolSize);
}
@@ -70,18 +92,23 @@ public class PushService {
* @param msg 消息体
* @param uids 接收消息的用户
* @param cuid 操作人
* TODO uids 中没有推送的消息加入延迟信箱
* @param retry 延迟推送 [延迟二次推送判断在途消息是否已经ack]
* @return
*/
public CompletableFuture<Void> sendAsync(WsBaseResp<?> msg, List<Long> uids, Long cuid) {
public CompletableFuture<Void> sendAsync(WsBaseResp<?> msg, List<Long> uids, Long hashId, Long cuid, Boolean retry) {
// 1. 构建三级映射: 节点 → 设备指纹 → 用户ID
Map<String, Map<String, Long>> nodeDeviceUser = routerService.findNodeDeviceUser(uids);
// 2. 按节点+设备批量推送
List<CompletableFuture<Void>> futures = new ArrayList<>();
nodeDeviceUser.forEach((nodeId, deviceUserMap) -> futures.add(CompletableFuture.runAsync(
() -> mqProducer.sendMsg(MqConstant.PUSH_TOPIC + nodeId, new NodePushDTO(msg, deviceUserMap, cuid)),
getExecutorForNode(nodeId)
() -> {
if (retry) {
mqProducer.sendMsgWithDelay(MqConstant.PUSH_DELAY_TOPIC, new NodePushDTO(msg, deviceUserMap, hashId, cuid), delaySeconds);
} else {
mqProducer.sendMsg(MqConstant.PUSH_TOPIC + nodeId, new NodePushDTO(msg, deviceUserMap, hashId, cuid));
}
}, getExecutorForNode(nodeId)
)));
// 3. 执行任务
@@ -89,7 +116,7 @@ public class PushService {
}
/**
* 直接发送, 单个用户直接推送
* 直接发送,单个用户直接推送
*/
public void sendPushMsg(WsBaseResp<?> msg, Long uid, Long cuid) {
sendPushMsg(msg, Arrays.asList(uid), cuid);
@@ -97,9 +124,10 @@ public class PushService {
/**
* 批量异步发送给 uidList
* TODO 这里hashId 需要重新生成
*/
public void sendPushMsg(WsBaseResp<?> msg, List<Long> uidList, Long cuid) {
sendAsync(msg, uidList, cuid)
sendAsync(msg, uidList, 0L, cuid, false)
.exceptionally(e -> {
log.error("批量推送失败", e);
return null;
@@ -124,6 +152,8 @@ public class PushService {
@PreDestroy
public void destroy() {
log.info("开始关闭推送线程池...");
// 1. 关闭推送线程池
Arrays.stream(NODE_EXECUTORS).forEach(executor -> {
executor.shutdown();
try {
@@ -136,7 +166,23 @@ public class PushService {
Thread.currentThread().interrupt();
}
});
log.info("推送线程池已关闭");
// 2. 关闭延迟调度线程池
if (retryScheduler != null) {
retryScheduler.shutdown();
try {
if (!retryScheduler.awaitTermination(5, TimeUnit.SECONDS)) {
retryScheduler.shutdownNow();
}
} catch (InterruptedException e) {
retryScheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
// 清理重试状态记录
messageRetryCountMap.clear();
log.info("推送线程池和重试调度器已关闭");
}
/**
@@ -184,4 +230,111 @@ public class PushService {
Lists.partition(memberIdList, pageSize).forEach(batch -> sendPushMsg(commonResp, batch, uid));
}
/**
* 批量推送方法 [重试专用]
*/
public void sendPushMsgWithRetry(WsBaseResp<?> msg, List<Long> uidList, Long hashId, Long cuid) {
sendAsyncWithRetry(msg, uidList, hashId, cuid)
.exceptionally(e -> {
log.error("重试的批量推送最终失败", e);
return null;
});
}
/**
* 单用户推送方法 [重试专用]
* @param msg 消息实体
* @param uid 推送的uid
* @param hashId 需要重试的唯一标识
* @param cuid 操作人
*/
public void sendPushMsgWithRetry(WsBaseResp<?> msg, Long uid, Long hashId, Long cuid) {
sendPushMsgWithRetry(msg, Arrays.asList(uid), hashId, cuid);
}
/**
* 发送带重试机制的推送消息
*/
public CompletableFuture<Void> sendAsyncWithRetry(WsBaseResp<?> msg, List<Long> uids, Long hashId, Long cuid) {
return sendAsync(msg, uids, hashId, cuid, true)
.exceptionally(throwable -> {
// 首次推送失败,触发延迟重试
log.warn("消息首次推送失败触发延迟重试。uidList: {}, Reason: {}", uids, throwable.getMessage());
scheduleDelayRetry(msg, uids, hashId, cuid, 1, "首次推送失败: " + throwable.getMessage());
return null;
});
}
/**
* 生成消息唯一标识Key
*/
private String generateMessageKey(WsBaseResp<?> msg, List<Long> targetUids) {
String uidListHash = Integer.toHexString(targetUids.hashCode());
return String.format("retry_%s_%s_%s",
msg.getType(),
uidListHash,
System.currentTimeMillis() / 1000);
}
/**
* 调度延迟重试
*/
private void scheduleDelayRetry(WsBaseResp<?> msg, List<Long> uids, Long hashId, Long cuid, int retryCount, String reason) {
String messageKey = generateMessageKey(msg, uids);
// 检查重试次数
if (retryCount > maxRetryCount) {
log.error("消息重试已达最大次数[{}]停止重试。Key: {}, Reason: {}", maxRetryCount, messageKey, reason);
messageRetryCountMap.remove(messageKey);
// 可以在这里添加死信队列处理
return;
}
// 记录重试次数
messageRetryCountMap.put(messageKey, new AtomicInteger(retryCount));
// 调度延迟重试
DelayRetryTask retryTask = new DelayRetryTask(msg, uids, cuid, hashId, retryCount, reason);
retryScheduler.schedule(() -> executeRetry(retryTask, messageKey), delaySeconds, TimeUnit.SECONDS);
log.info("延迟重试任务已调度。Key: {}, 第{}次重试, 延迟: {}秒", messageKey, retryCount, delaySeconds);
}
/**
* 执行重试推送
*/
private void executeRetry(DelayRetryTask retryTask, String messageKey) {
try {
log.info("开始执行延迟重试。Key: {}, 第{}次重试", messageKey, retryTask.getRetryCount());
// 再次尝试推送
sendAsync(retryTask.getOriginalMsg(), retryTask.getTargetUids(), retryTask.getHashId(), retryTask.getOperatorUid(), true)
.whenComplete((result, throwable) -> {
if (throwable != null) {
log.warn("第{}次重试推送失败准备下一次重试。Key: {}",
retryTask.getRetryCount(), messageKey, throwable);
scheduleDelayRetry(retryTask.getOriginalMsg(),
retryTask.getTargetUids(),
retryTask.getHashId(),
retryTask.getOperatorUid(), retryTask.getRetryCount() + 1,
"重试推送失败: " + throwable.getMessage());
} else {
messageRetryCountMap.remove(messageKey);
log.info("第{}次重试推送成功。Key: {}",
retryTask.getRetryCount(), messageKey);
}
});
} catch (Exception e) {
log.error("执行延迟重试时发生异常。Key: {}", messageKey, e);
// 异常情况下继续重试
scheduleDelayRetry(retryTask.getOriginalMsg(),
retryTask.getTargetUids(),
retryTask.getHashId(),
retryTask.getOperatorUid(),
retryTask.getRetryCount() + 1,
"执行异常: " + e.getMessage());
}
}
}

View File

@@ -198,6 +198,7 @@ public class UserServiceImpl implements UserService {
AssertUtil.equal(itemConfig.getType(), ItemTypeEnum.BADGE.getType(), "该徽章不可佩戴");
// 佩戴徽章
userDao.wearingBadge(uid, req.getBadgeId());
userCache.delete(uid);
userSummaryCache.delete(uid);
}
@@ -283,6 +284,7 @@ public class UserServiceImpl implements UserService {
boolean save = userDao.updateById(user);
if(save){
cachePlusOps.hDel("emailCode", req.getUuid());
userCache.delete(uid);
userSummaryCache.delete(uid);
}
return save;
@@ -308,6 +310,7 @@ public class UserServiceImpl implements UserService {
uw.lambda().set(User::getNum, user.getNum() - 1).eq(User::getId, user.getId());
boolean success = userDao.update(uw);
if(success){
userCache.delete(uid);
userSummaryCache.delete(uid);
}
return success;
@@ -342,13 +345,14 @@ public class UserServiceImpl implements UserService {
// 保存用户
newUser.setCreateBy(1L);
userDao.save(newUser);
// 加上系统机器人好友
roomAppService.createSystemFriend(DefValConstants.DEF_ROOM_ID, DefValConstants.DEF_GROUP_ID, newUser.getId());
// 注入群组信息
cachePlusOps.sAdd(PresenceCacheKeyBuilder.groupMembersKey(DefValConstants.DEF_ROOM_ID), newUser.getId());
cachePlusOps.sAdd(PresenceCacheKeyBuilder.userGroupsKey(newUser.getId()), DefValConstants.DEF_ROOM_ID);
// 加上系统机器人好友
roomAppService.createSystemFriend(DefValConstants.DEF_ROOM_ID, DefValConstants.DEF_GROUP_ID, newUser.getId());
// 发布用户注册消息
SpringUtils.publishEvent(new UserRegisterEvent(this, newUser));
return true;

View File

@@ -1,7 +1,7 @@
package com.luohuo.flex.im.core.user.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.luohuo.flex.im.core.user.dao.UserStateDao;
import com.luohuo.flex.im.core.user.service.cache.UserCache;
import com.luohuo.flex.im.domain.entity.UserState;
import com.luohuo.flex.model.entity.WSRespTypeEnum;
import com.luohuo.flex.im.domain.vo.resp.user.UserInfoResp;
@@ -24,6 +24,7 @@ import java.util.List;
public class UserStateServiceImpl implements UserStateService {
private UserStateDao userStateDao;
private UserCache userCache;
private UserSummaryCache userSummaryCache;
private UserService userService;
private PushService pushService;
@@ -42,17 +43,14 @@ public class UserStateServiceImpl implements UserStateService {
}
UserState userState = userStateDao.getById(userStateId);
Boolean changeUserState = userService.changeUserState(uid, userStateId);
userService.changeUserState(uid, userStateId);
if (ObjectUtil.isNotNull(userState) && changeUserState){
// 1.清除缓存
userSummaryCache.delete(uid);
// 1.清除缓存
userCache.delete(uid);
userSummaryCache.delete(uid);
// 2.推送数据
pushService.pushRoom(uid, WSRespTypeEnum.USER_STATE_CHANGE.getType(), new UserStateVo(uid, userState.getId()));
return true;
}else {
throw new RuntimeException("用户状态更新失败");
}
// 2.推送数据
pushService.pushRoom(uid, WSRespTypeEnum.USER_STATE_CHANGE.getType(), new UserStateVo(uid, userState == null? 0L: userState.getId()));
return true;
}
}

View File

@@ -14,6 +14,19 @@
active_time = VALUES(active_time)
</insert>
<!-- 执行这个sql是因为前端有消息没被收到每次更新当前会话未收到的消息时只更新最小的id那个 -->
<insert id="refreshOrCreateActive">
INSERT INTO im_contact (room_id, uid, last_msg_id, active_time, is_del) VALUES
<foreach collection="memberUidList" item="uid" separator=",">
(#{roomId},#{uid},#{msgId},#{activeTime},0)
</foreach>
ON DUPLICATE KEY UPDATE
is_del = IF(#{msgId} &lt; last_msg_id, 0, is_del),
hide = IF(#{msgId} &lt; last_msg_id, 0, hide),
last_msg_id = IF(#{msgId} &lt; last_msg_id, VALUES(last_msg_id), last_msg_id),
active_time = IF(#{msgId} &lt; last_msg_id, VALUES(active_time), active_time)
</insert>
<insert id="refreshOrCreate">
INSERT INTO im_contact (room_id, uid, is_del) VALUES (#{roomId},#{uid},0)
ON DUPLICATE KEY UPDATE is_del = 0, hide = 0

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-im</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -57,12 +57,12 @@ public class ChatController {
}
@PostMapping("/msg/list")
@Operation(summary ="消息列表")
@Operation(summary ="消息列表 [登录时消息同步用的]")
// @FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP)
public R<List<ChatMessageResp>> getMsgPage(@RequestBody MsgReq msgReq) {
List<ChatMessageResp> msgPage = chatService.getMsgList(msgReq, ContextUtil.getUid());
// Set<String> blackMembers = getBlackUidSet();
// msgPage.removeIf(a -> blackMembers.contains(a.getFromUser().getUid().toString()));
Set<String> blackMembers = getBlackUidSet();
msgPage.removeIf(a -> blackMembers.contains(a.getFromUser().getUid().toString()));
return R.success(msgPage);
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-im</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,23 @@
package com.luohuo.flex.im.domain;
import com.luohuo.flex.model.entity.WsBaseResp;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
@AllArgsConstructor
public class DelayRetryTask {
// 原始消息
private WsBaseResp<?> originalMsg;
// 目标用户
private List<Long> targetUids;
// 操作者
private Long operatorUid;
// 哈希值
private Long hashId;
// 重试次数
private Integer retryCount;
private String retryReason;
}

View File

@@ -48,8 +48,8 @@ public class Notice extends Entity<Long> {
@TableField("operate_id")
private Long operateId;
@Schema(description = "群聊的名称")
private String name;
@Schema(description = "房间id")
private Long roomId;
@Schema(description = "通知内容 申请时填写的, 进群、移除时是群聊的名称")
private String content;

View File

@@ -16,9 +16,6 @@ import java.util.stream.Collectors;
@AllArgsConstructor
@Getter
public enum GroupRoleEnum {
/**
*
*/
LEADER(1, "群主"),
MANAGER(2, "管理"),
MEMBER(3, "普通成员"),
@@ -27,9 +24,6 @@ public enum GroupRoleEnum {
private final Integer type;
private final String desc;
public static final List<Integer> ADMIN_LIST = Arrays.asList(GroupRoleEnum.LEADER.getType(), GroupRoleEnum.MANAGER.getType());
public static final List<Integer> ROLE_LIST = Arrays.asList(GroupRoleEnum.LEADER.getType(), GroupRoleEnum.MANAGER.getType(), GroupRoleEnum.MEMBER.getType());
private static Map<Integer, GroupRoleEnum> cache;
static {
@@ -39,4 +33,15 @@ public enum GroupRoleEnum {
public static GroupRoleEnum of(Integer type) {
return cache.get(type);
}
/**
* 返回角色的名称
* @param type 传入成员类型
*/
public static String get(Integer type) {
if(type > MANAGER.getType()){
return "";
}
return cache.get(type).getDesc();
}
}

View File

@@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.Data;
import java.io.Serializable;
@@ -24,6 +25,9 @@ public class PageBaseReq implements Serializable {
@Schema(description = "页面索引从1开始")
private Integer pageNo = 1;
@Schema(description = "点击请求")
private Boolean click = false;
/**
* 获取mybatisPlus的page
*/

View File

@@ -18,9 +18,9 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
public class MsgReq implements Serializable {
@Schema(description ="消息id")
@Schema(description ="消息id, 传了消息id默认就是查询消息的接口")
private List<Long> msgIds;
@Schema(description ="最后一次ws连接的时间")
private Long lastOptTime;
@Schema(description ="开启同步消息")
private Boolean async = false;
}

View File

@@ -27,8 +27,8 @@ public class NoticeVO {
@Schema(description = "被操作的人")
private Long operateId;
@Schema(description = "群昵称")
private String name;
@Schema(description = "房间id")
private Long roomId;
@Schema(description = "通知内容 申请时填写的")
private String content;

View File

@@ -0,0 +1,23 @@
package com.luohuo.flex.im.vo.result.tenant;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 消息撤回
* @author 乾乾
*/
@Data
@Builder
@NoArgsConstructor
public class MsgRecallVo implements Serializable {
private static final long serialVersionUID = 1L;
private String content;
public MsgRecallVo(String content) {
this.content = content;
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-im-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-im-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-im-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-im</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-im</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,6 +3,19 @@ package com.luohuo.flex.areatest;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.log.StaticLog;
import com.luohuo.basic.context.ContextUtil;
import com.luohuo.flex.im.core.chat.dao.ContactDao;
import com.luohuo.flex.im.core.chat.dao.GroupMemberDao;
import com.luohuo.flex.im.core.chat.dao.RoomGroupDao;
import com.luohuo.flex.im.core.chat.service.RoomService;
import com.luohuo.flex.im.core.chat.service.impl.ChatServiceImpl;
import com.luohuo.flex.im.core.user.dao.UserDao;
import com.luohuo.flex.im.core.user.dao.UserFriendDao;
import com.luohuo.flex.im.core.user.service.impl.FriendServiceImpl;
import com.luohuo.flex.im.domain.entity.Contact;
import com.luohuo.flex.im.domain.entity.GroupMember;
import com.luohuo.flex.im.domain.entity.RoomGroup;
import com.luohuo.flex.im.domain.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -22,11 +35,47 @@ public class CityParserTest {
CityParser cityParser;
@Resource
SqlCityParserDecorator sqlCityParserDecorator;
@Resource
UserDao userDao;
@Resource
UserFriendDao userFriendDao;
@Resource
ChatServiceImpl chatService;
@Resource
private RoomService roomService;
@Resource
private GroupMemberDao groupMemberDao;
@Resource
private RoomGroupDao roomGroupDao;
@Resource
private ContactDao contactDao;
@Resource
private FriendServiceImpl friendService;
@Test
public void bot() {
ContextUtil.setUid(1L);
ContextUtil.setTenantId(1L);
// 2. 计算会话的最后一条消息id
List<User> list = userDao.list();
list.forEach(user -> {
List<GroupMember> groupList = groupMemberDao.getSelfGroup(user.getId());
groupList.forEach(groupMember -> {
RoomGroup roomGroup = roomGroupDao.getById(groupMember.getGroupId());
if(roomGroup!=null){
Contact contact = contactDao.get(user.getId(), roomGroup.getRoomId());
if(contact == null){
// 创建会话
chatService.createContact(user.getId(), roomGroup.getRoomId());
}
}
});
});
}
/**
* 实时爬取最新的地区数据,请执行该方法
*/
/**
* 实时爬取最新的地区数据,请执行该方法
*/
@Test
public void pullArea() {

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../luohuo-dependencies-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-oauth</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -49,6 +49,7 @@ public class RefreshTokenGranter {
public LoginResultVO refresh(String refreshToken) {
// 1、验证
Object str = SaTempUtil.parseToken(refreshToken);
SaTempUtil.deleteToken(refreshToken);
JSONObject obj = JSONUtil.parseObj(str);
Long userId = obj.getLong(JWT_KEY_USER_ID);
@@ -102,6 +103,7 @@ public class RefreshTokenGranter {
resultVO.setToken(tokenSession.getToken());
resultVO.setExpire(StpUtil.getTokenTimeout());
resultVO.setClient(device);
resultVO.setUid(uid);
resultVO.setRefreshToken(SaTempUtil.createToken(obj.toString(), 2 * saTokenConfig.getTimeout()));
return resultVO;
}

View File

@@ -144,8 +144,9 @@ public class CaptchaServiceImpl implements CaptchaService {
String code = RandomUtil.randomNumbers(6);
CacheKey cacheKey = CaptchaCacheKeyBuilder.build(bindEmailReq.getEmail(), bindEmailReq.getTemplateCode());
cacheOps.set(cacheKey, code);
ArgumentAssert.isFalse(cacheOps.exists(cacheKey), "请勿重复发送验证码");
cacheOps.set(cacheKey, code);
log.info("邮件验证码 cacheKey={}, code={}", cacheKey, code);
// 在「运营平台」-「消息模板」配置一个「模板标识」为 templateCode 且「模板内容」中需要有 code 占位符

View File

@@ -101,7 +101,13 @@ public class UserInfoServiceImpl implements UserInfoService {
}
ArgumentAssert.equals(register.getConfirmPassword(), register.getPassword(), "密码和确认密码不一致");
DefUser defUser = BeanUtil.toBean(register, DefUser.class);
defUserService.registerByEmail(defUser);
try {
defUserService.registerByEmail(defUser);
} catch (Exception e) {
if(e.getMessage().contains("Duplicate")){
throw new BizException("账号已存在!");
}
}
// 2. 根据注册系统构造子系统需要的user参数
return switch (LoginEnum.get(register.getSystemType())) {

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-oauth</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-oauth</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-oauth-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-oauth-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-oauth-facade</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-oauth</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>luohuo-oauth</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-dependencies-parent</artifactId>
<version>2.6.15</version>
<version>3.0.0</version>
<relativePath>../luohuo-dependencies-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>luohuo-presence</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>luohuo-presence-biz</artifactId>
<name>${project.artifactId}</name>
<description>基础服务-业务模块</description>
<dependencies>
<dependency>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-presence-entity</artifactId>
<version>${luohuo-project.version}</version>
</dependency>
<dependency>
<groupId>com.luohuo.basic</groupId>
<artifactId>luohuo-cache-starter</artifactId>
</dependency>
<dependency>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-database-mode</artifactId>
<version>${luohuo-project.version}</version>
</dependency>
<dependency>
<groupId>com.luohuo.basic</groupId>
<artifactId>luohuo-databases</artifactId>
</dependency>
<dependency>
<groupId>com.luohuo.basic</groupId>
<artifactId>luohuo-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<exclusions>
<exclusion>
<artifactId>jboss-annotations-api_1.3_spec</artifactId>
<groupId>org.jboss.spec.javax.annotation</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- @RefreshScope 需要使用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<!-- groovy-all -->
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>luohuo-presence</artifactId>
<groupId>com.luohuo.flex</groupId>
<version>2.6.15</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>luohuo-presence-controller</artifactId>
<name>${project.artifactId}</name>
<description>基础服务-控制器模块</description>
<dependencies>
<dependency>
<groupId>com.luohuo.flex</groupId>
<artifactId>luohuo-presence-biz</artifactId>
<version>${luohuo-project.version}</version>
</dependency>
</dependencies>
</project>

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