From e6623be1e55d316485c5647d35d6e8a3990d8065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E4=BF=9D=E5=AE=89?= <1409538202@qq.com> Date: Mon, 1 Dec 2025 10:08:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E6=97=B6=E9=80=9A=E8=AE=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 207 ++++++ src/main/docker/Dockerfile | 4 + .../com/realtime/RealTimeApplication.java | 26 + .../config/AnnotationBinaryWebSocket.java | 77 +++ .../com/realtime/config/BaiduTtsConfig.java | 15 + .../realtime/config/ClientVoiceHandler.java | 90 +++ .../java/com/realtime/config/CorsConfig.java | 24 + .../realtime/config/DoubaoVoiceConfig.java | 14 + .../com/realtime/config/FileProperties.java | 17 + .../com/realtime/config/GlobalException.java | 27 + .../com/realtime/config/MinioComponent.java | 25 + .../java/com/realtime/config/MinioConfig.java | 25 + .../realtime/config/MyBatisPlusConfig.java | 21 + .../java/com/realtime/config/NettyConfig.java | 12 + .../realtime/config/ProtocolFrameDecoder.java | 14 + .../java/com/realtime/config/RtasrConfig.java | 20 + .../config/WebSocketAnnotationConfig.java | 23 + .../controller/ChatListController.java | 47 ++ .../realtime/controller/FileController.java | 35 ++ .../controller/FriendshipController.java | 43 ++ .../realtime/controller/GroupController.java | 88 +++ .../controller/MessageController.java | 38 ++ .../realtime/controller/TtsController.java | 84 +++ .../realtime/exception/BusinessException.java | 22 + .../com/realtime/mappers/ChatListMapper.java | 22 + .../mappers/FriendRelationshipMapper.java | 18 + .../com/realtime/mappers/GroupListMapper.java | 30 + .../realtime/mappers/GroupMemberMapper.java | 34 + .../realtime/mappers/GroupMessageMapper.java | 18 + .../com/realtime/mappers/MessageMapper.java | 24 + .../model/baseModel/BaseQueryModel.java | 13 + .../com/realtime/model/pojo/ChatList.java | 47 ++ .../realtime/model/pojo/ChatListSaveReq.java | 11 + .../model/pojo/FriendRelationship.java | 37 ++ .../com/realtime/model/pojo/GroupList.java | 48 ++ .../com/realtime/model/pojo/GroupMember.java | 31 + .../com/realtime/model/pojo/GroupMessage.java | 63 ++ .../java/com/realtime/model/pojo/Message.java | 64 ++ .../query/ChatFriendRelationshipQueryReq.java | 12 + .../model/query/ChatListPageQueryReq.java | 12 + .../model/query/ChatQueryPageReq.java | 13 + .../model/query/GroupDetailQueryReq.java | 12 + .../model/query/GroupListQueryReq.java | 14 + .../model/query/GroupMemberListQueryReq.java | 16 + .../realtime/model/query/LoginQueryReq.java | 11 + .../realtime/model/query/MessageQueryReq.java | 18 + .../realtime/model/query/TtsOptionsReq.java | 50 ++ .../model/remove/DisbandGroupReq.java | 9 + .../realtime/model/remove/RemoveGroupReq.java | 9 + .../model/remove/RemovesGroupReq.java | 11 + .../model/update/GroupInventUpdateReq.java | 9 + .../model/update/UpdateUserPasswordReq.java | 13 + .../model/update/UserInfoUpdateReq.java | 16 + .../com/realtime/packets/AnswerPacket.java | 18 + .../realtime/packets/AutoSoftwarePacket.java | 23 + .../java/com/realtime/packets/CallPacket.java | 18 + .../com/realtime/packets/ConnectPacket.java | 16 + .../com/realtime/packets/FilePackets.java | 18 + .../com/realtime/packets/GroupPacket.java | 22 + .../com/realtime/packets/GroupSendPacket.java | 21 + .../realtime/packets/InventGroupPacket.java | 21 + .../com/realtime/packets/PingPongPacket.java | 15 + .../com/realtime/packets/RealTimePacket.java | 20 + .../realtime/packets/RemoveGroupPacket.java | 21 + .../com/realtime/packets/SendMsgPackets.java | 31 + .../realtime/packets/SystemNoticePackets.java | 17 + .../packets/basePackets/BasePackets.java | 24 + .../com/realtime/packets/command/Command.java | 25 + .../packets/resp/GroupResponsePacket.java | 18 + .../realtime/packets/server/NettyServer.java | 47 ++ .../server/handler/ConnectMessageHandler.java | 59 ++ .../server/handler/ExceptionHandler.java | 34 + .../server/handler/GroupMessageHandler.java | 48 ++ .../server/handler/InventGroupHandler.java | 60 ++ .../server/handler/JoinGroupHandler.java | 58 ++ .../server/handler/MessageSocketHandler.java | 78 +++ .../server/handler/PingPongHartHandler.java | 41 ++ .../server/handler/PrivateMessageHandler.java | 51 ++ .../handler/RealTimeTransferHandler.java | 44 ++ .../server/handler/RemoveGroupHandler.java | 46 ++ .../server/handler/SocketChannelHandler.java | 69 ++ .../handler/SystemNoticeMessageHandler.java | 18 + .../packets/strategy/PackStrategy.java | 12 + .../packets/strategy/PacketService.java | 12 + .../impl/AutoSoftwareStrategyImpl.java | 24 + .../impl/ConnectPackStrategyImpl.java | 26 + .../impl/GroupJoinPackStrategyImpl.java | 24 + .../impl/GroupSendPackStrategyImpl.java | 26 + .../strategy/impl/InventStrategyImpl.java | 27 + .../strategy/impl/PacketServiceImpl.java | 35 ++ .../impl/PingPongPackStrategyImpl.java | 24 + .../impl/PrivatePackStrategyImpl.java | 26 + .../impl/RealTimePackStrategyImpl.java | 24 + .../strategy/impl/RemoveStrategyImpl.java | 27 + .../realtime/service/BaiduAuthService.java | 46 ++ .../com/realtime/service/BaiduTtsService.java | 94 +++ .../com/realtime/service/ChatListService.java | 28 + .../realtime/service/DoubaoVoiceService.java | 105 ++++ .../com/realtime/service/FileService.java | 18 + .../service/FriendRelationshipService.java | 22 + .../realtime/service/GroupListService.java | 33 + .../realtime/service/GroupMemberService.java | 32 + .../realtime/service/GroupMessageService.java | 23 + .../com/realtime/service/MessageService.java | 30 + .../service/RealTimeVoiceService.java | 18 + .../service/impl/ChatListServiceImpl.java | 147 +++++ .../service/impl/ChatServiceImpl.java | 589 ++++++++++++++++++ .../service/impl/FileServiceImpl.java | 89 +++ .../impl/FriendRelationshipServiceImpl.java | 79 +++ .../service/impl/GroupListServiceImpl.java | 123 ++++ .../service/impl/GroupMemberServiceImpl.java | 76 +++ .../service/impl/GroupMessageServiceImpl.java | 26 + .../service/impl/MessageServiceImpl.java | 43 ++ .../impl/RealTimeVoiceServiceImpl.java | 250 ++++++++ .../com/realtime/sysconst/RTASRClient.java | 377 +++++++++++ .../java/com/realtime/sysconst/Result.java | 61 ++ .../sysconst/enumConst/ResultEnum.java | 30 + .../java/com/realtime/utils/Attributes.java | 9 + .../realtime/utils/Base64ToMultipartFile.java | 89 +++ .../utils/InputStreamMultipartFile.java | 66 ++ .../java/com/realtime/utils/SessionUtils.java | 74 +++ .../vo/ChatFriendRelationshipInfoVo.java | 21 + .../java/com/realtime/vo/ChatListInfoVo.java | 19 + src/main/java/com/realtime/vo/ChatReqVo.java | 9 + .../java/com/realtime/vo/FriendMessageVo.java | 19 + .../java/com/realtime/vo/GroupDetailVo.java | 13 + .../com/realtime/vo/GroupListMessagesVo.java | 13 + .../java/com/realtime/vo/GroupListVo.java | 15 + .../com/realtime/vo/GroupMemberListVo.java | 10 + .../java/com/realtime/vo/MessageInfoVo.java | 22 + .../java/com/realtime/vo/MessageItemVo.java | 10 + src/main/java/com/realtime/vo/MessageVo.java | 17 + src/main/java/com/realtime/vo/UploadVo.java | 16 + src/main/resources/application.yml | 53 ++ src/main/resources/mappers/ChatListMapper.xml | 38 ++ .../mappers/FriendRelationshipMapper.xml | 24 + .../resources/mappers/GroupListMapper.xml | 53 ++ .../resources/mappers/GroupMemberMapper.xml | 70 +++ .../resources/mappers/GroupMessageMapper.xml | 25 + src/main/resources/mappers/MessageMapper.xml | 57 ++ 140 files changed, 6032 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/docker/Dockerfile create mode 100644 src/main/java/com/realtime/RealTimeApplication.java create mode 100644 src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java create mode 100644 src/main/java/com/realtime/config/BaiduTtsConfig.java create mode 100644 src/main/java/com/realtime/config/ClientVoiceHandler.java create mode 100644 src/main/java/com/realtime/config/CorsConfig.java create mode 100644 src/main/java/com/realtime/config/DoubaoVoiceConfig.java create mode 100644 src/main/java/com/realtime/config/FileProperties.java create mode 100644 src/main/java/com/realtime/config/GlobalException.java create mode 100644 src/main/java/com/realtime/config/MinioComponent.java create mode 100644 src/main/java/com/realtime/config/MinioConfig.java create mode 100644 src/main/java/com/realtime/config/MyBatisPlusConfig.java create mode 100644 src/main/java/com/realtime/config/NettyConfig.java create mode 100644 src/main/java/com/realtime/config/ProtocolFrameDecoder.java create mode 100644 src/main/java/com/realtime/config/RtasrConfig.java create mode 100644 src/main/java/com/realtime/config/WebSocketAnnotationConfig.java create mode 100644 src/main/java/com/realtime/controller/ChatListController.java create mode 100644 src/main/java/com/realtime/controller/FileController.java create mode 100644 src/main/java/com/realtime/controller/FriendshipController.java create mode 100644 src/main/java/com/realtime/controller/GroupController.java create mode 100644 src/main/java/com/realtime/controller/MessageController.java create mode 100644 src/main/java/com/realtime/controller/TtsController.java create mode 100644 src/main/java/com/realtime/exception/BusinessException.java create mode 100644 src/main/java/com/realtime/mappers/ChatListMapper.java create mode 100644 src/main/java/com/realtime/mappers/FriendRelationshipMapper.java create mode 100644 src/main/java/com/realtime/mappers/GroupListMapper.java create mode 100644 src/main/java/com/realtime/mappers/GroupMemberMapper.java create mode 100644 src/main/java/com/realtime/mappers/GroupMessageMapper.java create mode 100644 src/main/java/com/realtime/mappers/MessageMapper.java create mode 100644 src/main/java/com/realtime/model/baseModel/BaseQueryModel.java create mode 100644 src/main/java/com/realtime/model/pojo/ChatList.java create mode 100644 src/main/java/com/realtime/model/pojo/ChatListSaveReq.java create mode 100644 src/main/java/com/realtime/model/pojo/FriendRelationship.java create mode 100644 src/main/java/com/realtime/model/pojo/GroupList.java create mode 100644 src/main/java/com/realtime/model/pojo/GroupMember.java create mode 100644 src/main/java/com/realtime/model/pojo/GroupMessage.java create mode 100644 src/main/java/com/realtime/model/pojo/Message.java create mode 100644 src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/ChatListPageQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/ChatQueryPageReq.java create mode 100644 src/main/java/com/realtime/model/query/GroupDetailQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/GroupListQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/LoginQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/MessageQueryReq.java create mode 100644 src/main/java/com/realtime/model/query/TtsOptionsReq.java create mode 100644 src/main/java/com/realtime/model/remove/DisbandGroupReq.java create mode 100644 src/main/java/com/realtime/model/remove/RemoveGroupReq.java create mode 100644 src/main/java/com/realtime/model/remove/RemovesGroupReq.java create mode 100644 src/main/java/com/realtime/model/update/GroupInventUpdateReq.java create mode 100644 src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java create mode 100644 src/main/java/com/realtime/model/update/UserInfoUpdateReq.java create mode 100644 src/main/java/com/realtime/packets/AnswerPacket.java create mode 100644 src/main/java/com/realtime/packets/AutoSoftwarePacket.java create mode 100644 src/main/java/com/realtime/packets/CallPacket.java create mode 100644 src/main/java/com/realtime/packets/ConnectPacket.java create mode 100644 src/main/java/com/realtime/packets/FilePackets.java create mode 100644 src/main/java/com/realtime/packets/GroupPacket.java create mode 100644 src/main/java/com/realtime/packets/GroupSendPacket.java create mode 100644 src/main/java/com/realtime/packets/InventGroupPacket.java create mode 100644 src/main/java/com/realtime/packets/PingPongPacket.java create mode 100644 src/main/java/com/realtime/packets/RealTimePacket.java create mode 100644 src/main/java/com/realtime/packets/RemoveGroupPacket.java create mode 100644 src/main/java/com/realtime/packets/SendMsgPackets.java create mode 100644 src/main/java/com/realtime/packets/SystemNoticePackets.java create mode 100644 src/main/java/com/realtime/packets/basePackets/BasePackets.java create mode 100644 src/main/java/com/realtime/packets/command/Command.java create mode 100644 src/main/java/com/realtime/packets/resp/GroupResponsePacket.java create mode 100644 src/main/java/com/realtime/packets/server/NettyServer.java create mode 100644 src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java create mode 100644 src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java create mode 100644 src/main/java/com/realtime/packets/strategy/PackStrategy.java create mode 100644 src/main/java/com/realtime/packets/strategy/PacketService.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java create mode 100644 src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java create mode 100644 src/main/java/com/realtime/service/BaiduAuthService.java create mode 100644 src/main/java/com/realtime/service/BaiduTtsService.java create mode 100644 src/main/java/com/realtime/service/ChatListService.java create mode 100644 src/main/java/com/realtime/service/DoubaoVoiceService.java create mode 100644 src/main/java/com/realtime/service/FileService.java create mode 100644 src/main/java/com/realtime/service/FriendRelationshipService.java create mode 100644 src/main/java/com/realtime/service/GroupListService.java create mode 100644 src/main/java/com/realtime/service/GroupMemberService.java create mode 100644 src/main/java/com/realtime/service/GroupMessageService.java create mode 100644 src/main/java/com/realtime/service/MessageService.java create mode 100644 src/main/java/com/realtime/service/RealTimeVoiceService.java create mode 100644 src/main/java/com/realtime/service/impl/ChatListServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/ChatServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/FileServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/GroupListServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/MessageServiceImpl.java create mode 100644 src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java create mode 100644 src/main/java/com/realtime/sysconst/RTASRClient.java create mode 100644 src/main/java/com/realtime/sysconst/Result.java create mode 100644 src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java create mode 100644 src/main/java/com/realtime/utils/Attributes.java create mode 100644 src/main/java/com/realtime/utils/Base64ToMultipartFile.java create mode 100644 src/main/java/com/realtime/utils/InputStreamMultipartFile.java create mode 100644 src/main/java/com/realtime/utils/SessionUtils.java create mode 100644 src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java create mode 100644 src/main/java/com/realtime/vo/ChatListInfoVo.java create mode 100644 src/main/java/com/realtime/vo/ChatReqVo.java create mode 100644 src/main/java/com/realtime/vo/FriendMessageVo.java create mode 100644 src/main/java/com/realtime/vo/GroupDetailVo.java create mode 100644 src/main/java/com/realtime/vo/GroupListMessagesVo.java create mode 100644 src/main/java/com/realtime/vo/GroupListVo.java create mode 100644 src/main/java/com/realtime/vo/GroupMemberListVo.java create mode 100644 src/main/java/com/realtime/vo/MessageInfoVo.java create mode 100644 src/main/java/com/realtime/vo/MessageItemVo.java create mode 100644 src/main/java/com/realtime/vo/MessageVo.java create mode 100644 src/main/java/com/realtime/vo/UploadVo.java create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/mappers/ChatListMapper.xml create mode 100644 src/main/resources/mappers/FriendRelationshipMapper.xml create mode 100644 src/main/resources/mappers/GroupListMapper.xml create mode 100644 src/main/resources/mappers/GroupMemberMapper.xml create mode 100644 src/main/resources/mappers/GroupMessageMapper.xml create mode 100644 src/main/resources/mappers/MessageMapper.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c073769 --- /dev/null +++ b/pom.xml @@ -0,0 +1,207 @@ + + + 4.0.0 + com.realTime + real-time-application + 0.0.1-SNAPSHOT + real-time-application + real-time-application + + 17 + UTF-8 + UTF-8 + 3.0.2 + + + + + com.squareup.okhttp3 + okhttp + 4.9.0 + + + + org.springframework.boot + spring-boot-starter-websocket + + + + commons-fileupload + commons-fileupload + 1.5 + + + + + commons-io + commons-io + 2.11.0 + + + + org.json + json + 20231013 + + + + org.java-websocket + Java-WebSocket + 1.5.3 + + + + org.apache.httpcomponents + httpclient + 4.5.14 + + + + org.springframework.boot + spring-boot-starter-websocket + 3.0.2 + + + + org.bytedeco + javacv-platform + 1.5.9 + + + mysql + mysql-connector-java + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba + druid-spring-boot-3-starter + 1.2.23 + + + + io.netty + netty-all + + + + io.swagger.core.v3 + swagger-annotations + 2.2.25 + + + + io.swagger.core.v3 + swagger-annotations-jakarta + 2.2.28 + + + com.baomidou + mybatis-plus-spring-boot3-starter + 3.5.10.1 + + + + com.baomidou + mybatis-plus-jsqlparser + 3.5.10.1 + + + + cn.hutool + hutool-all + 5.8.40 + + + + io.minio + minio + 8.5.13 + + + + com.google.zxing + core + 3.4.1 + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.58 + + + + + com.google.zxing + javase + 3.3.3 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + 1.18.40 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + UTF-8 + + + + org.springframework.boot + spring-boot-maven-plugin + 3.1.0 + + com.realtime.RealTimeApplication + false + + + + repackage + + repackage + + + + + + + + diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile new file mode 100644 index 0000000..7602896 --- /dev/null +++ b/src/main/docker/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:21-jre +VOLUME /tmp +COPY real.jar real.jar +ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/real.jar"] diff --git a/src/main/java/com/realtime/RealTimeApplication.java b/src/main/java/com/realtime/RealTimeApplication.java new file mode 100644 index 0000000..7b26005 --- /dev/null +++ b/src/main/java/com/realtime/RealTimeApplication.java @@ -0,0 +1,26 @@ +package com.realtime; + +import com.realtime.packets.server.NettyServer; +import lombok.RequiredArgsConstructor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@MapperScan("com.realtime.mappers") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class RealTimeApplication implements CommandLineRunner { + + private final NettyServer nettyServer; + + public static void main(String[] args) { + SpringApplication.run(RealTimeApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + nettyServer.run(); + } +} diff --git a/src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java b/src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java new file mode 100644 index 0000000..b7901b7 --- /dev/null +++ b/src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java @@ -0,0 +1,77 @@ +package com.realtime.config; + +import com.realtime.sysconst.RTASRClient; +import com.realtime.utils.Base64ToMultipartFile; +import jakarta.websocket.*; +import jakarta.websocket.server.ServerEndpoint; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.UUID; + +@Component +@ServerEndpoint("/binary") + +public class AnnotationBinaryWebSocket { + + private static final Logger logger = LoggerFactory.getLogger(AnnotationBinaryWebSocket.class); + + @OnOpen + public void onOpen(Session session) { + logger.info("注解方式 - WebSocket 连接建立: {}", session.getId()); + } + + @OnMessage(maxMessageSize = 10485760) // 10MB限制 + public void onBinaryMessage(byte[] data, Session session) { + logger.info("注解方式 - 收到二进制数据, 大小: {} bytes", data.length); + + // 处理数据 + processData(session, data); + + // 发送响应 + sendResponse(session, data); + } + + @OnMessage + public void onTextMessage(String message, Session session) { + logger.info("注解方式 - 收到文本消息: {}", message); + } + + @OnError + public void onError(Session session, Throwable error) { + logger.error("注解方式 - WebSocket 错误: {}", session.getId(), error); + } + + @OnClose + public void onClose(Session session, CloseReason closeReason) { + logger.info("注解方式 - WebSocket 连接关闭: {}, 原因: {}", + session.getId(), closeReason.getReasonPhrase()); + } + + private void processData(Session session, byte[] data) { + // 数据处理逻辑 + + } + + private void sendResponse(Session session, byte[] data) { + try { + MultipartFile convert = Base64ToMultipartFile.convert(data, UUID.randomUUID() + ".pcm"); + RTASRClient client = new RTASRClient("5d899195","4c428332836cd9481be4127c941f4167", "ZjFiMWViMGY0NDA4ODNkNDgxYzg0Yzg3", "",convert.getInputStream(),session); + client.connect(); + boolean b = client.sendAudio(); + // 发送处理结果 + ByteBuffer buffer = ByteBuffer.wrap(("已接收 " + data.length + " bytes").getBytes()); + + } catch (IOException e) { + logger.error("发送响应失败", e); + } + } +} diff --git a/src/main/java/com/realtime/config/BaiduTtsConfig.java b/src/main/java/com/realtime/config/BaiduTtsConfig.java new file mode 100644 index 0000000..34af0ea --- /dev/null +++ b/src/main/java/com/realtime/config/BaiduTtsConfig.java @@ -0,0 +1,15 @@ + +package com.realtime.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "baidu.tts") +@Data +public class BaiduTtsConfig { + private String appId; + private String apiKey; + private String secretKey; +} diff --git a/src/main/java/com/realtime/config/ClientVoiceHandler.java b/src/main/java/com/realtime/config/ClientVoiceHandler.java new file mode 100644 index 0000000..97380d1 --- /dev/null +++ b/src/main/java/com/realtime/config/ClientVoiceHandler.java @@ -0,0 +1,90 @@ +package com.realtime.config; + +import com.realtime.service.DoubaoVoiceService; +import lombok.extern.slf4j.Slf4j; +import org.bytedeco.javacv.FFmpegFrameGrabber; +import org.bytedeco.javacv.FFmpegFrameRecorder; +import org.bytedeco.javacv.Frame; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.BinaryMessage; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.BinaryWebSocketHandler; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +@Slf4j +@Component +public class ClientVoiceHandler extends BinaryWebSocketHandler { + private final DoubaoVoiceService doubaoVoiceService; + + public ClientVoiceHandler(DoubaoVoiceService doubaoVoiceService) { + this.doubaoVoiceService = doubaoVoiceService; + } + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + // 客户端会话 + // 建立与豆包 API 的连接 + + System.out.println(session); + doubaoVoiceService.connect(session); + } + + @Override + protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception { + System.out.println("2"); + // 接收客户端的音频数据(如 PCM 片段) + byte[] audioData = message.getPayload().array(); + // 预处理:确保格式符合豆包 API 要求(如采样率、位深) + byte[] processedData = preprocessAudio(audioData); + // 发送给豆包 API + doubaoVoiceService.sendAudio(processedData); + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + // 关闭与豆包 API 的连接 + doubaoVoiceService.close(); + } + + private byte[] preprocessAudio(byte[] audioData) { + if (audioData == null || audioData.length == 0) { + log.warn("接收到空的音频数据,跳过处理"); + return new byte[0]; // 返回空数组,避免后续错误 + } + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new ByteArrayInputStream(audioData)); + FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputStream, 1)) { + + grabber.start(); + // 打印输入音频信息(调试用) + log.debug("输入音频格式:{},采样率:{},声道:{}", + grabber.getFormat(), grabber.getSampleRate(), grabber.getAudioChannels()); + + recorder.setFormat("s16le"); + recorder.setSampleRate(16000); + recorder.setAudioChannels(1); + recorder.start(); + + Frame frame; + int frameCount = 0; + while ((frame = grabber.grab()) != null) { + recorder.record(frame); + frameCount++; + } + log.debug("成功处理 {} 帧音频", frameCount); + + recorder.stop(); + grabber.stop(); + return outputStream.toByteArray(); + + } catch (Exception e) { + log.error("音频预处理失败", e); + return new byte[0]; + } + } +} diff --git a/src/main/java/com/realtime/config/CorsConfig.java b/src/main/java/com/realtime/config/CorsConfig.java new file mode 100644 index 0000000..1f6e94a --- /dev/null +++ b/src/main/java/com/realtime/config/CorsConfig.java @@ -0,0 +1,24 @@ +package com.realtime.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration +public class CorsConfig { + + + @Bean + CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOriginPattern("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/java/com/realtime/config/DoubaoVoiceConfig.java b/src/main/java/com/realtime/config/DoubaoVoiceConfig.java new file mode 100644 index 0000000..65a9789 --- /dev/null +++ b/src/main/java/com/realtime/config/DoubaoVoiceConfig.java @@ -0,0 +1,14 @@ +package com.realtime.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +@Data +@Configuration +@ConfigurationProperties(prefix = "doubao.voice") +public class DoubaoVoiceConfig { + private String appId; + private String apiKey; // 豆包 API Key + private String accessToken; // 访问令牌 + private String websocketUrl; // 豆包实时语音接口的 WebSocket 地址(如 wss://api.doubao.com/voice/realtime) +} diff --git a/src/main/java/com/realtime/config/FileProperties.java b/src/main/java/com/realtime/config/FileProperties.java new file mode 100644 index 0000000..6a1b4dd --- /dev/null +++ b/src/main/java/com/realtime/config/FileProperties.java @@ -0,0 +1,17 @@ +package com.realtime.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "file") +public class FileProperties { + private int picMaxSize; + private int picMaxCount; + private String picAllowedFormats; + private String region; + private String allowedFormats; +} + diff --git a/src/main/java/com/realtime/config/GlobalException.java b/src/main/java/com/realtime/config/GlobalException.java new file mode 100644 index 0000000..ad3c355 --- /dev/null +++ b/src/main/java/com/realtime/config/GlobalException.java @@ -0,0 +1,27 @@ +package com.realtime.config; + + +import com.realtime.exception.BusinessException; +import com.realtime.sysconst.Result; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalException { + + @ExceptionHandler(BusinessException.class) + public Result handle(BusinessException e) { + return Result.systemError(e.getMessage(),e.getCode()); + } + + /** + * 兜底异常 + * @param e 异常 + * @return 异常类型 + */ + @ExceptionHandler(Exception.class) + public Result exceptionHandler(Exception e) { + return Result.fail(e.getMessage()); + } + +} diff --git a/src/main/java/com/realtime/config/MinioComponent.java b/src/main/java/com/realtime/config/MinioComponent.java new file mode 100644 index 0000000..ad33473 --- /dev/null +++ b/src/main/java/com/realtime/config/MinioComponent.java @@ -0,0 +1,25 @@ +package com.realtime.config; + +import io.minio.MinioClient; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class MinioComponent { + + private final MinioConfig minioConfig; + + @Bean + public MinioClient minioClient() { + return MinioClient.builder() + .endpoint(minioConfig.getEndpoint()) + .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()) + .build(); + } + +} diff --git a/src/main/java/com/realtime/config/MinioConfig.java b/src/main/java/com/realtime/config/MinioConfig.java new file mode 100644 index 0000000..1ab843c --- /dev/null +++ b/src/main/java/com/realtime/config/MinioConfig.java @@ -0,0 +1,25 @@ +package com.realtime.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; + +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class MinioConfig { + + @Value("${minio.endpoint}") + private String endpoint; + + @Value("${minio.access-key}") + private String accessKey; + + @Value("${minio.secret-key}") + private String secretKey; + + @Value("${minio.bucket-name}") + private String bucketName; + + +} diff --git a/src/main/java/com/realtime/config/MyBatisPlusConfig.java b/src/main/java/com/realtime/config/MyBatisPlusConfig.java new file mode 100644 index 0000000..186fce6 --- /dev/null +++ b/src/main/java/com/realtime/config/MyBatisPlusConfig.java @@ -0,0 +1,21 @@ +package com.realtime.config; + + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MyBatisPlusConfig { + /** + * 分页插件 + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } +} diff --git a/src/main/java/com/realtime/config/NettyConfig.java b/src/main/java/com/realtime/config/NettyConfig.java new file mode 100644 index 0000000..0c96541 --- /dev/null +++ b/src/main/java/com/realtime/config/NettyConfig.java @@ -0,0 +1,12 @@ +package com.realtime.config; + +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.util.concurrent.GlobalEventExecutor; +import org.springframework.stereotype.Component; + + +@Component +public class NettyConfig { + public final static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); +} diff --git a/src/main/java/com/realtime/config/ProtocolFrameDecoder.java b/src/main/java/com/realtime/config/ProtocolFrameDecoder.java new file mode 100644 index 0000000..f64c8db --- /dev/null +++ b/src/main/java/com/realtime/config/ProtocolFrameDecoder.java @@ -0,0 +1,14 @@ +package com.realtime.config; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; + +public class ProtocolFrameDecoder extends LengthFieldBasedFrameDecoder { + + public ProtocolFrameDecoder() { + this(1024, 12, 4, 0, 0); + } + + public ProtocolFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) { + super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip); + } +} diff --git a/src/main/java/com/realtime/config/RtasrConfig.java b/src/main/java/com/realtime/config/RtasrConfig.java new file mode 100644 index 0000000..1062a76 --- /dev/null +++ b/src/main/java/com/realtime/config/RtasrConfig.java @@ -0,0 +1,20 @@ +package com.realtime.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "rtsa") +public class RtasrConfig { + private String appId; + private String accessKeyId; + private String accessKeySecret; + private String baseWsUrl; + private String audioEncode; + private String lang; + private Integer samplerate; + private Integer audioFameSize; + private Integer frameIntervalMs; +} diff --git a/src/main/java/com/realtime/config/WebSocketAnnotationConfig.java b/src/main/java/com/realtime/config/WebSocketAnnotationConfig.java new file mode 100644 index 0000000..e241881 --- /dev/null +++ b/src/main/java/com/realtime/config/WebSocketAnnotationConfig.java @@ -0,0 +1,23 @@ +package com.realtime.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +@Configuration +@EnableWebSocket +public class WebSocketAnnotationConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + // 空实现,因为使用 @ServerEndpoint + } + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/src/main/java/com/realtime/controller/ChatListController.java b/src/main/java/com/realtime/controller/ChatListController.java new file mode 100644 index 0000000..b503ffa --- /dev/null +++ b/src/main/java/com/realtime/controller/ChatListController.java @@ -0,0 +1,47 @@ +package com.realtime.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.ChatList; +import com.realtime.model.query.ChatListPageQueryReq; +import com.realtime.service.ChatListService; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatListInfoVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/chatList") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ChatListController { + + private final ChatListService chatListService; + + @PostMapping("/getChatFriend") + Result> getChatFriend(@RequestBody ChatListPageQueryReq chatListPageQueryReq){ + return chatListService.getChatList(chatListPageQueryReq); + } + + @PostMapping("/save") + Result saveChatList(@RequestBody List chatList){ + return chatListService.saveSignChatList(chatList); + } + + @PostMapping("/delete") + Result deleteChatList(@RequestBody ChatList ids){ + return chatListService.deleteSignChatList(ids); + } + + @PostMapping("/update") + Result updateChatList(@RequestBody List chatList){ + return chatListService.updateChatListFName(chatList); + } +} diff --git a/src/main/java/com/realtime/controller/FileController.java b/src/main/java/com/realtime/controller/FileController.java new file mode 100644 index 0000000..71f0e25 --- /dev/null +++ b/src/main/java/com/realtime/controller/FileController.java @@ -0,0 +1,35 @@ +package com.realtime.controller; + + + +import com.realtime.service.FileService; +import com.realtime.sysconst.Result; +import com.realtime.vo.UploadVo; +import io.minio.errors.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +@Slf4j +@RestController +@RequestMapping("/file") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class FileController { + + private final FileService fileService; + + @PostMapping("/upload") + Result upload(@RequestPart("file") MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException { + return fileService.uploadFile(file); + } + +} diff --git a/src/main/java/com/realtime/controller/FriendshipController.java b/src/main/java/com/realtime/controller/FriendshipController.java new file mode 100644 index 0000000..56c9bfa --- /dev/null +++ b/src/main/java/com/realtime/controller/FriendshipController.java @@ -0,0 +1,43 @@ +package com.realtime.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.FriendRelationship; +import com.realtime.model.query.ChatFriendRelationshipQueryReq; +import com.realtime.service.FriendRelationshipService; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatFriendRelationshipInfoVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/friendship") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class FriendshipController { + + private final FriendRelationshipService friendRelationshipService; + + @PostMapping("/getFriendship") + Result> selectByPhone(@RequestBody ChatFriendRelationshipQueryReq req){ + return friendRelationshipService.selectByPhone(req); + } + + @PostMapping("/saveShip") + Result saveShip(@RequestBody FriendRelationship req){ + return friendRelationshipService.saveShip(req); + } + + @PostMapping("/remove") + Result remove(@RequestBody List ids){ + return friendRelationshipService.removeIds(ids); + } + +} diff --git a/src/main/java/com/realtime/controller/GroupController.java b/src/main/java/com/realtime/controller/GroupController.java new file mode 100644 index 0000000..ce420d0 --- /dev/null +++ b/src/main/java/com/realtime/controller/GroupController.java @@ -0,0 +1,88 @@ +package com.realtime.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.google.zxing.WriterException; +import com.realtime.model.pojo.GroupMember; +import com.realtime.model.query.GroupDetailQueryReq; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.model.query.GroupMemberListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.remove.RemoveGroupReq; +import com.realtime.model.remove.RemovesGroupReq; +import com.realtime.model.update.GroupInventUpdateReq; +import com.realtime.service.GroupListService; +import com.realtime.service.GroupMemberService; +import com.realtime.service.GroupMessageService; +import com.realtime.sysconst.Result; +import com.realtime.vo.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/group") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class GroupController { + + private final GroupListService groupListService; + + private final GroupMessageService groupMessageService; + + private final GroupMemberService groupMemberService; + + @PostMapping("/getGroup") + Result> getGroup(@RequestBody GroupListQueryReq groupListQueryReq) { + return groupListService.getGroup(groupListQueryReq); + } + + @PostMapping("/getGroupList") + Result> getGroupList(@RequestBody GroupListQueryReq req) { + return groupMessageService.getGroupList(req); + } + + @PostMapping("/getGroupMemberList") + Result> getGroupMemberList(@RequestBody GroupMemberListQueryReq req) { + return groupMemberService.getMemberList(req); + } + + @PostMapping("/getGroupDetail") + Result getGroupDetail(@RequestBody GroupDetailQueryReq queryReq) throws IOException, WriterException { + return groupListService.getGroupDetail(queryReq); + } + + @PostMapping("/updateInvent") + Result updateInvent(@RequestBody GroupInventUpdateReq groupInventUpdateReq) { + return groupListService.updateInvent(groupInventUpdateReq); + } + + @PostMapping("/inventFriend") + Result> getAllByGroupIdAndMemberId(@RequestBody GroupMemberListQueryReq queryReq) { + return groupMemberService.getAllByGroupIdAndMemberId(queryReq); + } + + @PostMapping("/remove") + Result remove(@RequestBody RemovesGroupReq ids) { + return groupMemberService.removeMembersByIds(ids); + } + + @PostMapping("/saveInvent") + Result saveInvent(@RequestBody List groupMembers,@RequestParam("launchContactId")String launchContactId) { + return groupMemberService.saveInvent(groupMembers,launchContactId); + } + + @PostMapping("/disband") + Result disband(@RequestBody DisbandGroupReq disbandGroupReq) { + return groupListService.disband(disbandGroupReq); + } + + @PostMapping("/quit") + Result quit(@RequestBody RemoveGroupReq removeGroupReq) { + return groupMemberService.quit(removeGroupReq); + } +} diff --git a/src/main/java/com/realtime/controller/MessageController.java b/src/main/java/com/realtime/controller/MessageController.java new file mode 100644 index 0000000..db5ba61 --- /dev/null +++ b/src/main/java/com/realtime/controller/MessageController.java @@ -0,0 +1,38 @@ +package com.realtime.controller; + + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.query.ChatQueryPageReq; +import com.realtime.model.query.MessageQueryReq; +import com.realtime.service.MessageService; +import com.realtime.sysconst.Result; +import com.realtime.vo.FriendMessageVo; +import com.realtime.vo.MessageVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/message") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class MessageController { + + private final MessageService messageService; + + @PostMapping("/list") + Result> getList(@RequestBody MessageQueryReq messageQueryReq){ + return messageService.getList(messageQueryReq); + } + @PostMapping("/getFriendChatList") + Result> getFriendChatList(@RequestBody MessageQueryReq messageQueryReq){ + return messageService.getFriendChatList(messageQueryReq); + } + + +} diff --git a/src/main/java/com/realtime/controller/TtsController.java b/src/main/java/com/realtime/controller/TtsController.java new file mode 100644 index 0000000..abc766f --- /dev/null +++ b/src/main/java/com/realtime/controller/TtsController.java @@ -0,0 +1,84 @@ + +package com.realtime.controller; + +import com.realtime.exception.BusinessException; +import com.realtime.model.query.TtsOptionsReq; +import com.realtime.service.BaiduTtsService; +import com.realtime.service.FileService; +import com.realtime.sysconst.Result; +import com.realtime.utils.InputStreamMultipartFile; +import com.realtime.vo.UploadVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.ByteArrayInputStream; +import java.util.UUID; + +@Slf4j +@RestController +@RequestMapping("/tts") +@RequiredArgsConstructor(onConstructor_ = {@Autowired}) +public class TtsController { + + private final BaiduTtsService ttsService; + + private final FileService fileService; + + /** + * 文本转语音,返回音频流 + */ + @GetMapping("/speech") + public Result textToSpeech(@RequestParam("text") String text, + @RequestParam(defaultValue = "0",value = "per") int per, + @RequestParam(defaultValue = "5",value = "speed") int speed) { + try { + TtsOptionsReq options = TtsOptionsReq.builder() + .per(per) + .speed(speed) + .build(); + + byte[] audioData = ttsService.textToSpeech(text, options); + + if (audioData == null) { + throw new BusinessException("转换异常"); + } + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(audioData); + + InputStreamMultipartFile speech = new InputStreamMultipartFile(UUID.randomUUID().toString(), "speech.mp3", "audio/mp3", byteArrayInputStream); + + return fileService.uploadFile(speech); + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + /** + * 文本转语音并下载 + */ + @PostMapping("/download") + public ResponseEntity downloadSpeech(@RequestParam String text) { + try { + byte[] audioData = ttsService.textToSpeech(text, TtsOptionsReq.defaultOptions()); + + if (audioData == null) { + return ResponseEntity.badRequest().build(); + } + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + headers.setContentDispositionFormData("attachment", "speech.mp3"); + + return ResponseEntity.ok() + .headers(headers) + .body(audioData); + } catch (Exception e) { + return ResponseEntity.internalServerError().build(); + } + } +} diff --git a/src/main/java/com/realtime/exception/BusinessException.java b/src/main/java/com/realtime/exception/BusinessException.java new file mode 100644 index 0000000..38d8e45 --- /dev/null +++ b/src/main/java/com/realtime/exception/BusinessException.java @@ -0,0 +1,22 @@ +package com.realtime.exception; + + +import com.realtime.sysconst.enumConst.ResultEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class BusinessException extends RuntimeException { + private Integer code; + private ResultEnum result; + + public BusinessException(ResultEnum result) { + super(result.getMsg()); + this.code = result.getCode(); + } + + public BusinessException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/realtime/mappers/ChatListMapper.java b/src/main/java/com/realtime/mappers/ChatListMapper.java new file mode 100644 index 0000000..8c9550f --- /dev/null +++ b/src/main/java/com/realtime/mappers/ChatListMapper.java @@ -0,0 +1,22 @@ +package com.realtime.mappers; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.ChatList; +import com.realtime.model.query.ChatListPageQueryReq; +import com.realtime.vo.ChatListInfoVo; +import org.apache.ibatis.annotations.Param; + +public interface ChatListMapper extends BaseMapper { + + String getMachineIdBySenderId(@Param("id") String senderId); + + IPage getChatList(@Param("reqPage") IPage page, @Param("req") ChatListPageQueryReq chatListPageQueryReq); + + void deleteFriend(@Param("id") String id,@Param("receiver") String receiver); +} + + + + diff --git a/src/main/java/com/realtime/mappers/FriendRelationshipMapper.java b/src/main/java/com/realtime/mappers/FriendRelationshipMapper.java new file mode 100644 index 0000000..600c62d --- /dev/null +++ b/src/main/java/com/realtime/mappers/FriendRelationshipMapper.java @@ -0,0 +1,18 @@ +package com.realtime.mappers; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.FriendRelationship; +import com.realtime.model.query.ChatFriendRelationshipQueryReq; +import com.realtime.vo.ChatFriendRelationshipInfoVo; +import org.apache.ibatis.annotations.Param; + +public interface FriendRelationshipMapper extends BaseMapper { + + + IPage selectByPhone(@Param("page") IPage page, @Param("req") ChatFriendRelationshipQueryReq req); + + void updateStateById(@Param("id") Long friendRelationshipId); + +} diff --git a/src/main/java/com/realtime/mappers/GroupListMapper.java b/src/main/java/com/realtime/mappers/GroupListMapper.java new file mode 100644 index 0000000..2a21519 --- /dev/null +++ b/src/main/java/com/realtime/mappers/GroupListMapper.java @@ -0,0 +1,30 @@ +package com.realtime.mappers; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.GroupList; +import com.realtime.model.query.GroupDetailQueryReq; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.update.GroupInventUpdateReq; +import com.realtime.vo.GroupDetailVo; +import com.realtime.vo.GroupListVo; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface GroupListMapper extends BaseMapper { + + IPage getGroup(@Param("reqpage")IPage iPage, @Param("req") GroupListQueryReq loginIdAsLong); + + GroupDetailVo getGroupDetail(@Param("req") GroupDetailQueryReq queryReq); + + void updateInvent(@Param("req") GroupInventUpdateReq groupInventUpdateReq); + + int isOwner(@Param("req") DisbandGroupReq disbandGroupReq); +} + + + + diff --git a/src/main/java/com/realtime/mappers/GroupMemberMapper.java b/src/main/java/com/realtime/mappers/GroupMemberMapper.java new file mode 100644 index 0000000..db17287 --- /dev/null +++ b/src/main/java/com/realtime/mappers/GroupMemberMapper.java @@ -0,0 +1,34 @@ +package com.realtime.mappers; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.GroupMember; +import com.realtime.model.query.GroupMemberListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.remove.RemoveGroupReq; +import com.realtime.model.remove.RemovesGroupReq; +import com.realtime.vo.ChatListInfoVo; +import com.realtime.vo.GroupMemberListVo; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface GroupMemberMapper extends BaseMapper { + + IPage getMemberList(@Param("page") IPage queryReqIPage, @Param("req") GroupMemberListQueryReq queryReq); + + IPage getAllByGroupIdAndMemberId(@Param("page") IPage queryReqIPage, @Param("req") GroupMemberListQueryReq queryReq); + + void quit(RemoveGroupReq removeGroupReq); + + void removeByGroupId(@Param("req") DisbandGroupReq disbandGroupReq); + + void removesByGroupPhoneAndGroupId(@Param("req") RemovesGroupReq ids); + + List getByGroupContactId(@Param("groupContactId")String groupContactId); +} + + + + diff --git a/src/main/java/com/realtime/mappers/GroupMessageMapper.java b/src/main/java/com/realtime/mappers/GroupMessageMapper.java new file mode 100644 index 0000000..9ba7d33 --- /dev/null +++ b/src/main/java/com/realtime/mappers/GroupMessageMapper.java @@ -0,0 +1,18 @@ +package com.realtime.mappers; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.GroupMessage; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.vo.GroupListMessagesVo; +import org.apache.ibatis.annotations.Param; + +public interface GroupMessageMapper extends BaseMapper { + + IPage getGroupList(@Param("page") IPage req, @Param("req") GroupListQueryReq req1); +} + + + + diff --git a/src/main/java/com/realtime/mappers/MessageMapper.java b/src/main/java/com/realtime/mappers/MessageMapper.java new file mode 100644 index 0000000..326f9be --- /dev/null +++ b/src/main/java/com/realtime/mappers/MessageMapper.java @@ -0,0 +1,24 @@ +package com.realtime.mappers; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.pojo.Message; +import com.realtime.model.query.MessageQueryReq; +import com.realtime.vo.FriendMessageVo; +import com.realtime.vo.MessageItemVo; +import com.realtime.vo.MessageVo; +import org.apache.ibatis.annotations.Param; + +public interface MessageMapper extends BaseMapper { + + IPage getMsgList(@Param("req") IPage messageQueryReqIPage, @Param("req") MessageQueryReq messageQueryReq); + + IPage getFriendMsgList(@Param("page") IPage messageQueryReqIPage, @Param("req") MessageQueryReq messageQueryReq); + + MessageItemVo selectLastContent(@Param("sessionId") Long sessionId); +} + + + + diff --git a/src/main/java/com/realtime/model/baseModel/BaseQueryModel.java b/src/main/java/com/realtime/model/baseModel/BaseQueryModel.java new file mode 100644 index 0000000..d6ae6e1 --- /dev/null +++ b/src/main/java/com/realtime/model/baseModel/BaseQueryModel.java @@ -0,0 +1,13 @@ +package com.realtime.model.baseModel; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class BaseQueryModel extends Page { + private Long id; + private String contactId; +} diff --git a/src/main/java/com/realtime/model/pojo/ChatList.java b/src/main/java/com/realtime/model/pojo/ChatList.java new file mode 100644 index 0000000..8b212fe --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/ChatList.java @@ -0,0 +1,47 @@ +package com.realtime.model.pojo; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + + +@Data +public class ChatList implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + /** + * 好友昵称 + */ + private String friendNickName; + /** + * 发送者用户电话 + */ + private String sender; + /** + * 接受者Id + */ + private String receiver; + /** + * 是否将好友置顶 + */ + private Integer isTop; + /** + * 会话Id + */ + private Long sessionId; + /** + * 用户是不可以删除助手的 只有用户与用户之间可以删除 1 = 可以 0 = 不可以 + */ + private Integer isDelete; + private LocalDateTime createdTime; + + @TableField(exist = false) + private Long friendRelationshipId; + + +} diff --git a/src/main/java/com/realtime/model/pojo/ChatListSaveReq.java b/src/main/java/com/realtime/model/pojo/ChatListSaveReq.java new file mode 100644 index 0000000..df88404 --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/ChatListSaveReq.java @@ -0,0 +1,11 @@ +package com.realtime.model.pojo; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class ChatListSaveReq implements Serializable { + private ChatList chatList; + private ChatList newChatList; +} diff --git a/src/main/java/com/realtime/model/pojo/FriendRelationship.java b/src/main/java/com/realtime/model/pojo/FriendRelationship.java new file mode 100644 index 0000000..8cd31e2 --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/FriendRelationship.java @@ -0,0 +1,37 @@ +package com.realtime.model.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public class FriendRelationship implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + private String sendId; + /** + * 发起添加好友的时间 + */ + private LocalDateTime createdTime; + /** + * 0 = 未通过 1 = 通过好友 + */ + private Integer state; + + private String friendNickName; + /** + * 这个是被申请加好友的一方 + */ + private String recipientId; + /** + * 写入到chat_list的session_id + */ + private Long sessionId = System.currentTimeMillis(); + +} diff --git a/src/main/java/com/realtime/model/pojo/GroupList.java b/src/main/java/com/realtime/model/pojo/GroupList.java new file mode 100644 index 0000000..d09d3ce --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/GroupList.java @@ -0,0 +1,48 @@ +package com.realtime.model.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public class GroupList implements Serializable { + @TableId(type = IdType.INPUT) + private Long id; + + /** + * + */ + private String name; + + /** + * 创建者 + */ + private String creator; + + /** + * + */ + private LocalDateTime createdTime; + + /** + * 群图片 + */ + private String picture; + + /** + * 固定值 + */ + private Integer type; + + /** + * 是否需要邀请才能加入 1 = 是 0 = 否 + */ + private Integer isInvent; + + + private Integer owner; + +} diff --git a/src/main/java/com/realtime/model/pojo/GroupMember.java b/src/main/java/com/realtime/model/pojo/GroupMember.java new file mode 100644 index 0000000..4f7519b --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/GroupMember.java @@ -0,0 +1,31 @@ +package com.realtime.model.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public class GroupMember implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + /** + * + */ + private Long groupId; + + /** + * 成员电话号码 + */ + private String groupContactId; + + /** + * 加入时间 + */ + private LocalDateTime createdTime; + + +} diff --git a/src/main/java/com/realtime/model/pojo/GroupMessage.java b/src/main/java/com/realtime/model/pojo/GroupMessage.java new file mode 100644 index 0000000..77cedc6 --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/GroupMessage.java @@ -0,0 +1,63 @@ +package com.realtime.model.pojo; + + + + +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.realtime.packets.GroupSendPacket; +import lombok.Data; + +import java.io.Serializable; + +@Data + +public class GroupMessage implements Serializable { + /** + * + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 消息内容 + */ + private String message; + + /** + * 群Id + */ + private Long groupId; + + /** + * 发送者Id + */ + private String sender; + + /** + * + */ + private Long createTime; + + /** + * 0消息 1 =文件/文件 + */ + private Integer messageType; + + private String contentJson; + + public GroupMessage(GroupSendPacket groupMessage) { + this.createTime = System.currentTimeMillis(); + this.message = groupMessage.getMessage(); + this.groupId = groupMessage.getGroupId(); + this.sender = groupMessage.getSender(); + + this.messageType = Integer.valueOf(groupMessage.getMessageType()); + if (this.messageType == 1) { + this.contentJson = JSON.toJSONString(groupMessage.getUploadVos()); + } + } + + +} diff --git a/src/main/java/com/realtime/model/pojo/Message.java b/src/main/java/com/realtime/model/pojo/Message.java new file mode 100644 index 0000000..ec7b805 --- /dev/null +++ b/src/main/java/com/realtime/model/pojo/Message.java @@ -0,0 +1,64 @@ +package com.realtime.model.pojo; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.realtime.packets.SendMsgPackets; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Message { + /** + * + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 发送者手机号 + */ + private String sender; + + /** + * 接受者id + */ + private String receiver; + + /** + * 消息类型(0:文字;1:图片;2:文件) + */ + private String messageType; + + /** + * 内容或url + */ + private String content; + + private Long sessionId; + + /** + * 发送时间 + */ + private Long createTime; + + private String contentJson; + + public Message(SendMsgPackets params) { + this.sender = params.getSender(); + this.receiver = params.getReceiver(); + this.createTime = System.currentTimeMillis(); + this.messageType = String.valueOf(params.getContentType()); + this.content = params.getMessage(); + this.sessionId = params.getSessionId(); + this.contentJson = JSONObject.toJSONString(params.getUploadVos()); + } + +} diff --git a/src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java b/src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java new file mode 100644 index 0000000..7874dcc --- /dev/null +++ b/src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java @@ -0,0 +1,12 @@ +package com.realtime.model.query; + + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ChatFriendRelationshipQueryReq extends BaseQueryModel { + private String sendId; +} diff --git a/src/main/java/com/realtime/model/query/ChatListPageQueryReq.java b/src/main/java/com/realtime/model/query/ChatListPageQueryReq.java new file mode 100644 index 0000000..9a751de --- /dev/null +++ b/src/main/java/com/realtime/model/query/ChatListPageQueryReq.java @@ -0,0 +1,12 @@ +package com.realtime.model.query; + + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ChatListPageQueryReq extends BaseQueryModel { + private String sendId; +} diff --git a/src/main/java/com/realtime/model/query/ChatQueryPageReq.java b/src/main/java/com/realtime/model/query/ChatQueryPageReq.java new file mode 100644 index 0000000..ff5d9e4 --- /dev/null +++ b/src/main/java/com/realtime/model/query/ChatQueryPageReq.java @@ -0,0 +1,13 @@ +package com.realtime.model.query; + + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +public class ChatQueryPageReq extends BaseQueryModel { +} diff --git a/src/main/java/com/realtime/model/query/GroupDetailQueryReq.java b/src/main/java/com/realtime/model/query/GroupDetailQueryReq.java new file mode 100644 index 0000000..9dcea0e --- /dev/null +++ b/src/main/java/com/realtime/model/query/GroupDetailQueryReq.java @@ -0,0 +1,12 @@ +package com.realtime.model.query; + + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class GroupDetailQueryReq extends BaseQueryModel { + private Long groupId; +} diff --git a/src/main/java/com/realtime/model/query/GroupListQueryReq.java b/src/main/java/com/realtime/model/query/GroupListQueryReq.java new file mode 100644 index 0000000..f1b2637 --- /dev/null +++ b/src/main/java/com/realtime/model/query/GroupListQueryReq.java @@ -0,0 +1,14 @@ +package com.realtime.model.query; + + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class GroupListQueryReq extends BaseQueryModel { + private Long groupId; + private Long beginTime; + private Long endTime; +} diff --git a/src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java b/src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java new file mode 100644 index 0000000..fbdeafc --- /dev/null +++ b/src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java @@ -0,0 +1,16 @@ +package com.realtime.model.query; + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +@EqualsAndHashCode(callSuper = true) +@Data +public class GroupMemberListQueryReq extends BaseQueryModel { + private Long groupId; + private String name; + private LocalDateTime beginTime; + private LocalDateTime endTime; +} diff --git a/src/main/java/com/realtime/model/query/LoginQueryReq.java b/src/main/java/com/realtime/model/query/LoginQueryReq.java new file mode 100644 index 0000000..e65ffa9 --- /dev/null +++ b/src/main/java/com/realtime/model/query/LoginQueryReq.java @@ -0,0 +1,11 @@ +package com.realtime.model.query; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class LoginQueryReq implements Serializable { + private Long phone; + private String password; +} diff --git a/src/main/java/com/realtime/model/query/MessageQueryReq.java b/src/main/java/com/realtime/model/query/MessageQueryReq.java new file mode 100644 index 0000000..a32f410 --- /dev/null +++ b/src/main/java/com/realtime/model/query/MessageQueryReq.java @@ -0,0 +1,18 @@ +package com.realtime.model.query; + + +import com.realtime.model.baseModel.BaseQueryModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + + + +@EqualsAndHashCode(callSuper = true) +@Data +public class MessageQueryReq extends BaseQueryModel { + private Long taskId; + private Long acceptId; + private Long sessionId; + private Long beginTime; + private Long endTime; +} diff --git a/src/main/java/com/realtime/model/query/TtsOptionsReq.java b/src/main/java/com/realtime/model/query/TtsOptionsReq.java new file mode 100644 index 0000000..6543eda --- /dev/null +++ b/src/main/java/com/realtime/model/query/TtsOptionsReq.java @@ -0,0 +1,50 @@ +package com.realtime.model.query; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TtsOptionsReq { + /** + * 语言 + */ + @Builder.Default + private String lang = "zh"; + + /** + * 语速,0-15,默认为5 + */ + @Builder.Default + private int speed = 5; + + /** + * 音调,0-15,默认为5 + */ + @Builder.Default + private int pitch = 5; + + /** + * 音量,0-15,默认为5 + */ + @Builder.Default + private int volume = 5; + + /** + * 发音人选择 + * 0-女声,1-男声,3-情感合成-度逍遥,4-情感合成-度丫丫 + */ + @Builder.Default + private int per = 4100; + + /** + * 音频格式 + * 3:mp3(默认) 4:pcm-16k 5:pcm-8k 6:wav + */ + @Builder.Default + private String aue = "3"; + + public static TtsOptionsReq defaultOptions() { + return TtsOptionsReq.builder().build(); + } +} diff --git a/src/main/java/com/realtime/model/remove/DisbandGroupReq.java b/src/main/java/com/realtime/model/remove/DisbandGroupReq.java new file mode 100644 index 0000000..944addd --- /dev/null +++ b/src/main/java/com/realtime/model/remove/DisbandGroupReq.java @@ -0,0 +1,9 @@ +package com.realtime.model.remove; + +import lombok.Data; + +@Data +public class DisbandGroupReq { + private Long groupId; + private String groupContactId; +} diff --git a/src/main/java/com/realtime/model/remove/RemoveGroupReq.java b/src/main/java/com/realtime/model/remove/RemoveGroupReq.java new file mode 100644 index 0000000..114aaec --- /dev/null +++ b/src/main/java/com/realtime/model/remove/RemoveGroupReq.java @@ -0,0 +1,9 @@ +package com.realtime.model.remove; + +import lombok.Data; + +@Data +public class RemoveGroupReq { + private Long groupId; + private String groupContactId; +} diff --git a/src/main/java/com/realtime/model/remove/RemovesGroupReq.java b/src/main/java/com/realtime/model/remove/RemovesGroupReq.java new file mode 100644 index 0000000..2612af4 --- /dev/null +++ b/src/main/java/com/realtime/model/remove/RemovesGroupReq.java @@ -0,0 +1,11 @@ +package com.realtime.model.remove; + +import lombok.Data; + +import java.util.List; + +@Data +public class RemovesGroupReq { + private Long groupId; + private List groupContactId; +} diff --git a/src/main/java/com/realtime/model/update/GroupInventUpdateReq.java b/src/main/java/com/realtime/model/update/GroupInventUpdateReq.java new file mode 100644 index 0000000..c516c18 --- /dev/null +++ b/src/main/java/com/realtime/model/update/GroupInventUpdateReq.java @@ -0,0 +1,9 @@ +package com.realtime.model.update; + +import lombok.Data; + +@Data +public class GroupInventUpdateReq { + private Long groupId; + private Integer invent; +} diff --git a/src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java b/src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java new file mode 100644 index 0000000..6f66674 --- /dev/null +++ b/src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java @@ -0,0 +1,13 @@ +package com.realtime.model.update; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class UpdateUserPasswordReq implements Serializable { + private String code; + private String password; + private Long phone; + private String type; +} diff --git a/src/main/java/com/realtime/model/update/UserInfoUpdateReq.java b/src/main/java/com/realtime/model/update/UserInfoUpdateReq.java new file mode 100644 index 0000000..6badcaf --- /dev/null +++ b/src/main/java/com/realtime/model/update/UserInfoUpdateReq.java @@ -0,0 +1,16 @@ +package com.realtime.model.update; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class UserInfoUpdateReq implements Serializable { + private Long id; + private Long phone; + private String nickName; + private String avatar; + private String occupation; + private String region; + private Integer sex; +} diff --git a/src/main/java/com/realtime/packets/AnswerPacket.java b/src/main/java/com/realtime/packets/AnswerPacket.java new file mode 100644 index 0000000..730bd38 --- /dev/null +++ b/src/main/java/com/realtime/packets/AnswerPacket.java @@ -0,0 +1,18 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class AnswerPacket extends BasePackets { + private String sdp; + private String type; // answer + @Override + public Byte getCommand() { + return Command.ANSWER; + } +} diff --git a/src/main/java/com/realtime/packets/AutoSoftwarePacket.java b/src/main/java/com/realtime/packets/AutoSoftwarePacket.java new file mode 100644 index 0000000..723faf5 --- /dev/null +++ b/src/main/java/com/realtime/packets/AutoSoftwarePacket.java @@ -0,0 +1,23 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class AutoSoftwarePacket extends BasePackets { + private String url; + private String body; + private String method; + private String commandLine; + + @Override + public Byte getCommand() { + return Command.SOFT_CALL_MSG; + } +} diff --git a/src/main/java/com/realtime/packets/CallPacket.java b/src/main/java/com/realtime/packets/CallPacket.java new file mode 100644 index 0000000..c7dcfe0 --- /dev/null +++ b/src/main/java/com/realtime/packets/CallPacket.java @@ -0,0 +1,18 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class CallPacket extends BasePackets { + private String sdp; + private String type; // "call", "leave", "offer", "answer", "candidate", "hangup" + @Override + public Byte getCommand() { + return Command.CALL_LING; + } +} diff --git a/src/main/java/com/realtime/packets/ConnectPacket.java b/src/main/java/com/realtime/packets/ConnectPacket.java new file mode 100644 index 0000000..ceff12f --- /dev/null +++ b/src/main/java/com/realtime/packets/ConnectPacket.java @@ -0,0 +1,16 @@ +package com.realtime.packets; + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ConnectPacket extends BasePackets { + + @Override + public Byte getCommand() { + return Command.REGISTER; + } +} diff --git a/src/main/java/com/realtime/packets/FilePackets.java b/src/main/java/com/realtime/packets/FilePackets.java new file mode 100644 index 0000000..9cbf7bf --- /dev/null +++ b/src/main/java/com/realtime/packets/FilePackets.java @@ -0,0 +1,18 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class FilePackets extends BasePackets { + private String fileName; + private String filePath; + + @Override + public Byte getCommand() { + return -1; + } +} diff --git a/src/main/java/com/realtime/packets/GroupPacket.java b/src/main/java/com/realtime/packets/GroupPacket.java new file mode 100644 index 0000000..3e45a15 --- /dev/null +++ b/src/main/java/com/realtime/packets/GroupPacket.java @@ -0,0 +1,22 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class GroupPacket extends BasePackets { + private List userIds; + private Integer type = 2; + private String groupName; + + @Override + public Byte getCommand() { + return Command.CREATE_GROUP; + } +} diff --git a/src/main/java/com/realtime/packets/GroupSendPacket.java b/src/main/java/com/realtime/packets/GroupSendPacket.java new file mode 100644 index 0000000..b22692d --- /dev/null +++ b/src/main/java/com/realtime/packets/GroupSendPacket.java @@ -0,0 +1,21 @@ +package com.realtime.packets; + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.vo.UploadVo; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class GroupSendPacket extends BasePackets { + private Long groupId; + private Integer type = 2; + private List uploadVos; + @Override + public Byte getCommand() { + return Command.GROUP_MESSAGE; + } +} diff --git a/src/main/java/com/realtime/packets/InventGroupPacket.java b/src/main/java/com/realtime/packets/InventGroupPacket.java new file mode 100644 index 0000000..fa2a021 --- /dev/null +++ b/src/main/java/com/realtime/packets/InventGroupPacket.java @@ -0,0 +1,21 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class InventGroupPacket extends BasePackets { + private List userIds; + private Long groupId; + + @Override + public Byte getCommand() { + return Command.INVENT_GROUP; + } +} diff --git a/src/main/java/com/realtime/packets/PingPongPacket.java b/src/main/java/com/realtime/packets/PingPongPacket.java new file mode 100644 index 0000000..f166714 --- /dev/null +++ b/src/main/java/com/realtime/packets/PingPongPacket.java @@ -0,0 +1,15 @@ +package com.realtime.packets; + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PingPongPacket extends BasePackets { + @Override + public Byte getCommand() { + return Command.PING_PONG; + } +} diff --git a/src/main/java/com/realtime/packets/RealTimePacket.java b/src/main/java/com/realtime/packets/RealTimePacket.java new file mode 100644 index 0000000..a8f3bf9 --- /dev/null +++ b/src/main/java/com/realtime/packets/RealTimePacket.java @@ -0,0 +1,20 @@ +package com.realtime.packets; + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import io.netty.handler.codec.http.HttpObject; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +@EqualsAndHashCode(callSuper = true) +@Data +public class RealTimePacket extends BasePackets { + private String httpObject; + + private String end; + @Override + public Byte getCommand() { + return Command.REAL_TIME_VOICE; + } +} diff --git a/src/main/java/com/realtime/packets/RemoveGroupPacket.java b/src/main/java/com/realtime/packets/RemoveGroupPacket.java new file mode 100644 index 0000000..7dde391 --- /dev/null +++ b/src/main/java/com/realtime/packets/RemoveGroupPacket.java @@ -0,0 +1,21 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RemoveGroupPacket extends BasePackets { + private List userIds; + private Long groupId; + + @Override + public Byte getCommand() { + return Command.REMOVE_GROUP; + } +} diff --git a/src/main/java/com/realtime/packets/SendMsgPackets.java b/src/main/java/com/realtime/packets/SendMsgPackets.java new file mode 100644 index 0000000..7e9a6f3 --- /dev/null +++ b/src/main/java/com/realtime/packets/SendMsgPackets.java @@ -0,0 +1,31 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.vo.UploadVo; +import io.minio.messages.Upload; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class SendMsgPackets extends BasePackets { + private FilePackets filePackets; + private Long sessionId; + private Integer contentType; + private String friendNickName; //朋友给我的昵称 + private String friendName;// 我给朋友的昵称 + private String toAvatar; + private Integer unRead = 1;//规定一条 + private List uploadVos; + private Integer type = 1; + + + @Override + public Byte getCommand() { + return Command.SINGLE_MESSAGE; + } +} diff --git a/src/main/java/com/realtime/packets/SystemNoticePackets.java b/src/main/java/com/realtime/packets/SystemNoticePackets.java new file mode 100644 index 0000000..88813ba --- /dev/null +++ b/src/main/java/com/realtime/packets/SystemNoticePackets.java @@ -0,0 +1,17 @@ +package com.realtime.packets; + + +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class SystemNoticePackets extends BasePackets { + + @Override + public Byte getCommand() { + return Command.SYS_NOTICE; + } +} diff --git a/src/main/java/com/realtime/packets/basePackets/BasePackets.java b/src/main/java/com/realtime/packets/basePackets/BasePackets.java new file mode 100644 index 0000000..552842b --- /dev/null +++ b/src/main/java/com/realtime/packets/basePackets/BasePackets.java @@ -0,0 +1,24 @@ +package com.realtime.packets.basePackets; + +import io.netty.handler.codec.http.HttpObject; +import lombok.Data; + +import java.io.Serializable; + +@Data +public abstract class BasePackets implements Serializable { + private Byte version = 1; + private String sender; + private String receiver; + private Long groupId = System.currentTimeMillis(); + private String nickName; + private String avatar; + private String messageType; + private String message; + private HttpObject audioByte; + private Long createTime = System.currentTimeMillis(); + private Boolean isNoticeBar = Boolean.FALSE; // 是否需要显示到手机通知栏 + private Boolean callBackMessage = Boolean.FALSE; //是否需要回执消息 + + public abstract Byte getCommand(); +} diff --git a/src/main/java/com/realtime/packets/command/Command.java b/src/main/java/com/realtime/packets/command/Command.java new file mode 100644 index 0000000..ac29f6d --- /dev/null +++ b/src/main/java/com/realtime/packets/command/Command.java @@ -0,0 +1,25 @@ +package com.realtime.packets.command; + +public interface Command { + Byte SELF_RESPONSE = 0; //自己发送的消息确认 + Byte SINGLE_MESSAGE = 1; //私聊消息 + Byte MESSAGE_RESPONSE = 2; //私聊响应 + Byte CREATE_GROUP = 3; //创建群 + Byte CREATE_GROUP_RESPONSE = 4; //创建群响应 + Byte LOGIN_REQUEST = 5; //登录请求 + Byte LOGIN_RESPONSE = 6; // 登录响应 + Byte REGISTER = 7; //注册请求 + Byte INVENT_GROUP = 8; //邀请好友加入群聊 + Byte GROUP_MESSAGE = 9; //发送群消息 + Byte REMOVE_GROUP = 10; //移除群成员 + Byte HEARTBEAT_REQUEST = 11; //心跳消息请求 + Byte HEARTBEAT_RESPONSE = 12; //心跳消息恢复 + Byte RED_PACK_CREATED = 13; //红包发起 + Byte JOIN_GROUP = 14; //加入群 + Byte CALL_LING = 15;// 语音通话发起 + Byte ANSWER = 16; + Byte SYS_NOTICE = 20; //系统消息 + Byte PING_PONG = 21; + Byte REAL_TIME_VOICE = 22; + Byte SOFT_CALL_MSG = 23; +} diff --git a/src/main/java/com/realtime/packets/resp/GroupResponsePacket.java b/src/main/java/com/realtime/packets/resp/GroupResponsePacket.java new file mode 100644 index 0000000..54abad4 --- /dev/null +++ b/src/main/java/com/realtime/packets/resp/GroupResponsePacket.java @@ -0,0 +1,18 @@ +package com.realtime.packets.resp; + + +import com.realtime.packets.basePackets.BasePackets; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GroupResponsePacket { + private Long groupId; + private Integer groupSize; + private boolean success = Boolean.TRUE; +} diff --git a/src/main/java/com/realtime/packets/server/NettyServer.java b/src/main/java/com/realtime/packets/server/NettyServer.java new file mode 100644 index 0000000..8eece41 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/NettyServer.java @@ -0,0 +1,47 @@ +package com.realtime.packets.server; + + +import com.realtime.packets.server.handler.SocketChannelHandler; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.concurrent.atomic.AtomicReference; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor +public class NettyServer { + private final EventLoopGroup bossGroup = new NioEventLoopGroup(8); + private final EventLoopGroup workGroup = new NioEventLoopGroup(); + private final SocketChannelHandler myWebSocketChannelHandler; + private final AtomicReference port = new AtomicReference<>(88); + + public void run() { + try { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workGroup).option(ChannelOption.SO_BACKLOG, 1024) + .channel(NioServerSocketChannel.class) + .option(ChannelOption.SO_BACKLOG, 1024) + .childOption(ChannelOption.SO_KEEPALIVE, true) + .childOption(ChannelOption.TCP_NODELAY, true) + .childHandler(myWebSocketChannelHandler); + Channel ch = bootstrap.bind(port.get()).sync().channel(); + ch.closeFuture().sync(); + } catch (Exception e) { + log.error("异常{}", e.getMessage()); + } finally { + bossGroup.shutdownGracefully(); + workGroup.shutdownGracefully(); + } + } + +} diff --git a/src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java new file mode 100644 index 0000000..9972541 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java @@ -0,0 +1,59 @@ +package com.realtime.packets.server.handler; + + +import com.realtime.packets.ConnectPacket; +import com.realtime.service.GroupMemberService; +import com.realtime.utils.SessionUtils; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ConnectMessageHandler extends SimpleChannelInboundHandler { + + private final GroupMemberService groupMemberService; + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, ConnectPacket connectPacket) throws Exception { + SessionUtils.bindChannel(connectPacket, channelHandlerContext.channel()); + connectGroup(channelHandlerContext, connectPacket); + if (SessionUtils.hasLogin(channelHandlerContext.channel())) { + System.out.println(channelHandlerContext.channel()); + log.info("{}用户已登录", connectPacket.getSender()); + } + } + + // 重连到群组 + void connectGroup(ChannelHandlerContext ctx, ConnectPacket connectPacket) { + List byGroupContactId = groupMemberService.getByGroupContactId(connectPacket.getSender()); + if (!byGroupContactId.isEmpty()) { + byGroupContactId.forEach(item -> { + ChannelGroup channelGroup = SessionUtils.getChannelGroup(item); + if (channelGroup == null) { + ChannelGroup channels = new DefaultChannelGroup(ctx.executor()); + SessionUtils.bindChannelGroup(item, channels); + Channel channel = SessionUtils.getChannel(connectPacket.getSender()); + channels.add(channel); + } else { + Channel channel = SessionUtils.getChannel(connectPacket.getSender()); + boolean contains = channelGroup.contains(channel); + if (!contains) { + channelGroup.add(channel); + } + } + }); + } + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java b/src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java new file mode 100644 index 0000000..59f629d --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java @@ -0,0 +1,34 @@ +package com.realtime.packets.server.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +@Slf4j +@Sharable +public class ExceptionHandler extends ChannelDuplexHandler { + + private final Map map = new ConcurrentHashMap<>(); + + public static final ExceptionHandler INSTANCE_EXCEPTION = new ExceptionHandler(); + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + if (cause instanceof RuntimeException) { + ByteBuf byteBuf = ctx.alloc().buffer(); + map.put("errorCode",-10000); + map.put("errorMessage",cause.getMessage()); + byteBuf.writeBytes(map.toString().getBytes(StandardCharsets.UTF_8)); + ctx.channel().writeAndFlush(new TextWebSocketFrame(byteBuf)); + } + } +} + diff --git a/src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java new file mode 100644 index 0000000..8c51390 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java @@ -0,0 +1,48 @@ +package com.realtime.packets.server.handler; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.model.pojo.GroupMessage; +import com.realtime.packets.GroupSendPacket; +import com.realtime.service.GroupMessageService; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) + +public class GroupMessageHandler extends SimpleChannelInboundHandler { + + private final GroupMessageService groupMessageService; + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, GroupSendPacket groupSendPacket) throws Exception { + ChannelGroup group = SessionUtils.getChannelGroup(groupSendPacket.getGroupId()); + ByteBuf buff = getBuff(channelHandlerContext, groupSendPacket); + assert group != null; + group.writeAndFlush(new TextWebSocketFrame(buff)); + } + + ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, GroupSendPacket groupSendPacket) { + ByteBuf byteBuf = channelHandlerContext.alloc().buffer(); + byte[] bytes = JSONObject.toJSONString(groupSendPacket).getBytes(StandardCharsets.UTF_8); + byteBuf.writeBytes(bytes); + groupMessageService.save(new GroupMessage(groupSendPacket)); + return byteBuf; + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java b/src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java new file mode 100644 index 0000000..1165735 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java @@ -0,0 +1,60 @@ +package com.realtime.packets.server.handler; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.InventGroupPacket; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class InventGroupHandler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, InventGroupPacket inventGroupPacket) { + Long groupId = inventGroupPacket.getGroupId(); + if (SessionUtils.getChannelGroup(groupId) == null) { + ChannelGroup channels = new DefaultChannelGroup(channelHandlerContext.executor()); + SessionUtils.bindChannelGroup(groupId, channels); + inventGroupPacket.getUserIds().forEach(item -> { + Channel userChannel = SessionUtils.getChannel(item); + if (userChannel != null) { + channels.add(userChannel); + } + }); + ByteBuf buff = getBuff(channelHandlerContext, inventGroupPacket); + channels.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8))); + } else { + ChannelGroup channelGroup = SessionUtils.getChannelGroup(groupId); + inventGroupPacket.getUserIds().forEach(item -> { + Channel userChannel = SessionUtils.getChannel(item); + if (userChannel != null) { + channelGroup.add(userChannel); + } + }); + ByteBuf buff = getBuff(channelHandlerContext, inventGroupPacket); + channelGroup.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8))); + } + } + + ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, InventGroupPacket inventGroupPacket) { + ByteBuf byteBuf = channelHandlerContext.alloc().buffer(); + byte[] bytes = JSONObject.toJSONString(inventGroupPacket).getBytes(StandardCharsets.UTF_8); + byteBuf.writeBytes(bytes); + return byteBuf; + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java b/src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java new file mode 100644 index 0000000..e039652 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java @@ -0,0 +1,58 @@ +package com.realtime.packets.server.handler; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.GroupPacket; +import com.realtime.service.GroupListService; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class JoinGroupHandler extends SimpleChannelInboundHandler { + + private final GroupListService groupListService; + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, GroupPacket groupPacket) throws Exception { + ChannelGroup channels = new DefaultChannelGroup(channelHandlerContext.executor()); + Long groupId = groupPacket.getGroupId(); + SessionUtils.bindChannelGroup(groupPacket.getGroupId(), channels); + groupPacket.getUserIds().add(groupPacket.getSender());//把自己添加到群聊 + groupPacket.getUserIds().forEach(item -> { + Channel userChannel = SessionUtils.getChannel(item); + if (userChannel != null) { + channels.add(userChannel); + } + }); + System.out.println(channels.size()+"人"); + ByteBuf buff = getBuff(channelHandlerContext, channels, groupId, groupPacket); + channels.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8))); + } + + ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, ChannelGroup channels, Long groupId, GroupPacket groupPacket) { + ByteBuf byteBuf = channelHandlerContext.alloc().buffer(); + groupPacket.setGroupId(groupId); + byte[] bytes = JSONObject.toJSONString(groupPacket).getBytes(StandardCharsets.UTF_8); + byteBuf.writeBytes(bytes); + groupListService.saveGroupList(groupPacket, groupId); + return byteBuf; + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java b/src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java new file mode 100644 index 0000000..b6d5f23 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java @@ -0,0 +1,78 @@ +package com.realtime.packets.server.handler; + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.config.NettyConfig; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.strategy.PacketService; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Service +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class MessageSocketHandler extends SimpleChannelInboundHandler { + + private final PacketService packetService; + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame binaryWebSocketFrame) throws Exception { + dealWithMessage(channelHandlerContext, binaryWebSocketFrame); + } + + private void dealWithMessage(ChannelHandlerContext context, WebSocketFrame webSocketFrame) { + if (webSocketFrame instanceof CloseWebSocketFrame) { + context.channel().close(); + } + + if (webSocketFrame instanceof PingWebSocketFrame) { + context.channel().write(new PongWebSocketFrame(webSocketFrame.content().retain())); + } + + ByteBuf byteBuf = webSocketFrame.content(); + String content = byteBuf.toString(StandardCharsets.UTF_8); + JSONObject dataObject = JSONObject.parseObject(content); + JSONObject body = dataObject.getJSONObject("body"); + BasePackets basePackets = packetService.getCurrent(body); + if (basePackets.getCallBackMessage()) { + TextWebSocketFrame tws = new TextWebSocketFrame(String.valueOf(JSONObject.toJSONString(basePackets))); + context.channel().writeAndFlush(tws); + } + + context.fireChannelRead(basePackets); + } + + + @Override + public void channelActive(ChannelHandlerContext ctx) { + NettyConfig.group.add(ctx.channel()); + } + + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + NettyConfig.group.remove(ctx.channel()); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); +// ctx.close(); + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java b/src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java new file mode 100644 index 0000000..cb5a4fd --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java @@ -0,0 +1,41 @@ +package com.realtime.packets.server.handler; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.PingPongPacket; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicInteger; + +@Slf4j +@Component +@ChannelHandler.Sharable +public class PingPongHartHandler extends SimpleChannelInboundHandler { + + private final AtomicInteger times = new AtomicInteger(10); + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, PingPongPacket pingPongPacket) throws Exception { + Channel channel = SessionUtils.getChannel(pingPongPacket.getSender()); + ByteBuf buff = getBuff(channelHandlerContext, pingPongPacket); + assert channel != null; + channel.writeAndFlush(new TextWebSocketFrame(buff)); + } + + ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, PingPongPacket pingPongPacket) { + ByteBuf byteBuf = channelHandlerContext.alloc().buffer(); + pingPongPacket.setMessage("pong"); + byte[] bytes = JSONObject.toJSONString(pingPongPacket).getBytes(StandardCharsets.UTF_8); + byteBuf.writeBytes(bytes); + return byteBuf; + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java new file mode 100644 index 0000000..e6d247a --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java @@ -0,0 +1,51 @@ +package com.realtime.packets.server.handler; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.mappers.MessageMapper; +import com.realtime.model.pojo.Message; +import com.realtime.packets.SendMsgPackets; +import com.realtime.service.MessageService; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class PrivateMessageHandler extends SimpleChannelInboundHandler { + + private final MessageMapper messageMapper; + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, SendMsgPackets sendMsgPackets) throws Exception { + + messageMapper.insert(new Message(sendMsgPackets)); + Channel chanel = SessionUtils.getChannel(sendMsgPackets.getReceiver()); + ByteBuf buff = getBuff(channelHandlerContext, sendMsgPackets); + Objects.requireNonNull(chanel).writeAndFlush(new TextWebSocketFrame(buff)); + System.out.println("发送私聊消息"); + + } + + ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, SendMsgPackets sendMsgPackets) { + ByteBuf byteBuf = channelHandlerContext.alloc().buffer(); + byte[] bytes = JSONObject.toJSONString(sendMsgPackets).getBytes(StandardCharsets.UTF_8); + byteBuf.writeBytes(bytes); + return byteBuf; + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java b/src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java new file mode 100644 index 0000000..fed0328 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java @@ -0,0 +1,44 @@ +package com.realtime.packets.server.handler; + + + +import com.realtime.config.RtasrConfig; + +import com.realtime.packets.RealTimePacket; + +import com.realtime.sysconst.RTASRClient; +import com.realtime.utils.Base64ToMultipartFile; + +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class RealTimeTransferHandler extends SimpleChannelInboundHandler { + +// private final RealTimeVoiceService realTimeVoiceService; +// + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, RealTimePacket realTimePacket) throws Exception { + + + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java b/src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java new file mode 100644 index 0000000..ef001dd --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java @@ -0,0 +1,46 @@ +package com.realtime.packets.server.handler; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.RemoveGroupPacket; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class RemoveGroupHandler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, RemoveGroupPacket removeGroupPacket) { + Long groupId = removeGroupPacket.getGroupId(); + ChannelGroup channelGroup = SessionUtils.getChannelGroup(groupId); + removeGroupPacket.getUserIds().forEach(userId -> { + Channel channel = SessionUtils.getChannel(userId); + assert channelGroup != null; + channelGroup.remove(channel); + }); + ByteBuf buff = getBuff(channelHandlerContext, removeGroupPacket); + assert channelGroup != null; + channelGroup.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8))); + } + + ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, RemoveGroupPacket removeGroupPacket) { + ByteBuf byteBuf = channelHandlerContext.alloc().buffer(); + byte[] bytes = JSONObject.toJSONString(removeGroupPacket).getBytes(StandardCharsets.UTF_8); + byteBuf.writeBytes(bytes); + return byteBuf; + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java b/src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java new file mode 100644 index 0000000..1d7dfcd --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java @@ -0,0 +1,69 @@ +package com.realtime.packets.server.handler; + + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.*; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.util.CharsetUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static com.realtime.packets.server.handler.ExceptionHandler.INSTANCE_EXCEPTION; + +@Slf4j +@Service +@ChannelHandler.Sharable +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class SocketChannelHandler extends ChannelInitializer { + + private final MessageSocketHandler myWebSocketHandler; + + private final GroupMessageHandler groupMessageHandler; + + private final ConnectMessageHandler connectMessageHandler; + + private final JoinGroupHandler joinGroupHandler; + + private final PrivateMessageHandler privateMessageHandler; + + private final PingPongHartHandler pingPongHartHandler; + + private final InventGroupHandler inventGroupHandler; + + private final RealTimeTransferHandler realTimeTransferHandler; + + @Override + protected void initChannel(SocketChannel socketChannel) throws Exception { + int maxFrameSize = 10 * 1024 * 1024; + socketChannel.pipeline() + .addLast("http-codec", new HttpServerCodec()) + .addLast("http-chunked", new ChunkedWriteHandler()) + .addLast(new WebSocketServerProtocolHandler("/ws", null,true, maxFrameSize)) + .addLast() + .addLast(new StringDecoder(CharsetUtil.UTF_8)) + .addLast(new StringEncoder(CharsetUtil.UTF_8)) + .addLast("myWebSocketHandler", myWebSocketHandler) + .addLast("groupMessageHandler", groupMessageHandler) + .addLast("connectHandler", connectMessageHandler) + .addLast("joinGroupHandler", joinGroupHandler) + .addLast("privateMessageHandler", privateMessageHandler) + .addLast("inventGroupHandler", inventGroupHandler) + .addLast("pingPongHartHandler", pingPongHartHandler) + .addLast("realTimeTransferHandler", realTimeTransferHandler) +// .addLast(new IdleStateHandler(10,0,0)) + .addLast("selfException", INSTANCE_EXCEPTION); + + + + } +} diff --git a/src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java new file mode 100644 index 0000000..ddad730 --- /dev/null +++ b/src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java @@ -0,0 +1,18 @@ +package com.realtime.packets.server.handler; + + +import com.realtime.packets.SystemNoticePackets; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@ChannelHandler.Sharable +public class SystemNoticeMessageHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, SystemNoticePackets msg) throws Exception { + + } +} diff --git a/src/main/java/com/realtime/packets/strategy/PackStrategy.java b/src/main/java/com/realtime/packets/strategy/PackStrategy.java new file mode 100644 index 0000000..54d83d9 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/PackStrategy.java @@ -0,0 +1,12 @@ +package com.realtime.packets.strategy; + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.basePackets.BasePackets; + +public interface PackStrategy { + boolean getCurrent(Byte commandLine); + + BasePackets getCurrentPacket(JSONObject jsonObject); +} diff --git a/src/main/java/com/realtime/packets/strategy/PacketService.java b/src/main/java/com/realtime/packets/strategy/PacketService.java new file mode 100644 index 0000000..273c1e5 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/PacketService.java @@ -0,0 +1,12 @@ +package com.realtime.packets.strategy; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.basePackets.BasePackets; + +public interface PacketService { + + BasePackets getCurrent(JSONObject jsonObject); +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java new file mode 100644 index 0000000..13c4240 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java @@ -0,0 +1,24 @@ +package com.realtime.packets.strategy.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.AutoSoftwarePacket; +import com.realtime.packets.ConnectPacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class AutoSoftwareStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.SOFT_CALL_MSG.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), AutoSoftwarePacket.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java new file mode 100644 index 0000000..19de994 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java @@ -0,0 +1,26 @@ +package com.realtime.packets.strategy.impl; + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.ConnectPacket; +import com.realtime.packets.SendMsgPackets; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class ConnectPackStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.REGISTER.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), ConnectPacket.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java new file mode 100644 index 0000000..899f834 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java @@ -0,0 +1,24 @@ +package com.realtime.packets.strategy.impl; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.GroupPacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class GroupJoinPackStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.CREATE_GROUP.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), GroupPacket.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java new file mode 100644 index 0000000..510d571 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java @@ -0,0 +1,26 @@ +package com.realtime.packets.strategy.impl; + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.GroupSendPacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class GroupSendPackStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.GROUP_MESSAGE.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + + return JSONObject.parseObject(jsonObject.toString(), GroupSendPacket.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java new file mode 100644 index 0000000..92a08ce --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java @@ -0,0 +1,27 @@ +package com.realtime.packets.strategy.impl; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.InventGroupPacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class InventStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.INVENT_GROUP.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), InventGroupPacket.class); + + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java b/src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java new file mode 100644 index 0000000..ed1b82a --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java @@ -0,0 +1,35 @@ +package com.realtime.packets.strategy.impl; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.exception.BusinessException; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.strategy.PackStrategy; +import com.realtime.packets.strategy.PacketService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class PacketServiceImpl implements PacketService { + + private final List packStrategies; + @Override + public BasePackets getCurrent(JSONObject jsonObject) { + Byte command = jsonObject.getByte("command"); + return getCurrent(command).getCurrentPacket(jsonObject); + } + + private PackStrategy getCurrent(Byte commandLine) { + long size = packStrategies.stream().filter(item -> item.getCurrent(commandLine)).count(); + if (size <= 0) { + throw new BusinessException("没有可用的频道!!"); + } + return packStrategies.stream().filter(item -> item.getCurrent(commandLine)).toList().get(0); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java new file mode 100644 index 0000000..d9508f7 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java @@ -0,0 +1,24 @@ +package com.realtime.packets.strategy.impl; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.PingPongPacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class PingPongPackStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.PING_PONG.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), PingPongPacket.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java new file mode 100644 index 0000000..f9dfcf8 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java @@ -0,0 +1,26 @@ +package com.realtime.packets.strategy.impl; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.SendMsgPackets; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class PrivatePackStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.SINGLE_MESSAGE.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), SendMsgPackets.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java new file mode 100644 index 0000000..39bcaa6 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java @@ -0,0 +1,24 @@ +package com.realtime.packets.strategy.impl; + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.RealTimePacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class RealTimePackStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.REAL_TIME_VOICE.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), RealTimePacket.class); + } +} diff --git a/src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java new file mode 100644 index 0000000..e0bb182 --- /dev/null +++ b/src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java @@ -0,0 +1,27 @@ +package com.realtime.packets.strategy.impl; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.packets.RemoveGroupPacket; +import com.realtime.packets.basePackets.BasePackets; +import com.realtime.packets.command.Command; +import com.realtime.packets.strategy.PackStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class RemoveStrategyImpl implements PackStrategy { + @Override + public boolean getCurrent(Byte commandLine) { + return Command.REMOVE_GROUP.equals(commandLine); + } + + @Override + public BasePackets getCurrentPacket(JSONObject jsonObject) { + return JSONObject.parseObject(jsonObject.toString(), RemoveGroupPacket.class); + + } +} diff --git a/src/main/java/com/realtime/service/BaiduAuthService.java b/src/main/java/com/realtime/service/BaiduAuthService.java new file mode 100644 index 0000000..8e4b9bc --- /dev/null +++ b/src/main/java/com/realtime/service/BaiduAuthService.java @@ -0,0 +1,46 @@ +package com.realtime.service; + + + + +import com.alibaba.fastjson2.JSONObject; +import com.realtime.config.BaiduTtsConfig; +import lombok.RequiredArgsConstructor; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class BaiduAuthService { + + + private final BaiduTtsConfig ttsConfig; + + /** + * 获取百度语音合成访问令牌 + */ + public String getAccessToken() { + String authHost = "https://aip.baidubce.com/oauth/2.0/token?"; + String getAccessTokenUrl = authHost + + "grant_type=client_credentials" + + "&client_id=" + ttsConfig.getApiKey() + + "&client_secret=" + ttsConfig.getSecretKey(); + + try { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpGet get = new HttpGet(getAccessTokenUrl); + HttpResponse response = httpClient.execute(get); + String result = EntityUtils.toString(response.getEntity()); + + JSONObject jsonObject = JSONObject.parseObject(result); + return jsonObject.getString("access_token"); + } catch (Exception e) { + throw new RuntimeException("获取百度语音合成Token失败", e); + } + } +} diff --git a/src/main/java/com/realtime/service/BaiduTtsService.java b/src/main/java/com/realtime/service/BaiduTtsService.java new file mode 100644 index 0000000..92dfd64 --- /dev/null +++ b/src/main/java/com/realtime/service/BaiduTtsService.java @@ -0,0 +1,94 @@ +package com.realtime.service; + + +import com.google.common.io.Files; +import com.realtime.model.query.TtsOptionsReq; +import lombok.RequiredArgsConstructor; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +@Service +@RequiredArgsConstructor(onConstructor_ = {@Autowired}) +public class BaiduTtsService { + + private static final String TTS_URL = "http://tsn.baidu.com/text2audio"; + + private final BaiduAuthService authService; + + /** + * 文本转语音 + * @param text 要转换的文本 + * @param options 合成参数 + * @return 音频字节数组 + */ + public byte[] textToSpeech(String text, TtsOptionsReq options) { + try { + String accessToken = authService.getAccessToken(); + + Map params = new HashMap<>(); + params.put("tex", URLEncoder.encode(text, StandardCharsets.UTF_8)); + params.put("tok", accessToken); + params.put("cuid", UUID.randomUUID().toString().replaceAll("-", "")); + params.put("ctp", "1"); + params.put("lan", options.getLang()); + params.put("spd", String.valueOf(options.getSpeed())); + params.put("pit", String.valueOf(options.getPitch())); + params.put("vol", String.valueOf(options.getVolume())); + params.put("per", String.valueOf(options.getPer())); + params.put("aue", options.getAue()); + + return postForm(params); + } catch (Exception e) { + throw new RuntimeException("语音合成失败", e); + } + } + + /** + * 发送POST请求 + */ + private byte[] postForm(Map params) throws Exception { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost post = new HttpPost(BaiduTtsService.TTS_URL); + + // 设置表单参数 + List paramList = new ArrayList<>(); + for (Map.Entry param : params.entrySet()) { + paramList.add(new BasicNameValuePair(param.getKey(), param.getValue())); + } + post.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8")); + + // 执行请求 + HttpResponse response = httpClient.execute(post); + HttpEntity entity = response.getEntity(); + + if (entity != null) { + return EntityUtils.toByteArray(entity); + } + return null; + } + + /** + * 文本转语音并保存为文件 + */ + public void textToSpeechFile(String text, TtsOptionsReq options, String filePath) throws IOException { + byte[] audioData = textToSpeech(text, options); + if (audioData != null) { + Files.write(audioData,new File(filePath)); + } + } +} diff --git a/src/main/java/com/realtime/service/ChatListService.java b/src/main/java/com/realtime/service/ChatListService.java new file mode 100644 index 0000000..cd47b8a --- /dev/null +++ b/src/main/java/com/realtime/service/ChatListService.java @@ -0,0 +1,28 @@ +package com.realtime.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.realtime.model.pojo.ChatList; +import com.realtime.model.query.ChatListPageQueryReq; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatListInfoVo; + +import java.util.List; + +public interface ChatListService extends IService { + + + void saveChatList(ChatList chatList); + + String getMachineIdBySenderId(String senderId); + + Result> getChatList(ChatListPageQueryReq chatListPageQueryReq); + + Result saveSignChatList(List chatList); + + Result updateChatListFName(List chatList); + + + Result deleteSignChatList(ChatList ids); +} diff --git a/src/main/java/com/realtime/service/DoubaoVoiceService.java b/src/main/java/com/realtime/service/DoubaoVoiceService.java new file mode 100644 index 0000000..749fc32 --- /dev/null +++ b/src/main/java/com/realtime/service/DoubaoVoiceService.java @@ -0,0 +1,105 @@ +package com.realtime.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.realtime.config.DoubaoVoiceConfig; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import okio.ByteString; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Service; +import org.springframework.web.socket.BinaryMessage; +import org.springframework.web.socket.WebSocketSession; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +@Slf4j +@Service +public class DoubaoVoiceService { + private final DoubaoVoiceConfig config; + private final OkHttpClient okHttpClient; + private WebSocket doubaoWebSocket; // 与豆包 API 的 WebSocket 连接 + + public DoubaoVoiceService(DoubaoVoiceConfig config) { + this.config = config; + this.okHttpClient = new OkHttpClient.Builder() + .readTimeout(0, TimeUnit.MILLISECONDS) // 实时流禁用超时 + .build(); + } + + /** + * 建立与豆包实时语音接口的 WebSocket 连接 + * @param clientSession 客户端的 WebSocket 会话(用于将结果返回给客户端) + */ + public void connect(WebSocketSession clientSession) { + + Request request = new Request.Builder() + .addHeader("X-Api-App-ID",config.getAppId()) + .addHeader("X-Api-Access-Key",config.getAccessToken()) + .addHeader("X-Api-Resource-Id","volc.speech.dialog").addHeader("X-Api-App-Key",config.getApiKey()) + .url("wss://openspeech.bytedance.com/api/v3/realtime/dialogue") + .build(); + + // 连接豆包 API 并处理回调 + doubaoWebSocket = okHttpClient.newWebSocket(request, new WebSocketListener() { + @Override + public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { + // 连接成功:可发送初始化参数(如语音类型、采样率) + sendInitParams(webSocket); + } + + @Override + public void onMessage(@NotNull WebSocket webSocket, ByteString bytes) { + // 接收豆包返回的实时结果(如识别文本、合成语音) + try { + // 将结果转发给客户端 + clientSession.sendMessage(new BinaryMessage(bytes.toByteArray())); + } catch (IOException e) { + log.error("转发结果到客户端失败", e); + } + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + System.out.println(t.getMessage()); + log.error("豆包 WebSocket 连接失败", t); + } + }); + } + + /** + * 向豆包 API 发送音频数据(实时流) + */ + public void sendAudio(byte[] audioData) { + if (doubaoWebSocket != null) { + doubaoWebSocket.send(ByteString.of(audioData)); + } + } + + /** + * 发送初始化参数(根据豆包 API 要求) + */ + private void sendInitParams(WebSocket webSocket) { + Map params = new HashMap<>(); + params.put("action", "init"); + params.put("format", "pcm"); // 音频格式 + params.put("sample_rate", 16000); // 采样率 + params.put("mode", "realtime"); // 实时模式 + try { + webSocket.send(new ObjectMapper().writeValueAsString(params)); + } catch (JsonProcessingException e) { + log.error("发送初始化参数失败", e); + } + } + + /** + * 关闭连接 + */ + public void close() { + if (doubaoWebSocket != null) { + doubaoWebSocket.close(1000, "正常关闭"); + } + } +} diff --git a/src/main/java/com/realtime/service/FileService.java b/src/main/java/com/realtime/service/FileService.java new file mode 100644 index 0000000..bf4f603 --- /dev/null +++ b/src/main/java/com/realtime/service/FileService.java @@ -0,0 +1,18 @@ +package com.realtime.service; + + + +import com.realtime.sysconst.Result; +import com.realtime.vo.UploadVo; +import io.minio.errors.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public interface FileService { + + Result uploadFile(MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException; + +} diff --git a/src/main/java/com/realtime/service/FriendRelationshipService.java b/src/main/java/com/realtime/service/FriendRelationshipService.java new file mode 100644 index 0000000..4f7d253 --- /dev/null +++ b/src/main/java/com/realtime/service/FriendRelationshipService.java @@ -0,0 +1,22 @@ +package com.realtime.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.realtime.model.pojo.FriendRelationship; +import com.realtime.model.query.ChatFriendRelationshipQueryReq; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatFriendRelationshipInfoVo; + +import java.util.List; + +public interface FriendRelationshipService extends IService { + + Result> selectByPhone(ChatFriendRelationshipQueryReq req); + + Result saveShip(FriendRelationship friendRelationship); + + void updateStateById(Long friendRelationshipId); + + Result removeIds(List ids); +} diff --git a/src/main/java/com/realtime/service/GroupListService.java b/src/main/java/com/realtime/service/GroupListService.java new file mode 100644 index 0000000..45083fe --- /dev/null +++ b/src/main/java/com/realtime/service/GroupListService.java @@ -0,0 +1,33 @@ +package com.realtime.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.google.zxing.WriterException; +import com.realtime.model.pojo.GroupList; +import com.realtime.model.query.GroupDetailQueryReq; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.update.GroupInventUpdateReq; +import com.realtime.packets.GroupPacket; +import com.realtime.sysconst.Result; +import com.realtime.vo.GroupDetailVo; +import com.realtime.vo.GroupListVo; + +import java.io.IOException; +import java.util.List; + +public interface GroupListService extends IService { + + void saveGroupList(GroupPacket groupPacket, Long groupId); + + Result> getGroup(GroupListQueryReq groupDetailQueryReq); + + Result getGroupDetail(GroupDetailQueryReq queryReq) throws WriterException, IOException, WriterException; + + + Result updateInvent(GroupInventUpdateReq groupInventUpdateReq); + + Result disband(DisbandGroupReq disbandGroupReq); + +} diff --git a/src/main/java/com/realtime/service/GroupMemberService.java b/src/main/java/com/realtime/service/GroupMemberService.java new file mode 100644 index 0000000..0c684b4 --- /dev/null +++ b/src/main/java/com/realtime/service/GroupMemberService.java @@ -0,0 +1,32 @@ +package com.realtime.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.realtime.model.pojo.GroupMember; +import com.realtime.model.query.GroupMemberListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.remove.RemoveGroupReq; +import com.realtime.model.remove.RemovesGroupReq; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatListInfoVo; +import com.realtime.vo.GroupMemberListVo; + +import java.util.List; + +public interface GroupMemberService extends IService { + + Result> getMemberList(GroupMemberListQueryReq queryReq); + + Result> getAllByGroupIdAndMemberId(GroupMemberListQueryReq queryReq); + + Result saveInvent(List groupMembers, String launchContactId); + + Result quit(RemoveGroupReq removeGroupReq); + + void removeByGroupId(DisbandGroupReq disbandGroupReq); + + Result removeMembersByIds(RemovesGroupReq removesGroupReq); + + List getByGroupContactId(String groupContactId); +} diff --git a/src/main/java/com/realtime/service/GroupMessageService.java b/src/main/java/com/realtime/service/GroupMessageService.java new file mode 100644 index 0000000..7d994c6 --- /dev/null +++ b/src/main/java/com/realtime/service/GroupMessageService.java @@ -0,0 +1,23 @@ +package com.realtime.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.realtime.model.pojo.GroupMessage; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.sysconst.Result; +import com.realtime.vo.GroupListMessagesVo; + +import java.util.List; + +public interface GroupMessageService extends IService { + + Result> getGroupList(GroupListQueryReq req); + + default Result removeMembersByIds(List ids) { + removeByIds(ids); + return Result.success("ok"); + } + + +} diff --git a/src/main/java/com/realtime/service/MessageService.java b/src/main/java/com/realtime/service/MessageService.java new file mode 100644 index 0000000..6d7f37c --- /dev/null +++ b/src/main/java/com/realtime/service/MessageService.java @@ -0,0 +1,30 @@ +package com.realtime.service; + + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.model.query.ChatQueryPageReq; +import com.realtime.model.query.MessageQueryReq; +import com.realtime.sysconst.Result; +import com.realtime.vo.FriendMessageVo; +import com.realtime.vo.MessageInfoVo; +import com.realtime.vo.MessageVo; +import io.netty.channel.ChannelHandlerContext; + +public interface MessageService { + + + /** + * 获取聊天记录 + * @param messageQueryReq 请求参数 + * @return 结果 + */ + Result> getList(MessageQueryReq messageQueryReq); + + /**** + * 获取所有和我聊过天的好友 + * @param messageQueryReq + * @return + */ + Result> getFriendChatList(MessageQueryReq messageQueryReq); +} diff --git a/src/main/java/com/realtime/service/RealTimeVoiceService.java b/src/main/java/com/realtime/service/RealTimeVoiceService.java new file mode 100644 index 0000000..9dabe58 --- /dev/null +++ b/src/main/java/com/realtime/service/RealTimeVoiceService.java @@ -0,0 +1,18 @@ +package com.realtime.service; + + +import com.realtime.packets.RealTimePacket; +import org.json.JSONObject; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; + +public interface RealTimeVoiceService { + void connect() throws RuntimeException, URISyntaxException; + + + void sendAudio(RealTimePacket relativePacket) throws RuntimeException, URISyntaxException; +} diff --git a/src/main/java/com/realtime/service/impl/ChatListServiceImpl.java b/src/main/java/com/realtime/service/impl/ChatListServiceImpl.java new file mode 100644 index 0000000..2dff14b --- /dev/null +++ b/src/main/java/com/realtime/service/impl/ChatListServiceImpl.java @@ -0,0 +1,147 @@ +package com.realtime.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.realtime.mappers.ChatListMapper; +import com.realtime.model.pojo.ChatList; +import com.realtime.model.pojo.FriendRelationship; +import com.realtime.model.query.ChatListPageQueryReq; +import com.realtime.service.ChatListService; +import com.realtime.service.FriendRelationshipService; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatListInfoVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ChatListServiceImpl extends ServiceImpl + implements ChatListService { + + private final FriendRelationshipService friendRelationshipService; + + /** + * @param chatList + * @return + */ + @Override + public void saveChatList(ChatList chatList) { + long sessionId = System.currentTimeMillis(); + chatList.setSessionId(sessionId); + chatList.setIsDelete(0); + ChatList newChatList = new ChatList(); + newChatList.setSessionId(sessionId); + newChatList.setReceiver(chatList.getSender()); + newChatList.setSender(chatList.getReceiver()); + newChatList.setIsDelete(0); + newChatList.setFriendNickName("我的助手"); + baseMapper.insert(chatList); + baseMapper.insert(newChatList); + } + + /** + * @param senderId 用户号码 + * @return 返回机器人的虚拟电话号码 + */ + @Override + public String getMachineIdBySenderId(String senderId) { + return baseMapper.getMachineIdBySenderId(senderId); + } + + /** + * 查询自己的的好友 + * + * @param chatListPageQueryReq 请求参数 + * @return 结果 + */ + @Override + public Result> getChatList(ChatListPageQueryReq chatListPageQueryReq) { + return Result.success(baseMapper.getChatList(chatListPageQueryReq, chatListPageQueryReq)); + } + + /** + * 保存好友 + * + * @param chatList 请求参数 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Result saveSignChatList(List chatList) { + Long friendRelationshipId = chatList.get(0).getFriendRelationshipId(); + chatList.get(1).setFriendNickName(friendRelationshipService.getById(friendRelationshipId).getFriendNickName()); + this.saveBatch(chatList); + friendRelationshipService.updateStateById(friendRelationshipId); + return Result.success("添加成功"); + } + + //@Override + //public Result updateChatListFName(List chatList) { + // return null; + //} + +// @Override +// public Result deleteSignChatList(ChatList chatList) { +// List i = baseMapper.selectList(new LambdaQueryWrapper().eq(ChatList::getSessionId, chatList.getSessionId())); +// if(i.size() < 2){ +// return Result.fail("删除失败: 非好友"); +// } +// if(i.get(0).getIsDelete() == 0){ +// return Result.fail("不可删除"); +// } +// baseMapper.delete(new LambdaQueryWrapper().eq(ChatList::getSessionId, chatList.getSessionId())); +// friendRelationshipService.remove(new LambdaQueryWrapper().eq(FriendRelationship::getSessionId, chatList.getSessionId())); +// return Result.success("删除成功"); +// } + /** + * @param chatList + * @return + */ + @Override + public Result updateChatListFName(List chatList) { + // 遍历传入的chatList + for (ChatList chat : chatList) { + // 根据receiver和sessionId查询聊天列表 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("receiver", chat.getReceiver()) + .eq("session_id", chat.getSessionId()); + + ChatList existingChat = this.getOne(queryWrapper); + System.out.println(existingChat); + if (existingChat != null) { + // 判断是否是"我的助手",如果是,不进行修改 + if ("我的助手".equals(existingChat.getFriendNickName())) { + // 如果是"我的助手",跳过此记录 + continue; + } else { + // 如果不是"我的助手",修改friendNickName + existingChat.setFriendNickName(chat.getFriendNickName()); + System.out.println(existingChat.getFriendNickName()); + this.updateById(existingChat); // 更新数据库中的数据 + } + } + } + return Result.success("更新完成"); + } + + @Override + public Result deleteSignChatList(ChatList ids) { + baseMapper.deleteFriend(ids.getSender(), ids.getReceiver()); + baseMapper.deleteFriend(ids.getReceiver(),ids.getSender()); + return Result.success("ok"); + } + + +} + + + diff --git a/src/main/java/com/realtime/service/impl/ChatServiceImpl.java b/src/main/java/com/realtime/service/impl/ChatServiceImpl.java new file mode 100644 index 0000000..cd07786 --- /dev/null +++ b/src/main/java/com/realtime/service/impl/ChatServiceImpl.java @@ -0,0 +1,589 @@ +///* +// * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. +// * +// * Licensed under the GNU Affero General Public License, Version 3 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * https://www.gnu.org/licenses/agpl-3.0.html +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package com.realtime.service.impl; +// +// +//import com.chat.config.OssProperties; +//import com.chat.constants.FileConstant; +//import com.chat.constants.RoleEnum; +//import com.chat.endpoint.DoBaoAiService; +//import com.chat.model.pojo.AigcMessage; +//import com.chat.model.pojo.AigcOss; +//import com.chat.model.query.ChatReq; +//import com.chat.model.query.ChatRes; +//import com.chat.model.query.ImageR; +//import com.chat.service.AigcMessageService; +//import com.chat.service.ChatService; +//import com.chat.service.LangChatService; +//import com.chat.service.UserService; +//import com.chat.utils.HttpUtil; +//import com.chat.utils.OssFileUtil; +//import com.chat.utils.ServletUtil; +//import com.chat.utils.StreamEmitter; +//import dev.langchain4j.data.image.Image; +//import dev.langchain4j.model.output.Response; +//import dev.langchain4j.model.output.TokenUsage; +//import lombok.AllArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.BeanUtils; +//import org.springframework.stereotype.Service; +// +//import java.io.BufferedReader; +//import java.io.IOException; +//import java.io.InputStreamReader; +//import java.nio.file.Path; +//import java.nio.file.Paths; +//import java.util.List; +//import java.util.Objects; +//import java.util.concurrent.ExecutorService; +//import java.util.concurrent.Executors; +// +///** +// * @author tycoding +// * @since 2024/1/4 +// */ +//@Slf4j +//@Service +//@AllArgsConstructor +//public class ChatServiceImpl implements ChatService { +// +// private final LangChatService langChatService; +// private final AigcMessageService aigcMessageService; +// private final DoBaoAiService doBaoAiService; +// private final UserService userService; +// private final OssProperties ossProperties; +// private final OssFileUtil ossFileUtil; +// +// private final String addText = "add_text"; +// private final String addFile = "add_file"; +// +// private final String fileHandleUrl = "http://127.0.0.1:5001/convert/word-to-markdown"; +// +// @Override +// public void chat(ChatReq req, ExecutorService executorService) { +// if(req.getUrl() != null){ +// gradioChat(req, executorService, addFile, req.getUrl(), req.getMessage()); +// }else { +// gradioChat(req, executorService, addText, req.getMessage()); +// } +// } +// +// @Override +// public void chat(ChatReq req) { +// StreamEmitter emitter = req.getEmitter(); +// long startTime = System.currentTimeMillis(); +// StringBuilder text = new StringBuilder(); +// +// +// // save user message +// req.setRole(RoleEnum.USER.getName()); +// saveMessage(req, 0, 0); +// +// //if(req.getType() == 0){ +// // chatFileWord(req); +// // return; +// //} +// if(req.getType() == 2 || req.getType() == 0){ +// emitter.complete(); +// return; +// } +// +// try { +// if (req.getUrl() != null && !req.getUrl().isEmpty()){ +// doBaoAiService.chatFile(req); +// } +// else if(Objects.equals(req.getModelName(), "AI对话")){ +// doBaoAiService.chat(req); +// } +// else { +// langChatService +// .chat(req) +// .onNext(e -> { +// StringBuilder append = text.append(e); +// emitter.send(new ChatRes(e)); +// }) +// .onComplete((e) -> { +// TokenUsage tokenUsage = e.tokenUsage(); +// ChatRes res = new ChatRes(tokenUsage.totalTokenCount(), startTime); +// emitter.send(res); +// emitter.complete(); +// +// // save assistant message +// req.setMessage(text.toString()); +// req.setRole(RoleEnum.ASSISTANT.getName()); +// req.setType(1); +// saveMessage(req, tokenUsage.inputTokenCount(), tokenUsage.outputTokenCount()); +// }) +// .onError((e) -> { +// emitter.error(e.getMessage()); +// throw new RuntimeException(e.getMessage()); +// }) +// .start(); +// } +// } catch (Exception e) { +// e.printStackTrace(); +// emitter.error(e.getMessage()); +// throw new RuntimeException(e.getMessage()); +// } +// } +// +// private void chatFileWord(ChatReq req) { +// StreamEmitter emitter = req.getEmitter(); +// long startTime = System.currentTimeMillis(); +// +// JSONObject jsonObject = HttpUtil.builder() +// .url("http://127.0.0.1:5001/convert/word-to-markdown") +// .addParam("ossUrl", req.getMessage()) +// .addParam("userId", req.getUserId()) +// .post(true) +// .sync(); +// if(req.getEmitter() != null){ +// if(jsonObject.getString("status").equals("success")){ +// emitter.send(new ChatRes(jsonObject.getJSONObject("result").getString("content"))); +// req.setMessage(jsonObject.getJSONObject("result").getString("content")); +// req.setRole(RoleEnum.ASSISTANT.getName()); +// req.setType(1); +// saveMessage(req, 0, 0); +// }else { +// emitter.send(new ChatRes(jsonObject.getString("message"))); +// req.setMessage(jsonObject.getString("message")); +// req.setRole(RoleEnum.ASSISTANT.getName()); +// req.setType(1); +// saveMessage(req, 0, 0); +// } +// +// } +// ChatRes res = new ChatRes(0, startTime); +// emitter.send(res); +// emitter.complete(); +// } +// +// private void saveMessage(ChatReq req, Integer inputToken, Integer outputToken) { +// if (req.getConversationId() != null) { +// AigcMessage message = new AigcMessage(); +// BeanUtils.copyProperties(req, message); +// message.setIp(ServletUtil.getIpAddr()); +// message.setPromptTokens(inputToken); +// message.setTokens(outputToken); +// aigcMessageService.addMessage(message); +// } +// } +// +// @Override +// public String text(ChatReq req) { +// String text; +// try { +// text = langChatService.text(req); +// } catch (Exception e) { +// e.printStackTrace(); +// throw new RuntimeException(e.getMessage()); +// } +// return text; +// } +// +// @Override +// public AigcOss image(ImageR req) { +// Response res = langChatService.image(req); +// +// String path = res.content().url().toString(); +// AigcOss oss = new AigcOss(); +// oss.setUrl(path); +// return oss; +// } +// +// @Override +// public void saveTaskMessage(ChatReq req) { +// +// req.setRole(RoleEnum.USER.getName()); +// saveMessage(req, 0, 0); +// StreamEmitter emitter = req.getEmitter(); +//// emitter.send(new ChatRes("点击文件进行操作")); +// emitter.send(new ChatRes(0,0)); +// emitter.complete(); +// } +// +// @Override +// public JSONObject isPdfToDxf(ChatReq req) { +// JSONObject jsonObject = null; +// try { +// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本 +// String pythonPath = getProjectRoot() + +// (System.getProperty("os.name").toLowerCase().contains("win") +// ? "\\venv\\Scripts\\python.exe" +// : "/venv/bin/python"); +// ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() +"/scripts/prompt.py"); +// System.out.println(List.of(req.getMessage())); +// pb.command().add(req.getMessage()); +// // 启动进程 +// Process process = pb.start(); +// +// // 获取进程的标准输出流 +// BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); +// // 获取进程的错误输出流 +// BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); +// +// String line; +// // 读取并打印 Python 脚本的标准输出 +// while ((line = stdInput.readLine()) != null) { +// jsonObject = JSONObject.parseObject(line); +// } +// +// // 读取并打印 Python 脚本的错误输出 +// while ((line = stdError.readLine()) != null) { +// System.err.println(line); +// } +// +// // 等待进程执行完毕 +// int exitCode = process.waitFor(); +// System.out.println("Exit Code: " + exitCode); +// +// } catch (InterruptedException | IOException e) { +// e.printStackTrace(); +// } +// if (jsonObject == null) { +// jsonObject = JSONObject.parseObject("{\"status\": false}"); +// } +// return jsonObject; +// } +// +// @Override +// public void pdfToDxf(ChatReq req, ExecutorService executor, JSONObject jsonObject) { +// StreamEmitter emitter = req.getEmitter(); +// long startTime = System.currentTimeMillis(); +// +// String userId = String.valueOf(userService.getIdByPhone(Long.parseLong(req.getUserId()))); +// String filePath = FileConstant.UserFilePath + userId + "/" + jsonObject.get("pdf_file"); +// String outFilePath = ossProperties.getEndpoint() + "/" + ossProperties.getBucketName() + "/" + FileConstant.USERTEMPName + userId + "/"; +// String outFileName = jsonObject.getString("dxf_file"); +// // 调用模型 +// String out = "AI异常"; +// JSONObject jsonObject1 = pdfToDxfPy(req.getMessage(), filePath, jsonObject.getString("pdf_file"), outFilePath, outFileName); +// // 生成文件 +// if(jsonObject1.getBoolean("success")){ +// ossFileUtil.upFile("D://xiazai//"+outFileName, FileConstant.USERTEMPName + userId + "/"); +// out = "操作成功"; +// } +// // 发送结果 +// emitter.send(new ChatRes(out)); +// // 关闭SSE +// emitter.send(new ChatRes(0, startTime)); +// emitter.complete(); +// +// } +// +// @Override +// public void pdfToDxf2(ChatReq req, ExecutorService executor, JSONObject jsonObject) { +// StreamEmitter emitter = req.getEmitter(); +// long startTime = System.currentTimeMillis(); +// try { +// String userId = String.valueOf(userService.getIdByPhone(Long.parseLong(req.getUserId()))); +// String filePath = FileConstant.UserFilePath + userId + "/" + jsonObject.get("pdf_file"); +// String outFilePath = ossProperties.getEndpoint() + "/" + ossProperties.getBucketName() + "/" + FileConstant.USERTEMPName + userId + "/"; +// String outFileName = jsonObject.getString("dxf_file"); +// // 调用模型 +// String out = "AI异常"; +// JSONObject jsonObject1 = pdfToDxfPy(req.getMessage(), filePath, jsonObject.getString("pdf_file"), outFilePath, outFileName); +// // 上传文件 +// if(jsonObject1.getBoolean("success")){ +// ossFileUtil.upFile("D:/xiazai/"+outFileName, FileConstant.USERTEMPPath + userId + "/" + outFileName); +// out = "操作成功"; +// } +// // 发送结果 +// emitter.send(new ChatRes(out)); +// // 关闭SSE +// emitter.send(new ChatRes(0, startTime)); +// }catch (Exception e){ +// emitter.error("AI处理异常"); +// log.error(e.getMessage()); +// }finally { +// emitter.complete(); +// } +// } +// +// private JSONObject pdfToDxfPy(String message, String filePath,String xiazaiFileneme, String outFilePath, String outFileName) { +// // 下载文件 +// ossFileUtil.download(filePath, "D:\\xiazai\\" + xiazaiFileneme); +// JSONObject jsonObject = null; +// try { +// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本 +// String pythonPath = getProjectRoot() + +// (System.getProperty("os.name").toLowerCase().contains("win") +// ? "\\venv\\Scripts\\python.exe" +// : "/venv/bin/python"); +// ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() +"/scripts/forceTest_agent(2).py"); +// System.out.println(List.of(message)); +// pb.command().add(message); +// // 启动进程 +// Process process = pb.start(); +// +// // 获取进程的标准输出流 +// BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); +// // 获取进程的错误输出流 +// BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); +// +// String line; +// // 读取并打印 Python 脚本的标准输出 +// StringBuilder aimessage = new StringBuilder(); +// boolean foundStart = false; +// while ((line = stdInput.readLine()) != null) { +// if (!foundStart) { +// if (line.trim().startsWith("{")) { +// foundStart = true; +// aimessage.append(line); +// } +// } else { +// aimessage.append(line); +// if (line.trim().endsWith("}")) { +// break; +// } +// } +// } +// log.info(String.valueOf(aimessage)); +// jsonObject = JSONObject.parseObject(String.valueOf(aimessage)); +// // 读取并打印 Python 脚本的错误输出 +// while ((line = stdError.readLine()) != null) { +// System.err.println(line); +// } +// +// // 等待进程执行完毕 +// int exitCode = process.waitFor(); +// System.out.println("Exit Code: " + exitCode); +// +// } catch (InterruptedException | IOException e) { +// e.printStackTrace(); +// } +// if (jsonObject == null || jsonObject.getBoolean("success") == null) { +// jsonObject = JSONObject.parseObject("{\"success\": false}"); +// } +// return jsonObject; +// } +// +// private void gradioChat(ChatReq req, ExecutorService executorService, String pythonFile, String... inputMessage){ +// ExecutorService executor = req.getExecutor() != null ? executorService : Executors.newSingleThreadExecutor(); +// +// try { +// StreamEmitter emitter = req.getEmitter(); +// long startTime = System.currentTimeMillis(); +// +// +// // save user message +// req.setRole(RoleEnum.USER.getName()); +// saveMessage(req, 0, 0); +// +// if(req.getType() == 2){ +// emitter.complete(); +// return; +// } +// +// String pythonPath = getProjectRoot() + +// (System.getProperty("os.name").toLowerCase().contains("win") +// ? "\\venv\\Scripts\\python.exe" +// : "/venv/bin/python"); +// ProcessBuilder pb1 = new ProcessBuilder(pythonPath, getProjectRoot() + "/scripts/c20250423/"+ pythonFile +".py"); +// //System.out.println(List.of(inputMessage)); +// pb1.command().addAll(List.of(inputMessage)); +// // 启动进程 +// Process process1 = pb1.start(); +// String line1; +// StringBuilder aimessage1 = new StringBuilder(); +// // 处理标准输出流 +// try (BufferedReader stdInput = new BufferedReader( +// new InputStreamReader(process1.getInputStream()))) { +// while ((line1 = stdInput.readLine()) != null) { +// aimessage1.append(line1); +// } +// } +// JSONObject jsonObject = doBaoAiService.pdData(String.valueOf(aimessage1)); +// log.info("AI任务对话:{}", jsonObject); +// if(jsonObject.getString("code").equals("3") && jsonObject.getString("txt").equals("false")){ +// // 调用Python脚本获取AI响应 +// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本 +// // 动态构建Python路径 +// ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() + "/scripts/"+ pythonFile +".py"); +// //System.out.println(List.of(inputMessage)); +// pb.command().addAll(List.of(inputMessage)); +// // 启动进程 +// Process process = pb.start(); +// String line; +// StringBuilder aimessage = new StringBuilder(); +// // 处理标准输出流 +// try (BufferedReader stdInput = new BufferedReader( +// new InputStreamReader(process.getInputStream()))) { +// boolean skipFirst = true; +// String previousLine = ""; +// +// while ((line = stdInput.readLine()) != null) { +// // 不要开头 +// if (skipFirst && line.startsWith("Loaded as API: ")) { +// skipFirst = false; +// continue; +// } +// +// int startIndex = previousLine.length(); +// if (startIndex < line.length()) { +// String processedLine = line.replace("\\~n", "\n").replace("\\~r", "\r");; +// String newPart = processedLine.substring(startIndex); +// aimessage.append(newPart); +// // 发送流式响应 +// if (emitter != null) { +// emitter.send(new ChatRes(newPart)); +// } +// previousLine = processedLine; +// } +// +// } +// if (emitter != null) { +// emitter.send(new ChatRes(0,startTime)); +// } +// } +// +// // 处理错误流 +// try (BufferedReader stdError = new BufferedReader( +// new InputStreamReader(process.getErrorStream()))) { +// +// String errorLine; +// while ((errorLine = stdError.readLine()) != null) { +// log.error("Python script error: {}", errorLine); +// } +// } +// +// // 等待进程结束 +// int exitCode = process.waitFor(); +// if (exitCode != 0) { +// throw new RuntimeException("Python script exited with code: " + exitCode); +// } +// +// req.setMessage(String.valueOf(aimessage)); +// req.setRole(RoleEnum.ASSISTANT.getName()); +// req.setType(1); +// saveMessage(req, 0, 0); +// +// } else { +// if (emitter != null) { +// emitter.send(new ChatRes(jsonObject.getString("txt"))); +// emitter.send(new ChatRes(0,startTime)); +// } +// +// req.setMessage(String.valueOf(jsonObject.getString("txt"))); +// req.setRole(RoleEnum.ASSISTANT.getName()); +// req.setType(1); +// saveMessage(req, 0, 0); +// } +// +// +// // 处理错误流 +// try (BufferedReader stdError = new BufferedReader( +// new InputStreamReader(process1.getErrorStream()))) { +// String errorLine; +// while ((errorLine = stdError.readLine()) != null) { +// log.error("Python script error: {}", errorLine); +// } +// } +// +// // 等待进程结束 +// int exitCode1 = process1.waitFor(); +// if (exitCode1 != 0) { +// throw new RuntimeException("Python script exited with code: " + exitCode1); +// } +// +// +// // 调用Python脚本获取AI响应 +// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本 +// // 动态构建Python路径 +// //ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() + "/scripts/c202523/"+ pythonFile +".py"); +// ////System.out.println(List.of(inputMessage)); +// //pb.command().addAll(List.of(inputMessage)); +// //// 启动进程 +// //Process process = pb.start(); +// //String line; +// //StringBuilder aimessage = new StringBuilder(); +// //// 处理标准输出流 +// //try (BufferedReader stdInput = new BufferedReader( +// // new InputStreamReader(process.getInputStream()))) { +// // boolean skipFirst = true; +// // String previousLine = ""; +// // +// // while ((line = stdInput.readLine()) != null) { +// // // 不要开头 +// // if (skipFirst && line.startsWith("Loaded as API: ")) { +// // skipFirst = false; +// // continue; +// // } +// // +// // int startIndex = previousLine.length(); +// // if (startIndex < line.length()) { +// // String processedLine = line.replace("\\~n", "\n").replace("\\~r", "\r");; +// // String newPart = processedLine.substring(startIndex); +// // aimessage.append(newPart); +// // // 发送流式响应 +// // if (emitter != null) { +// // emitter.send(new ChatRes(newPart)); +// // } +// // previousLine = processedLine; +// // } +// // +// // } +// // if (emitter != null) { +// // emitter.send(new ChatRes(0,startTime)); +// // } +// //} +// // +// //// 处理错误流 +// //try (BufferedReader stdError = new BufferedReader( +// // new InputStreamReader(process.getErrorStream()))) { +// // +// // String errorLine; +// // while ((errorLine = stdError.readLine()) != null) { +// // log.error("Python script error: {}", errorLine); +// // } +// //} +// // +// //// 等待进程结束 +// //int exitCode = process.waitFor(); +// //if (exitCode != 0) { +// // throw new RuntimeException("Python script exited with code: " + exitCode); +// //} +// +// // 保存AI响应到数据库 +// //req.setMessage(String.valueOf(aimessage)); +// //req.setRole(RoleEnum.ASSISTANT.getName()); +// //req.setType(1); +// //saveMessage(req, 0, 0); +// +// +// // 7. 完成流式响应 +// if (req.getEmitter() != null) { +// req.getEmitter().complete(); +// } +// } catch (Exception e) { +// log.error("Chat processing failed", e); +// if (req.getEmitter() != null) { +// req.getEmitter().error(e.getMessage()); +// } +// } finally { +// if (req.getExecutor() != null) { +// executor.shutdown(); +// } +// } +// } +// +// // 获取项目根目录路径 +// private static String getProjectRoot() { +// Path currentPath = Paths.get("").toAbsolutePath(); +// return currentPath.toString(); +// } +//} diff --git a/src/main/java/com/realtime/service/impl/FileServiceImpl.java b/src/main/java/com/realtime/service/impl/FileServiceImpl.java new file mode 100644 index 0000000..46bfb80 --- /dev/null +++ b/src/main/java/com/realtime/service/impl/FileServiceImpl.java @@ -0,0 +1,89 @@ +package com.realtime.service.impl; + + +import cn.hutool.core.codec.Base64; +import com.realtime.config.FileProperties; +import com.realtime.config.MinioComponent; +import com.realtime.config.MinioConfig; +import com.realtime.exception.BusinessException; +import com.realtime.service.FileService; +import com.realtime.sysconst.Result; +import com.realtime.sysconst.enumConst.ResultEnum; +import com.realtime.vo.UploadVo; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import io.minio.errors.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class FileServiceImpl implements FileService { + + private final MinioConfig minioConfig; + + private final MinioClient minioClient; + + private final FileProperties fileProperties; + + @Override + public Result uploadFile(MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException { + if (file.isEmpty()) throw new BusinessException(ResultEnum.FILE_NOT_NULL); + List allowedFormats = Arrays.asList(fileProperties.getAllowedFormats().split(",")); + String fileName = Objects.requireNonNull(file.getOriginalFilename()).toLowerCase(); + String fileSuffix = fileName.substring(fileName.lastIndexOf('.') + 1); + if (!allowedFormats.contains(fileSuffix)) { + throw new BusinessException(ResultEnum.FILE_FORMAT_ERROR); + } + + UploadVo vo = generateFileName(file,fileSuffix); + InputStream inputStream = file.getInputStream(); + minioClient.putObject(PutObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(vo.getNewFileName()) + .stream(inputStream, file.getSize(), -1) + .contentType(file.getContentType()) + .build() + ); + return Result.success(vo); + } + + + private UploadVo generateFileName(MultipartFile file,String fileSuffix) { + String originalFilename = file.getOriginalFilename(); + assert originalFilename != null; + UploadVo uploadVo = new UploadVo(); + String storeFileName = UUID.randomUUID() + "_" + originalFilename; + String url = generateFileUrl(storeFileName); + uploadVo.setName(originalFilename); + uploadVo.setUrl(url); + uploadVo.setExtendName(fileSuffix); + uploadVo.setNewFileName(storeFileName); + uploadVo.setFileSize(BigDecimal.valueOf(file.getSize()).divide(BigDecimal.valueOf(1048576)).setScale(3, RoundingMode.HALF_UP)); // MB + uploadVo.setFileNameCode(Base64.encode(originalFilename)); + return uploadVo; + + } + + private String generateFileUrl(String fileName) { + return + minioConfig.getEndpoint()+"/real/" + fileName; + } + + +} diff --git a/src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java b/src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java new file mode 100644 index 0000000..38c7875 --- /dev/null +++ b/src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java @@ -0,0 +1,79 @@ +package com.realtime.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.realtime.exception.BusinessException; +import com.realtime.mappers.FriendRelationshipMapper; +import com.realtime.model.pojo.FriendRelationship; +import com.realtime.model.query.ChatFriendRelationshipQueryReq; +import com.realtime.service.FriendRelationshipService; +import com.realtime.sysconst.Result; +import com.realtime.vo.ChatFriendRelationshipInfoVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class FriendRelationshipServiceImpl extends ServiceImpl implements FriendRelationshipService { + /** + * 获取好友申请 + * @param req 请求参数 + * @return 结果 + */ + @Override + public Result> selectByPhone(ChatFriendRelationshipQueryReq req) { + return Result.success(baseMapper.selectByPhone(req,req)); + } + + /** + * 申请添加好友 + * @param friendRelationship 请求参数 + * @return 结果 + */ + @Override + public Result saveShip(FriendRelationship friendRelationship) { +// if (StpUtil.getLoginIdAsLong() == friendRelationship.getRecipientPhone()){ +// throw new BusinessException(ResultEnum.NOT_ADD_SELF); +// } + Long count = baseMapper.selectCount( + new LambdaQueryWrapper() + .and(wrapper -> wrapper + .eq(FriendRelationship::getSendId, friendRelationship.getSendId()) + .eq(FriendRelationship::getRecipientId, friendRelationship.getRecipientId()) + .eq(FriendRelationship::getState,0) + ) + .or(wrapper -> wrapper + .eq(FriendRelationship::getSendId, friendRelationship.getRecipientId()) + .eq(FriendRelationship::getRecipientId, friendRelationship.getSendId()) + .eq(FriendRelationship::getState,0) + ) + ); + if (count > 0) { + return Result.fail("重复申请"); + } + + baseMapper.insert(friendRelationship); + return Result.success("success"); + } + + /** + * @param friendRelationshipId + */ + @Override + public void updateStateById(Long friendRelationshipId) { + baseMapper.updateStateById(friendRelationshipId); + } + + @Override + public Result removeIds(List ids) { + removeByIds(ids); + return Result.success("ok"); + } +} diff --git a/src/main/java/com/realtime/service/impl/GroupListServiceImpl.java b/src/main/java/com/realtime/service/impl/GroupListServiceImpl.java new file mode 100644 index 0000000..7f5d183 --- /dev/null +++ b/src/main/java/com/realtime/service/impl/GroupListServiceImpl.java @@ -0,0 +1,123 @@ +package com.realtime.service.impl; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.realtime.exception.BusinessException; +import com.realtime.mappers.GroupListMapper; +import com.realtime.model.pojo.GroupList; +import com.realtime.model.pojo.GroupMember; +import com.realtime.model.query.GroupDetailQueryReq; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.update.GroupInventUpdateReq; +import com.realtime.packets.GroupPacket; +import com.realtime.service.GroupListService; +import com.realtime.service.GroupMemberService; +import com.realtime.sysconst.Result; +import com.realtime.utils.SessionUtils; +import com.realtime.vo.GroupDetailVo; +import com.realtime.vo.GroupListVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor_ = {@Autowired}) +public class GroupListServiceImpl extends ServiceImpl + implements GroupListService { + + private final GroupMemberService groupMemberService; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveGroupList(GroupPacket groupPacket, Long groupId) { + GroupList groupList = new GroupList(); + groupList.setId(groupId); + groupList.setCreator(groupPacket.getSender()); + groupList.setOwner(1); + groupList.setName(groupPacket.getGroupName()); + save(groupList); + + saveMember(groupPacket,groupId); + } + + @Override + public Result> getGroup(GroupListQueryReq groupListQueryReq) { + return Result.success(baseMapper.getGroup(groupListQueryReq,groupListQueryReq)); + } + + @Override + public Result getGroupDetail(GroupDetailQueryReq queryReq) throws IOException, WriterException { + String content = "/pages/group/joinGroup?qrCode=" + queryReq.getGroupId(); // 扫描这个内容直接跳转到确认登录界面 + // 生成二维码图片 + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 240, 240); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // 转换为Base64 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "png", baos); + byte[] bytes = baos.toByteArray(); + String qrcode = "data:image/png;base64,"+ Base64.getEncoder().encodeToString(bytes); + GroupDetailVo groupDetail = baseMapper.getGroupDetail(queryReq); + groupDetail.setQrCode(qrcode); + return Result.success(groupDetail); + } + + @Override + public Result updateInvent(GroupInventUpdateReq groupInventUpdateReq) { + baseMapper.updateInvent(groupInventUpdateReq); + return Result.success(null); + } + + @Override + public Result disband(DisbandGroupReq disbandGroupReq) { +// long loginIdAsLong = StpUtil.getLoginIdAsLong(); +// disbandGroupReq.setPhone(loginIdAsLong); +// int owner = baseMapper.isOwner(disbandGroupReq); +// if (owner != 1){ +// throw new BusinessException(NOT_CREATOR); +// } +// Objects.requireNonNull(SessionUtils.getChannelGroup(disbandGroupReq.getGroupId())).close().addListener(item->{ +// baseMapper.deleteById(disbandGroupReq.getGroupId()); +// groupMemberService.removeByGroupId(disbandGroupReq); +// }); + + return Result.success("解散成功"); + } + + void saveMember(GroupPacket groupPacket,Long groupId) { + List saveList = new ArrayList<>(); + groupPacket.getUserIds().forEach(item->{ + GroupMember groupMember = new GroupMember(); + groupMember.setGroupId(groupId); + groupMember.setGroupContactId(item); + saveList.add(groupMember); + }); + groupMemberService.saveBatch(saveList); + } + + +} + + + + diff --git a/src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java b/src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java new file mode 100644 index 0000000..72e38cb --- /dev/null +++ b/src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java @@ -0,0 +1,76 @@ +package com.realtime.service.impl; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.realtime.mappers.GroupMemberMapper; +import com.realtime.model.pojo.GroupList; +import com.realtime.model.pojo.GroupMember; +import com.realtime.model.query.GroupMemberListQueryReq; +import com.realtime.model.remove.DisbandGroupReq; +import com.realtime.model.remove.RemoveGroupReq; +import com.realtime.model.remove.RemovesGroupReq; +import com.realtime.service.GroupListService; +import com.realtime.service.GroupMemberService; +import com.realtime.sysconst.Result; +import com.realtime.utils.SessionUtils; +import com.realtime.vo.ChatListInfoVo; +import com.realtime.vo.GroupMemberListVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class GroupMemberServiceImpl extends ServiceImpl + implements GroupMemberService { + + @Override + public Result> getMemberList(GroupMemberListQueryReq queryReq) { + return Result.success(baseMapper.getMemberList(queryReq, queryReq)); + } + + @Override + public Result> getAllByGroupIdAndMemberId(GroupMemberListQueryReq queryReq) { + return Result.success(baseMapper.getAllByGroupIdAndMemberId(queryReq, queryReq)); + } + + @Override + public Result saveInvent(List groupMembers, String launchContactId) { + saveBatch(groupMembers); + return Result.success("ok"); + } + + @Override + public Result quit(RemoveGroupReq removeGroupReq) { + baseMapper.quit(removeGroupReq); + SessionUtils.removeChanelByGroup(removeGroupReq.getGroupId(), removeGroupReq.getGroupContactId()); + return Result.success("ok"); + } + + @Override + public void removeByGroupId(DisbandGroupReq disbandGroupReq) { + baseMapper.removeByGroupId(disbandGroupReq); + } + + @Override + public Result removeMembersByIds(RemovesGroupReq ids) { + SessionUtils.removeBatchChannel(ids.getGroupId(), ids.getGroupContactId()); + baseMapper.removesByGroupPhoneAndGroupId(ids); + return Result.success("ok"); + } + + @Override + public List getByGroupContactId(String groupContactId) { + return baseMapper.getByGroupContactId(groupContactId); + } + +} + + + + diff --git a/src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java b/src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java new file mode 100644 index 0000000..0a736fe --- /dev/null +++ b/src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java @@ -0,0 +1,26 @@ +package com.realtime.service.impl; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.realtime.mappers.GroupMessageMapper; +import com.realtime.model.pojo.GroupMessage; +import com.realtime.model.query.GroupListQueryReq; +import com.realtime.service.GroupMessageService; +import com.realtime.sysconst.Result; +import com.realtime.vo.GroupListMessagesVo; +import org.springframework.stereotype.Service; + +@Service +public class GroupMessageServiceImpl extends ServiceImpl + implements GroupMessageService { + + @Override + public Result> getGroupList(GroupListQueryReq req) { + return Result.success(baseMapper.getGroupList(req,req)); + } +} + + + + diff --git a/src/main/java/com/realtime/service/impl/MessageServiceImpl.java b/src/main/java/com/realtime/service/impl/MessageServiceImpl.java new file mode 100644 index 0000000..514ca8d --- /dev/null +++ b/src/main/java/com/realtime/service/impl/MessageServiceImpl.java @@ -0,0 +1,43 @@ +package com.realtime.service.impl; + + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.realtime.exception.BusinessException; +import com.realtime.mappers.MessageMapper; +import com.realtime.model.query.ChatQueryPageReq; +import com.realtime.model.query.MessageQueryReq; +import com.realtime.service.MessageService; +import com.realtime.sysconst.Result; +import com.realtime.vo.FriendMessageVo; +import com.realtime.vo.MessageInfoVo; +import com.realtime.vo.MessageVo; +import io.netty.channel.ChannelHandlerContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class MessageServiceImpl implements MessageService { + + private final MessageMapper mapper; + + + + @Override + public Result> getList(MessageQueryReq messageQueryReq) { + return Result.success(mapper.getMsgList(messageQueryReq,messageQueryReq)); + } + + + @Override + public Result> getFriendChatList(MessageQueryReq messageQueryReq) { + return Result.success(mapper.getFriendMsgList(messageQueryReq,messageQueryReq)); + } + +} diff --git a/src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java b/src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java new file mode 100644 index 0000000..8916526 --- /dev/null +++ b/src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java @@ -0,0 +1,250 @@ +//package com.realtime.service.impl; +// +//import com.realtime.config.RtasrConfig; +//import com.realtime.packets.RealTimePacket; +//import com.realtime.service.RealTimeVoiceService; +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import org.java_websocket.client.WebSocketClient; +//import org.java_websocket.handshake.ServerHandshake; +//import org.json.JSONObject; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Service; +// +//import javax.crypto.Mac; +//import javax.crypto.spec.SecretKeySpec; +//import java.io.*; +//import java.net.URI; +//import java.net.URISyntaxException; +//import java.net.URLEncoder; +//import java.nio.charset.StandardCharsets; +//import java.nio.file.Files; +//import java.nio.file.Path; +//import java.text.SimpleDateFormat; +//import java.util.*; +// +//@Slf4j +//@Service +//@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +//public class RealTimeVoiceServiceImpl implements RealTimeVoiceService { +// +// private final RtasrConfig config; +// +// private String sessionId; +// +// private WebSocketClient webSocketClient; +// +// @Override +// public void connect() throws RuntimeException, URISyntaxException { +// Map authParams = generateAuthParams(); +// String paramsStr = buildParamsString(authParams); +// String fullWsUrl = config.getBaseWsUrl() + "?" + paramsStr; +// System.out.println("【连接信息】完整URL:" + fullWsUrl); +// webSocketClient = new WebSocketClient(new URI(fullWsUrl)) { +// @Override +// public void onOpen(ServerHandshake handshakedata) { +// System.out.println(handshakedata); +// // 等待服务端初始化 +// try { +// Thread.sleep(1200); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } +// } +// +// @Override +// public void onMessage(String message) { +// System.out.println(message); +// try { +// // 使用org.json解析JSON消息 +// JSONObject json = new JSONObject(message); +// System.out.println("【接收消息】" + json.toString()); +// +// // 处理会话ID +// if ("action".equals(json.optString("msg_type"))) { +// JSONObject data = json.optJSONObject("data"); +// if (data != null && data.has("sessionId")) { +// sessionId = data.getString("sessionId"); +// System.out.println("【会话信息】已获取sessionId:" + sessionId); +// } +// } +// } catch (Exception e) { +// int maxLength = Math.min(50, message.length()); +// System.out.println("【接收异常】非JSON文本消息:" + message.substring(0, maxLength) + "..."); +// } +// } +// +// @Override +// public void onClose(int code, String reason, boolean remote) { +// +// System.out.println("【连接关闭】代码:" + code + ",原因:" + reason); +// } +// +// @Override +// public void onError(Exception ex) { +// System.err.println("【WebSocket错误】" + ex.getMessage()); +// ex.printStackTrace(); +// } +// }; +// } +// +// @Override +// public void sendAudio(RealTimePacket relativePacket) throws RuntimeException, URISyntaxException { +// try (FileInputStream fis = convertBytesToFileInputStream(relativePacket.getAudioByte(),UUID.randomUUID().toString(),".pcm")) { +// +// +// +// // 发送音频帧 +// byte[] buffer = new byte[config.getAudioFameSize()]; +// int bytesRead; +// int frameIndex = 0; +// Long startTime = null; +// +// while ((bytesRead = fis.read(buffer)) != -1) { +// // 处理实际读取的字节数(最后一帧可能不足AUDIO_FRAME_SIZE) +// byte[] frameData = bytesRead == config.getAudioFameSize() ? buffer : Arrays.copyOf(buffer, bytesRead); +// +// // 记录起始时间 +// if (startTime == null) { +// startTime = System.currentTimeMillis(); +// System.out.println("【发送开始】起始时间:" + startTime + "ms(基准时间)"); +// } +// +// // 计算理论发送时间 +// long expectedSendTime = startTime + ((long) frameIndex * config.getFrameIntervalMs()); +// long currentTime = System.currentTimeMillis(); +// long timeDiff = expectedSendTime - currentTime; +// +// // 动态调整休眠时间 +// if (timeDiff > 1) { // 大于1ms才休眠 +// try { +// Thread.sleep(timeDiff); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// +// } +// } +// System.out.println(webSocketClient); +// +// System.out.println(frameData); +// // 发送音频帧(二进制消息) +// webSocketClient.send(frameData); +// +// // 打印节奏控制日志(每10帧) +// if (frameIndex % 10 == 0) { +// long actualSendTime = System.currentTimeMillis(); +// System.out.printf("【节奏控制】帧%d | 理论时间:%dms | 实际时间:%dms | 误差:%.1fms%n", frameIndex, expectedSendTime, actualSendTime, (actualSendTime - expectedSendTime) * 1.0); +// } +// +// frameIndex++; +// } +// +// System.out.println("【发送完成】所有音频帧发送完毕(共" + frameIndex + "帧)"); +// +// // 发送结束标记(使用org.json构建JSON) +// JSONObject endMsg = new JSONObject(); +// endMsg.put("end", true); +// if (sessionId != null && !sessionId.isEmpty()) { +// endMsg.put("sessionId", sessionId); +// } +// String endMsgStr = endMsg.toString(); +// webSocketClient.send(endMsgStr); +// System.out.println("【发送结束】已发送标准JSON结束标记:" + endMsgStr); +// +// +// } catch (FileNotFoundException e) { +//// System.err.println("【发送失败】音频文件不存在:" + audioPath); +// e.printStackTrace(); +// } catch (IOException e) { +// System.err.println("【发送异常】文件读取错误:" + e.getMessage()); +// e.printStackTrace(); +// } +// +// +// } +// +// private Map generateAuthParams() { +// Map params = new TreeMap<>(); // TreeMap保证字典序排序 +// +// // 固定参数 +// params.put("audio_encode", config.getAudioEncode()); +// params.put("lang", config.getLang()); +// params.put("samplerate", config.getLang()); +// +// // 动态参数 +// params.put("accessKeyId", config.getAccessKeyId()); +// params.put("appId", config.getAppId()); +// params.put("uuid", UUID.randomUUID().toString().replaceAll("-", "")); +// params.put("utc", getUtcTime()); +// +// // 计算签名 +// String signature = calculateSignature(params); +// params.put("signature", signature); +// +// return params; +// } +// +// private String getUtcTime() { +// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); +// sdf.setTimeZone(TimeZone.getTimeZone("GMT+8")); +// return sdf.format(new Date()); +// } +// +// private String calculateSignature(Map params) { +// try { +// // 构建基础字符串 +// StringBuilder baseStr = new StringBuilder(); +// boolean first = true; +// for (Map.Entry entry : params.entrySet()) { +// String key = entry.getKey(); +// String value = entry.getValue(); +// +// // 跳过signature参数 +// if ("signature".equals(key)) continue; +// // 过滤空值 +// if (value == null || value.trim().isEmpty()) continue; +// +// if (!first) { +// baseStr.append("&"); +// } +// baseStr.append(URLEncoder.encode(key, StandardCharsets.UTF_8)).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8)); +// first = false; +// } +// +// // HMAC-SHA1计算 +// Mac mac = Mac.getInstance("HmacSHA1"); +// SecretKeySpec keySpec = new SecretKeySpec(config.getAccessKeyId().getBytes(StandardCharsets.UTF_8), "HmacSHA1"); +// mac.init(keySpec); +// byte[] signBytes = mac.doFinal(baseStr.toString().getBytes(StandardCharsets.UTF_8)); +// +// // Base64编码 +// return Base64.getEncoder().encodeToString(signBytes); +// } catch (Exception e) { +// throw new RuntimeException("计算签名失败", e); +// } +// } +// +// private String buildParamsString(Map params) { +// StringBuilder sb = new StringBuilder(); +// boolean first = true; +// for (Map.Entry entry : params.entrySet()) { +// if (!first) { +// sb.append("&"); +// } +// sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)).append("=").append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)); +// first = false; +// } +// return sb.toString(); +// } +// +// public static FileInputStream convertBytesToFileInputStream(byte[] data, +// String prefix, +// String suffix) throws IOException { +// Path tempFile = Files.createTempFile(prefix, suffix); +// Files.write(tempFile, data); +// +// return new FileInputStream(tempFile.toFile()); +// } +// +// +//} diff --git a/src/main/java/com/realtime/sysconst/RTASRClient.java b/src/main/java/com/realtime/sysconst/RTASRClient.java new file mode 100644 index 0000000..9a5dc10 --- /dev/null +++ b/src/main/java/com/realtime/sysconst/RTASRClient.java @@ -0,0 +1,377 @@ +package com.realtime.sysconst; + +import com.realtime.packets.RealTimePacket; +import com.realtime.utils.SessionUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import jakarta.websocket.Session; +import lombok.Data; +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.handshake.ServerHandshake; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +@Data +public class RTASRClient { + // 配置参数 + private static final String AUDIO_ENCODE = "pcm_s16le"; + private static final String LANG = "autodialect"; + private static final String SAMPLERATE = "16000"; + private static final int AUDIO_FRAME_SIZE = 1280; // 每帧字节数 + private static final int FRAME_INTERVAL_MS = 40; // 帧间隔(毫秒) + private static final Logger log = LoggerFactory.getLogger(RTASRClient.class); + + + // 客户端参数 + private final String appId; + private final String accessKeyId; + private final InputStream inputStream; + private final String accessKeySecret; + private final String audioPath; + private final Session realTimePacket; + private final String baseWsUrl = "wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1"; + + // 状态变量 + private WebSocketClient webSocketClient; + private final AtomicBoolean isConnected = new AtomicBoolean(false); + private final AtomicBoolean isSendingAudio = new AtomicBoolean(false); + private String sessionId; + private long audioFileSize = 0; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + + public RTASRClient(String appId, String accessKeyId, String accessKeySecret, String audioPath, InputStream inputStream, Session realTimePacket) { + this.appId = appId; + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.audioPath = audioPath; + this.inputStream = inputStream; + this.realTimePacket = realTimePacket; + } + + /** + * 获取音频文件大小 + */ + private long getAudioFileSize() { + try { + return this.inputStream.available(); + } catch (Exception _e) { + log.info(_e.getMessage()); + } + return 0; + } + + /** + * 生成鉴权参数并建立WebSocket连接 + */ + public boolean connect() { + try { + // 生成鉴权参数 + Map authParams = generateAuthParams(); + String paramsStr = buildParamsString(authParams); + String fullWsUrl = baseWsUrl + "?" + paramsStr; + System.out.println("【连接信息】完整URL:" + fullWsUrl); + + // 创建WebSocket客户端 + webSocketClient = new WebSocketClient(new URI(fullWsUrl)) { + @Override + public void onOpen(ServerHandshake handshakedata) { + isConnected.set(true); + System.out.println("【连接成功】WebSocket握手完成,等待服务端就绪(1.5秒)..."); + + // 启动接收消息处理线程 + executor.submit(() -> receiveMessages()); + + // 等待服务端初始化 + try { + Thread.sleep(1500); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void onMessage(String message) { + try { + // 使用org.json解析JSON消息 + JSONObject json = new JSONObject(message); + System.out.println("【接收消息】" + json.toString()); + + // 处理会话ID + if ("action".equals(json.optString("msg_type"))) { + JSONObject data = json.optJSONObject("data"); + if (data != null && data.has("sessionId")) { + sessionId = data.getString("sessionId"); + System.out.println("【会话信息】已获取sessionId:" + sessionId); + } + } + realTimePacket.getBasicRemote().sendText(message); + } catch (Exception e) { + int maxLength = Math.min(50, message.length()); + System.out.println("【接收异常】非JSON文本消息:" + message.substring(0, maxLength) + "..."); + } + } + + @Override + public void onClose(int code, String reason, boolean remote) { + isConnected.set(false); + System.out.println("【连接关闭】代码:" + code + ",原因:" + reason); + } + + @Override + public void onError(Exception ex) { + System.err.println("【WebSocket错误】" + ex.getMessage()); + ex.printStackTrace(); + } + }; + + // 连接服务器 + webSocketClient.connectBlocking(15, TimeUnit.SECONDS); + return isConnected.get(); + } catch (Exception e) { + System.err.println("【连接失败】" + e.getMessage()); + e.printStackTrace(); + return false; + } + } + + /** + * 接收并处理服务端消息 + */ + private void receiveMessages() { + while (isConnected.get() && webSocketClient != null) { + try { + // 等待消息(通过onMessage回调处理) + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } catch (Exception e) { + System.err.println("【接收异常】" + e.getMessage()); + e.printStackTrace(); + close(); + break; + } + } + System.out.println("【接收线程】连接已关闭,退出接收循环"); + } + + /** + * 发送音频文件(带精确节奏控制) + */ + public boolean sendAudio() throws IOException { + if (!isConnected.get() || webSocketClient == null || isSendingAudio.get()) { + System.out.println("【发送失败】WebSocket未连接或已有发送任务"); + return false; + } + + isSendingAudio.set(true); + audioFileSize = getAudioFileSize(); + try (InputStream fis = this.getInputStream()) { + System.out.println(fis.available()); + // 计算总帧数和预估时长 + long totalFrames = audioFileSize / AUDIO_FRAME_SIZE; + long remainingBytes = audioFileSize % AUDIO_FRAME_SIZE; + if (remainingBytes > 0) { + totalFrames++; + } + double estimatedDuration = (totalFrames * FRAME_INTERVAL_MS) / 1000.0; + System.out.printf("【发送配置】音频文件大小:%d字节 | 总帧数:%d | 预估时长:%.1f秒%n", audioFileSize, totalFrames, estimatedDuration); + System.out.printf("【发送配置】每%dms发送%d字节,严格控制节奏%n", FRAME_INTERVAL_MS, AUDIO_FRAME_SIZE); + + // 发送音频帧 + byte[] buffer = new byte[AUDIO_FRAME_SIZE]; + int bytesRead; + int frameIndex = 0; + Long startTime = null; + + while ((bytesRead = fis.read(buffer)) != -1) { + // 处理实际读取的字节数(最后一帧可能不足AUDIO_FRAME_SIZE) + byte[] frameData = bytesRead == AUDIO_FRAME_SIZE ? buffer : Arrays.copyOf(buffer, bytesRead); + + // 记录起始时间 + if (startTime == null) { + startTime = System.currentTimeMillis(); + System.out.println("【发送开始】起始时间:" + startTime + "ms(基准时间)"); + } + + // 计算理论发送时间 + long expectedSendTime = startTime + (frameIndex * FRAME_INTERVAL_MS); + long currentTime = System.currentTimeMillis(); + long timeDiff = expectedSendTime - currentTime; + + // 动态调整休眠时间 + if (timeDiff > 1) { // 大于1ms才休眠 + try { + Thread.sleep(timeDiff); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + } + + // 发送音频帧(二进制消息) + webSocketClient.send(frameData); + + // 打印节奏控制日志(每10帧) + if (frameIndex % 10 == 0) { + long actualSendTime = System.currentTimeMillis(); + System.out.printf("【节奏控制】帧%d | 理论时间:%dms | 实际时间:%dms | 误差:%.1fms%n", frameIndex, expectedSendTime, actualSendTime, (actualSendTime - expectedSendTime) * 1.0); + } + + frameIndex++; + } + + System.out.println("【发送完成】所有音频帧发送完毕(共" + frameIndex + "帧)"); + + // 发送结束标记(使用org.json构建JSON) + JSONObject endMsg = new JSONObject(); + endMsg.put("end", true); + if (sessionId != null && !sessionId.isEmpty()) { + endMsg.put("sessionId", sessionId); + } + String endMsgStr = endMsg.toString(); + webSocketClient.send(endMsgStr); + System.out.println("【发送结束】已发送标准JSON结束标记:" + endMsgStr); + + return false; + } catch (FileNotFoundException e) { + System.err.println("【发送失败】音频文件不存在:" + audioPath); + e.printStackTrace(); + } catch (IOException e) { + System.err.println("【发送异常】文件读取错误:" + e.getMessage()); + e.printStackTrace(); + } finally { + isSendingAudio.set(false); + } + return false; + } + + /** + * 生成鉴权参数 + */ + private Map generateAuthParams() { + Map params = new TreeMap<>(); // TreeMap保证字典序排序 + + // 固定参数 + params.put("audio_encode", AUDIO_ENCODE); + params.put("lang", LANG); + params.put("samplerate", SAMPLERATE); + + // 动态参数 + params.put("accessKeyId", accessKeyId); + params.put("appId", appId); + params.put("uuid", UUID.randomUUID().toString().replaceAll("-", "")); + params.put("utc", getUtcTime()); + + // 计算签名 + String signature = calculateSignature(params); + params.put("signature", signature); + + return params; + } + + /** + * 生成UTC时间字符串(yyyy-MM-dd'T'HH:mm:ss+0800) + */ + private String getUtcTime() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT+8")); + return sdf.format(new Date()); + } + + /** + * 计算HMAC-SHA1签名 + */ + private String calculateSignature(Map params) { + try { + // 构建基础字符串 + StringBuilder baseStr = new StringBuilder(); + boolean first = true; + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + + // 跳过signature参数 + if ("signature".equals(key)) continue; + // 过滤空值 + if (value == null || value.trim().isEmpty()) continue; + + if (!first) { + baseStr.append("&"); + } + baseStr.append(URLEncoder.encode(key, StandardCharsets.UTF_8.name())).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8.name())); + first = false; + } + + // HMAC-SHA1计算 + Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec keySpec = new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"); + mac.init(keySpec); + byte[] signBytes = mac.doFinal(baseStr.toString().getBytes(StandardCharsets.UTF_8)); + + // Base64编码 + return Base64.getEncoder().encodeToString(signBytes); + } catch (Exception e) { + throw new RuntimeException("计算签名失败", e); + } + } + + /** + * 构建参数字符串 + */ + private String buildParamsString(Map params) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (Map.Entry entry : params.entrySet()) { + if (!first) { + sb.append("&"); + } + try { + sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name())).append("=").append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name())); + } catch (UnsupportedEncodingException e) { + // UTF-8编码总是支持的 + e.printStackTrace(); + } + first = false; + } + return sb.toString(); + } + + /** + * 关闭连接 + */ + public void close() { + if (isConnected.get() && webSocketClient != null) { + isConnected.set(false); + webSocketClient.close(); + System.out.println("【连接关闭】WebSocket已安全关闭"); + } else { + System.out.println("【连接关闭】WebSocket已断开或未初始化"); + } + executor.shutdown(); + try { + if (!executor.awaitTermination(1, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + } + } + + +} diff --git a/src/main/java/com/realtime/sysconst/Result.java b/src/main/java/com/realtime/sysconst/Result.java new file mode 100644 index 0000000..6902533 --- /dev/null +++ b/src/main/java/com/realtime/sysconst/Result.java @@ -0,0 +1,61 @@ +package com.realtime.sysconst; + +import lombok.Data; + +@Data +public class Result { + private Integer code; + private String msg; + private T data; + private String token; + private Long timestamp = System.currentTimeMillis(); + + + public static Result success(T data) { + Result result = new Result<>(); + result.setCode(0); + result.setMsg("成功"); + result.setData(data); + return result; + } + + public static Result success(T data,String token) { + Result result = new Result<>(); + result.setCode(0); + result.setMsg("成功"); + result.setToken(token); + result.setData(data); + return result; + } + + + public static Result fail(String msg) { + Result result = new Result<>(); + result.setCode(-1); + result.setMsg(msg); + result.setData(null); + return result; + } + + public static Result notAuth(String msg) { + Result result = new Result<>(); + result.setCode(-2); + result.setMsg(msg); + result.setData(null); + return result; + } + + public static Result systemError(String msg) { + return notAuth(msg); + } + + public static Result systemError(String msg,Integer code) { + Result result = new Result<>(); + result.setCode(code); + result.setMsg(msg); + result.setData(null); + return result; + } + + +} diff --git a/src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java b/src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java new file mode 100644 index 0000000..a1f1e2d --- /dev/null +++ b/src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java @@ -0,0 +1,30 @@ +package com.realtime.sysconst.enumConst; + +import lombok.Getter; + +@Getter +public enum ResultEnum { + SYSTEM_ERROR("系统异常",500), + FILE_NOT_NULL("请上传文件", -8), + FILE_FORMAT_ERROR("文件格式不正确", -9), + LOGIN_DISABLE("账户状态异常",-10), + PARAMETER_ERROR("参数异常",-11), + PERMISSION_INSUFFICIENT("权限不足", -12), + SEND_ERROR("请稍后发送", -13), + MSG_CODE_ERROR("验证码错误", -4), + ACCOUNT_ERROR_OR_PASSWORD_ERROR("用户名或密码错误",-15), + ACCOUNT_NOT_EXITS("账户不存在",-16), + CUSTOMER_NOT_EXITS("该客户不存在",-17), + MANAGER_NOT_EXITS("该领导不存在",-18), + ASSIGNEE_NOT_EXITS("该负责人不存在",-19), + DATABASE_EXITS("动态数据库已存在",-20); + + private final String msg; + private final Integer code; + + ResultEnum(String msg, Integer code) { + this.msg = msg; + this.code = code; + } + +} diff --git a/src/main/java/com/realtime/utils/Attributes.java b/src/main/java/com/realtime/utils/Attributes.java new file mode 100644 index 0000000..4702914 --- /dev/null +++ b/src/main/java/com/realtime/utils/Attributes.java @@ -0,0 +1,9 @@ +package com.realtime.utils; + + +import com.realtime.packets.basePackets.BasePackets; +import io.netty.util.AttributeKey; + +public interface Attributes { + AttributeKey SESSION = AttributeKey.newInstance("session"); +} diff --git a/src/main/java/com/realtime/utils/Base64ToMultipartFile.java b/src/main/java/com/realtime/utils/Base64ToMultipartFile.java new file mode 100644 index 0000000..091524a --- /dev/null +++ b/src/main/java/com/realtime/utils/Base64ToMultipartFile.java @@ -0,0 +1,89 @@ +package com.realtime.utils; + +import org.jetbrains.annotations.NotNull; +import org.springframework.web.multipart.MultipartFile; +import java.io.*; + +public class Base64ToMultipartFile { + + public static MultipartFile convert(byte[] byteData , String filename) { + final byte[] bytes = byteData; + + return new MultipartFile() { + @NotNull + @Override + public String getName() { + return "file"; + } + + @Override + public String getOriginalFilename() { + return filename; + } + + @Override + public String getContentType() { + return getContentTypeFromFilename(filename); + } + + @Override + public boolean isEmpty() { + return bytes.length == 0; + } + + @Override + public long getSize() { + return bytes.length; + } + + @NotNull + @Override + public byte[] getBytes() throws IOException { + return bytes; + } + + @NotNull + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(bytes); + } + + @Override + public void transferTo(@NotNull File dest) throws IOException, IllegalStateException { + try (FileOutputStream fos = new FileOutputStream(dest)) { + fos.write(bytes); + } + } + }; + } + + private static String getContentTypeFromFilename(String filename) { + if (filename == null) { + return "application/octet-stream"; + } + + String lowerCaseFilename = filename.toLowerCase(); + + if (lowerCaseFilename.endsWith(".jpg") || lowerCaseFilename.endsWith(".jpeg")) { + return "image/jpeg"; + } else if (lowerCaseFilename.endsWith(".png")) { + return "image/png"; + } else if (lowerCaseFilename.endsWith(".gif")) { + return "image/gif"; + } else if (lowerCaseFilename.endsWith(".pdf")) { + return "application/pdf"; + } else if (lowerCaseFilename.endsWith(".txt")) { + return "text/plain"; + } else if (lowerCaseFilename.endsWith(".doc")) { + return "application/msword"; + } else if (lowerCaseFilename.endsWith(".docx")) { + return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + } else if (lowerCaseFilename.endsWith(".xls")) { + return "application/vnd.ms-excel"; + } else if (lowerCaseFilename.endsWith(".xlsx")) { + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + } + + return "application/octet-stream"; + } +} diff --git a/src/main/java/com/realtime/utils/InputStreamMultipartFile.java b/src/main/java/com/realtime/utils/InputStreamMultipartFile.java new file mode 100644 index 0000000..1de75e5 --- /dev/null +++ b/src/main/java/com/realtime/utils/InputStreamMultipartFile.java @@ -0,0 +1,66 @@ +package com.realtime.utils; + +import org.jetbrains.annotations.NotNull; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.util.FileCopyUtils; + +import java.io.*; + +public class InputStreamMultipartFile implements MultipartFile { + + private final String name; + private final String originalFilename; + private final String contentType; + private final byte[] content; + + public InputStreamMultipartFile(String name, String originalFilename, + String contentType, InputStream inputStream) throws IOException { + this.name = name; + this.originalFilename = originalFilename; + this.contentType = contentType; + this.content = FileCopyUtils.copyToByteArray(inputStream); + } + + @NotNull + @Override + public String getName() { + return this.name; + } + + @Override + public String getOriginalFilename() { + return this.originalFilename; + } + + @Override + public String getContentType() { + return this.contentType; + } + + @Override + public boolean isEmpty() { + return this.content.length == 0; + } + + @Override + public long getSize() { + return this.content.length; + } + + @NotNull + @Override + public byte[] getBytes() throws IOException { + return this.content; + } + + @NotNull + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(this.content); + } + + @Override + public void transferTo(@NotNull File dest) throws IOException, IllegalStateException { + FileCopyUtils.copy(this.content, dest); + } +} diff --git a/src/main/java/com/realtime/utils/SessionUtils.java b/src/main/java/com/realtime/utils/SessionUtils.java new file mode 100644 index 0000000..a6782d7 --- /dev/null +++ b/src/main/java/com/realtime/utils/SessionUtils.java @@ -0,0 +1,74 @@ +package com.realtime.utils; + +import com.realtime.packets.basePackets.BasePackets; +import io.netty.channel.Channel; +import io.netty.channel.group.ChannelGroup; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class SessionUtils { + + public static final Map userIdChannelMap = new ConcurrentHashMap<>(); + + /** + * groupId ---> channelgroup 群聊ID和群聊ChannelGroup映射 + */ + public static final Map sessionUser = new ConcurrentHashMap<>(); + + private static final Map groupIdChannelGroupMap = new ConcurrentHashMap<>(); + + public static void bindChannel(BasePackets user, Channel channel) { + userIdChannelMap.put(user.getSender(), channel); + sessionUser.put(user.getSender(), user); + channel.attr(Attributes.SESSION).set(user); + } + + public static void unbind(Channel channel) { + if (hasLogin(channel)) { + userIdChannelMap.remove(getUser(channel).getSender()); + channel.attr(Attributes.SESSION).set(null); + } + } + + public static boolean hasLogin(Channel channel) { + return channel.hasAttr(Attributes.SESSION); + } + + public static BasePackets getUser(Channel channel) { + return channel.attr(Attributes.SESSION).get(); + } + + public static Channel getChannel(String userId) { + return userIdChannelMap.get(userId) == null ? null : userIdChannelMap.get(userId); + } + + public static void bindChannelGroup(Long groupId, ChannelGroup channelGroup) { + groupIdChannelGroupMap.put(groupId, channelGroup); + } + + public static ChannelGroup getChannelGroup(Long groupId) { + return groupIdChannelGroupMap.get(groupId) == null ? null : groupIdChannelGroupMap.get(groupId); + } + + public static void removeChanelByGroup(Long groupId, String phone) { + Channel channel = getChannel(phone); + if (channel != null) { + ChannelGroup channelGroup = getChannelGroup(groupId); + if (channelGroup != null) { + channelGroup.remove(channel); + } + } + } + + public static void removeBatchChannel(Long groupId, List phone) { + ChannelGroup channelGroup = getChannelGroup(groupId); + if (channelGroup != null) { + phone.forEach(item -> { + Channel channel = getChannel(item); + channelGroup.remove(channel); + }); + } + } +} diff --git a/src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java b/src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java new file mode 100644 index 0000000..c64ac5e --- /dev/null +++ b/src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java @@ -0,0 +1,21 @@ +package com.realtime.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public class ChatFriendRelationshipInfoVo implements Serializable { + private Long id; + private Long sessionId; + private Integer state; + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdTime; + private String sendId; + private String recipientId; + private String friendNickName; +} diff --git a/src/main/java/com/realtime/vo/ChatListInfoVo.java b/src/main/java/com/realtime/vo/ChatListInfoVo.java new file mode 100644 index 0000000..4e79de3 --- /dev/null +++ b/src/main/java/com/realtime/vo/ChatListInfoVo.java @@ -0,0 +1,19 @@ +package com.realtime.vo; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class ChatListInfoVo implements Serializable { + private Long id; + private String sender; + private String receiver; + private String avatar; + private String nickName; + private String friendNickName; + private Long sessionId; + private Integer isDelete; + private Boolean exits; + private Integer type; +} diff --git a/src/main/java/com/realtime/vo/ChatReqVo.java b/src/main/java/com/realtime/vo/ChatReqVo.java new file mode 100644 index 0000000..5120ebe --- /dev/null +++ b/src/main/java/com/realtime/vo/ChatReqVo.java @@ -0,0 +1,9 @@ +package com.realtime.vo; + +import lombok.Data; + +@Data +public class ChatReqVo { + private String txt; + private String fileId; +} diff --git a/src/main/java/com/realtime/vo/FriendMessageVo.java b/src/main/java/com/realtime/vo/FriendMessageVo.java new file mode 100644 index 0000000..d7f6871 --- /dev/null +++ b/src/main/java/com/realtime/vo/FriendMessageVo.java @@ -0,0 +1,19 @@ +package com.realtime.vo; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class FriendMessageVo implements Serializable { + private Long id; + private String sender; + private String receiver; + private String avatar; + private MessageItemVo item; + private String friendNickName; + private Long sessionId; + private String nickName; + private String friendName; // 好友给我备注的昵称 + private String contentJson; +} diff --git a/src/main/java/com/realtime/vo/GroupDetailVo.java b/src/main/java/com/realtime/vo/GroupDetailVo.java new file mode 100644 index 0000000..2aa7040 --- /dev/null +++ b/src/main/java/com/realtime/vo/GroupDetailVo.java @@ -0,0 +1,13 @@ +package com.realtime.vo; + +import lombok.Data; + +@Data +public class GroupDetailVo { + private Long id; + private String name; + private Boolean owner; + private Integer isInvent; + private String creator; + private String qrCode; +} diff --git a/src/main/java/com/realtime/vo/GroupListMessagesVo.java b/src/main/java/com/realtime/vo/GroupListMessagesVo.java new file mode 100644 index 0000000..8c18b27 --- /dev/null +++ b/src/main/java/com/realtime/vo/GroupListMessagesVo.java @@ -0,0 +1,13 @@ +package com.realtime.vo; +import lombok.Data; + +@Data +public class GroupListMessagesVo { + private Long id; + private String message; + private Integer messageType; + private Long groupId; + private Long createTime; + private String contentJson; + private String sender; +} diff --git a/src/main/java/com/realtime/vo/GroupListVo.java b/src/main/java/com/realtime/vo/GroupListVo.java new file mode 100644 index 0000000..09e1f00 --- /dev/null +++ b/src/main/java/com/realtime/vo/GroupListVo.java @@ -0,0 +1,15 @@ +package com.realtime.vo; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class GroupListVo { + private Long id; + private String name; + private String picture; + private Integer type; + private String content; + private LocalDateTime createTime; +} diff --git a/src/main/java/com/realtime/vo/GroupMemberListVo.java b/src/main/java/com/realtime/vo/GroupMemberListVo.java new file mode 100644 index 0000000..5791b06 --- /dev/null +++ b/src/main/java/com/realtime/vo/GroupMemberListVo.java @@ -0,0 +1,10 @@ +package com.realtime.vo; + +import lombok.Data; + +@Data +public class GroupMemberListVo { + private Long id; + private String groupContactId; + private Long groupId; +} diff --git a/src/main/java/com/realtime/vo/MessageInfoVo.java b/src/main/java/com/realtime/vo/MessageInfoVo.java new file mode 100644 index 0000000..e00e6c5 --- /dev/null +++ b/src/main/java/com/realtime/vo/MessageInfoVo.java @@ -0,0 +1,22 @@ +package com.realtime.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public class MessageInfoVo implements Serializable { + + private String avatar; + private String nickName; + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime;; + private String message; + private String role; + private String ip; + private Integer type; +} diff --git a/src/main/java/com/realtime/vo/MessageItemVo.java b/src/main/java/com/realtime/vo/MessageItemVo.java new file mode 100644 index 0000000..618ddb4 --- /dev/null +++ b/src/main/java/com/realtime/vo/MessageItemVo.java @@ -0,0 +1,10 @@ +package com.realtime.vo; + +import lombok.Data; + +@Data +public class MessageItemVo { + private String content; + private Integer type; + private Long createTime; +} diff --git a/src/main/java/com/realtime/vo/MessageVo.java b/src/main/java/com/realtime/vo/MessageVo.java new file mode 100644 index 0000000..43f2a30 --- /dev/null +++ b/src/main/java/com/realtime/vo/MessageVo.java @@ -0,0 +1,17 @@ +package com.realtime.vo; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class MessageVo implements Serializable { + private String sender; + private String receiver; + private String content; + private Long taskId; + private String avatar; + private Long createTime; + private String messageType; + private String contentJson; +} diff --git a/src/main/java/com/realtime/vo/UploadVo.java b/src/main/java/com/realtime/vo/UploadVo.java new file mode 100644 index 0000000..737fd0c --- /dev/null +++ b/src/main/java/com/realtime/vo/UploadVo.java @@ -0,0 +1,16 @@ +package com.realtime.vo; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +public class UploadVo implements Serializable { + private BigDecimal fileSize; + private String url; + private String newFileName; + private String name; + private String extendName; + private String fileNameCode; +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..17518e4 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,53 @@ +server: + port: 70 + servlet: + context-path: /api +minio: + endpoint: https://database.yuxindazhineng.com + access-key: yuxinda_admin + secret-key: yuxinda_admin01 + bucket-name: real +file: + picMaxSize: 104857600 # 100MB + picMaxCount: 1 + picAllowedFormats: png,jpg + allowedFormats: doc,docx,xls,xlsx,ppt,pptx,txt,jpg,jpeg,png,gif,svg,mp3,mp4,zip,rar,exe,dmg,apk,md +spring: + servlet: + multipart: + max-request-size: 100MB + max-file-size: 100MB + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://8.134.75.237:3309/real_time?serverTimezone=Asia/Shanghai + username: root + password: zhengfei_2024 + type: com.alibaba.druid.pool.DruidDataSource +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + map-underscore-to-camel-case: true + auto-mapping-unknown-column-behavior: warning + mapper-locations: classpath*:/mappers/**/*.xml + type-aliases-package: com.realtime.vo +baidu: + tts: + app-id: 118182863 + api-key: WemzV9uFIDTad8s0VeCxfrf9 + secret-key: kRr1OrebrE1kWPn1B02ECbGK5yCCKEdJ +doubao: + voice: + app-id: 9478107274 + api-key: FADK4NWToP_0oSbPr__4qSENvCsPN795 + access-token: HQ6ZJzTG3MmceyZDuZZSZQYQUrfiewdZ + websocket-url: wss://openspeech.bytedance.com/api/v3/realtime/dialogue +rtsa: + appId: 5d899195 + accessKeyId: 4c428332836cd9481be4127c941f4167 + accessKeySecret: ZjFiMWViMGY0NDA4ODNkNDgxYzg0Yzg3 + baseWsUrl: wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1 + audioEncode: pcm_s16le + lang: autodialect + samplerate: 16000 + audioFameSize: 1280 + frameIntervalMs: 40 diff --git a/src/main/resources/mappers/ChatListMapper.xml b/src/main/resources/mappers/ChatListMapper.xml new file mode 100644 index 0000000..df8318a --- /dev/null +++ b/src/main/resources/mappers/ChatListMapper.xml @@ -0,0 +1,38 @@ + + + + + + + + id + ,friend_nick_name,sender,receiver,is_top,session_id, + is_delete,created_time + + + + delete from chat_list lt where lt.sender = #{id} and lt.receiver = #{receiver} + + + + + + + + diff --git a/src/main/resources/mappers/FriendRelationshipMapper.xml b/src/main/resources/mappers/FriendRelationshipMapper.xml new file mode 100644 index 0000000..d62a828 --- /dev/null +++ b/src/main/resources/mappers/FriendRelationshipMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + update friend_relationship + set state = 1 + where id = #{id} + + + diff --git a/src/main/resources/mappers/GroupListMapper.xml b/src/main/resources/mappers/GroupListMapper.xml new file mode 100644 index 0000000..05687a4 --- /dev/null +++ b/src/main/resources/mappers/GroupListMapper.xml @@ -0,0 +1,53 @@ + + + + + + + id + ,name,creator, + created_time,picture,type, + is_invent + + + + + + + + update group_list + set is_invent = #{req.invent} + where id = #{req.groupId} + + + + + + diff --git a/src/main/resources/mappers/GroupMemberMapper.xml b/src/main/resources/mappers/GroupMemberMapper.xml new file mode 100644 index 0000000..430310e --- /dev/null +++ b/src/main/resources/mappers/GroupMemberMapper.xml @@ -0,0 +1,70 @@ + + + + + + id + ,group_id,group_contact_id, + created_time + + + + + + + + + delete + from group_member grp + where grp.group_id = #{groupId} + and grp.group_contact_id = #{groupContactId} + + + + delete + from group_member grp + where grp.group_id = #{req.groupId} + + + + delete from group_member grp where grp.group_contact_id in + + #{item} + + and grp.group_id = #{req.groupId} + + + diff --git a/src/main/resources/mappers/GroupMessageMapper.xml b/src/main/resources/mappers/GroupMessageMapper.xml new file mode 100644 index 0000000..1398d7d --- /dev/null +++ b/src/main/resources/mappers/GroupMessageMapper.xml @@ -0,0 +1,25 @@ + + + + + + + id + ,message,group_id, + sender,create_time,message_type + + + + diff --git a/src/main/resources/mappers/MessageMapper.xml b/src/main/resources/mappers/MessageMapper.xml new file mode 100644 index 0000000..e227a74 --- /dev/null +++ b/src/main/resources/mappers/MessageMapper.xml @@ -0,0 +1,57 @@ + + + + + + + + id + , sender, receiver, session_id, message_type, content, create_time + + + + + + + + + + + + + + + + + +