diff --git a/README.md b/README.md index 72d08d5..261a3a5 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,17 @@ 基于WebRTC实现信令服务,实现Mesh、MCU和SFU三种媒体通信架构,支持直播会议两种场景。 项目提供WebRTC服务信令,终端已有H5示例,其他终端需要自己实现。 -## 授权 - -开源公益免费,商用需要购买授权。 - ## 模块 |模块|名称|描述| |:--|:--|:--| |taoyao|桃夭|桃之夭夭灼灼其华| -|taoyao-boot|启动模块|基础模块| +|taoyao-boot|基础模块|基础模块| |taoyao-live|直播|直播、连麦| |taoyao-test|测试|测试工具| -|taoyao-media|媒体|录制、视频(美颜、AI识别)、音频(混音、变声、降噪)| +|taoyao-media|媒体|录制、视频(水印、美颜、AI识别)、音频(降噪、混音、变声)| |taoyao-signal|信令|信令服务| -|taoyao-server|服务|启动服务| +|taoyao-server|启动服务|启动服务| |taoyao-meeting|会议|会议模式、广播模式、单人对讲| |taoyao-webrtc|WebRTC模块|WebRTC模块| |taoyao-webrtc-sfu|WebRTC SFU架构|SFU架构| @@ -36,15 +32,15 @@ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | taoyao-live | taoyao-meeting | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| taoyao-signal | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | taoyao-media | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | taoyao-mcu / taoyao-sfu | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ taoyao-mesh + | taoyao-jitsi / taoyao-kurento | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| taoyao-boot | +| taoyao-signal | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-boot | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ``` @@ -54,50 +50,19 @@ > 只有公网Mesh架构才需要真正的内网穿透 -## 信令 - -|功能|描述|标识|响应| -|:--|:--|:--|:--| -|注册|终端注册(同步信息)||| -|关闭|终端关闭(注销)||| -|心跳|终端心跳||| -|创建会议|创建会议||返回会议ID| -|进入会议|没有会议自动创建||返回会议终端同时广播进入消息| -|离开会议|离开会议||广播离开消息| -|关闭会议|关闭会议(踢出所有人员)||广播关闭消息| -|终端列表|||返回所有终端列表| -|会议终端列表|||返回所有会议终端列表| -|直播终端列表|||返回所有直播终端列表| -|邀请终端|会议邀请终端(主动/被动)||单播邀请| -|踢出终端|会议踢出终端||单播踢出| -|开启直播|||| -|关闭直播|||| -|发布|控制终端推流||| -|取消发布|控制终端暂停推流||| -|订阅|订阅终端媒体流||| -|取消订阅|取消订阅终端媒体流||| -|暂停媒体流|暂停终端媒体流分流(不关媒体流通道)||| -|恢复媒体流|恢复终端媒体流分流(不关媒体流通道)||| -|开启录像|||| -|关闭录像|||| -|终端状态|||| -|单播消息|发送指定终端||| -|广播消息|广播排除自己的所有终端||| -|全员广播消息|广播包括自己的所有终端||| -|异常|异常信息||| - ## 直播 终端推流到服务端,由服务端分流。 ## 会议 +Mesh架构声音视频控制部分功能均在终端实现,同时不会实现终端录制、美颜、AI识别、变声、混音等等功能。 +MCU/SFU声音视频控制在服务端实现,如果没有终端订阅并且没有录制是不会对终端进行拉流。 + ### Mesh 流媒体点对点连接,不经过服务端。 -> 录制、AI识别等等功能只能在终端实现。 - ### MCU 终端推流到服务端,由服务端分流并且混音。 diff --git a/docs/FFmpeg.md b/docs/FFmpeg.md new file mode 100644 index 0000000..525add6 --- /dev/null +++ b/docs/FFmpeg.md @@ -0,0 +1,92 @@ +# FFmpeg + +默认使用`ffmpeg-platform`所以不用安装,如果使用本地FFmpeg需要自己安装。 + +## FFmpeg + +``` +# nasm +wget https://www.nasm.us/pub/nasm/releasebuilds/2.14/nasm-2.14.tar.gz +tar zxvf nasm-2.14.tar.gz +cd nasm-2.14 +./configure --prefix=/usr/local/nasm +make -j && make install +# 环境变量 +vim /etc/profile +export PATH=$PATH:/usr/local/nasm/bin +source /etc/profile + +# yasm +wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz +tar zxvf yasm-1.3.0.tar.gz +cd yasm-1.3.0 +./configure --prefix=/usr/local/yasm +make -j && make install +# 环境变量 +vim /etc/profile +export PATH=$PATH:/usr/local/yasm/bin +source /etc/profile + +# x264 +git clone https://code.videolan.org/videolan/x264.git +cd x264 +./configure --prefix=/usr/local/x264 --libdir=/usr/local/lib --includedir=/usr/local/include --enable-shared --enable-static +make -j && make install +# 环境变量 +vim /etc/profile +export PATH=$PATH:/usr/local/x264/bin +source /etc/profile + +# 编码解码 +# acc +https://github.com/mstorsjo/fdk-aac.git +--enable-libfdk_aac +# vpx +https://github.com/webmproject/libvpx.git +--enable-libvpx +# x265 +https://bitbucket.org/multicoreware/x265 +--enable-libx265 +# opus +https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz +--enable-libopus + +# ffmpeg +wget http://www.ffmpeg.org/releases/ffmpeg-4.3.1.tar.xz +tar xvJf ffmpeg-4.3.1.tar.xz +cd ffmpeg-4.3.1 +./configure --prefix=/usr/local/ffmpeg --enable-gpl --enable-shared --enable-libx264 +# --enable-cuda --enable-cuvid --enable-nvenc --nvcc=/usr/local/cuda-11.0/bin/nvcc +make -j && make install +# 环境变量 +vim /etc/profile +export PATH=$PATH:/usr/local/ffmpeg/bin +source /etc/profile + +# lib +vim /etc/ld.so.conf +/usr/local/x264/lib/ +/usr/local/ffmpeg/lib/ +ldconfig + +# 查看版本 +ffmpeg -version +# 查看编解码 +ffmpeg -codecs +# 格式化文件 +ffmpeg -y -i source.mkv -c copy target.mp4 +# 查看文件格式 +ffprobe -v error -show_streams -print_format json source.mp4 +``` + +## GPU + +``` +驱动 +# cuda +https://developer.nvidia.com/cuda-downloads +# nv-codec-headers +https://git.videolan.org/git/ffmpeg/nv-codec-headers.git +# 验证 +nvidia-smi +``` diff --git a/docs/LINK.md b/docs/LINK.md new file mode 100644 index 0000000..ba1f7e3 --- /dev/null +++ b/docs/LINK.md @@ -0,0 +1,12 @@ +https://www.jianshu.com/p/fa047d7054eb +https://www.jianshu.com/p/59da3d350488 +https://segmentfault.com/a/1190000039782685 +https://www.cnblogs.com/bolingcavalry/p/15473808.html +http://www.manoner.com/post/音视频基础/WebRTC核心组件和协议栈/ +https://blog.csdn.net/eguid_1/article/details/117277841 +https://blog.csdn.net/xiang_6119/article/details/108779678 +https://blog.csdn.net/qq_40321119/article/details/108336324 +https://blog.csdn.net/ababab12345/article/details/115585378 +https://blog.csdn.net/jisuanji111111/article/details/121634199 +https://blog.csdn.net/weixin_48638578/article/details/120191152 +https://blog.csdn.net/weixin_45565568/article/details/108929438 diff --git a/pom.xml b/pom.xml index ff411f5..f3da863 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,8 @@ 17 1.18.24 + 1.5.8 + 5.1.2 6.18.0 1.6.12 1.5.3.Final @@ -61,7 +63,7 @@ org.projectlombok lombok - + org.apache.commons commons-lang3 @@ -70,6 +72,11 @@ org.apache.commons commons-collections4 + + + org.springdoc + springdoc-openapi-ui + com.fasterxml.jackson.core @@ -186,12 +193,62 @@ kurento-client ${kurento.version} + + + org.bytedeco + ffmpeg-platform + ${ffmpeg.version}-${javacv.version} + + + org.bytedeco + ffmpeg + + + org.bytedeco + javacpp + + + + + org.bytedeco + ffmpeg + ${ffmpeg.version}-${javacv.version} + ${javacv.os.version} + + + org.bytedeco + javacpp + ${javacv.version} + ${javacv.os.version} + org.apache.commons commons-collections4 ${collections4.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + org.mapstruct @@ -205,13 +262,6 @@ ${mapstruct.version} provided - - - org.projectlombok - lombok - ${lombok.version} - provided - @@ -306,6 +356,7 @@ dev + windows-x86_64 -Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2 @@ -336,6 +387,7 @@ test test + linux-x86_64 -Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2 @@ -367,7 +419,8 @@ release release - -Dtaoyao.password=123456 + linux-x86_64 + -Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2 diff --git a/taoyao-boot/pom.xml b/taoyao-boot/pom.xml index c9fa638..a1db1e0 100644 --- a/taoyao-boot/pom.xml +++ b/taoyao-boot/pom.xml @@ -14,16 +14,9 @@ jar taoyao-boot - 基础:启动模型 + 启动模块:启动模块 - - - org.springdoc - springdoc-openapi-ui - true - - org.springframework.boot spring-boot-starter-web diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java index 31b18c3..2469d0a 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java @@ -20,6 +20,10 @@ public class SecurityProperties { */ public static final String BASIC = "Basic"; + /** + * 是否启用 + */ + private Boolean enabled; /** * 范围 */ diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/TaoyaoProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/TaoyaoProperties.java index 391274b..ac02337 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/TaoyaoProperties.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/TaoyaoProperties.java @@ -6,7 +6,7 @@ import lombok.Getter; import lombok.Setter; /** - * 系统配置 + * 平台配置 * * @author acgist */ diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Message.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Message.java index a46ce7a..2060776 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Message.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Message.java @@ -24,7 +24,7 @@ import lombok.Setter; @Builder @NoArgsConstructor @AllArgsConstructor -public class Message implements Serializable { +public class Message implements Cloneable, Serializable { private static final long serialVersionUID = 1L; @@ -61,8 +61,8 @@ public class Message implements Serializable { } /** - * @param code 状态编码 - * @param message + * @param code 响应编码 + * @param message 响应描述 * * @return this */ @@ -161,6 +161,30 @@ public class Message implements Serializable { return failMessage; } + @Override + public Message clone() { + try { + return (Message) super.clone(); + } catch (CloneNotSupportedException e) { + return new Message(this.code, this.message, this.header, this.body); + } + } + + /** + * 克隆排除主体 + * + * @return 请求响应消息 + */ + public Message cloneWidthoutBody() { + try { + final Message message = (Message) super.clone(); + message.setBody(null); + return message; + } catch (CloneNotSupportedException e) { + return new Message(this.code, this.message, this.header, null); + } + } + @Override public String toString() { return JSONUtils.toJSON(this); diff --git a/taoyao-live/pom.xml b/taoyao-live/pom.xml index dba5e74..2fc05eb 100644 --- a/taoyao-live/pom.xml +++ b/taoyao-live/pom.xml @@ -19,7 +19,7 @@ com.acgist - taoyao-signal + taoyao-media diff --git a/taoyao-live/src/main/java/com/acgist/taoyao/live/Live.java b/taoyao-live/src/main/java/com/acgist/taoyao/live/Live.java new file mode 100644 index 0000000..e0119f5 --- /dev/null +++ b/taoyao-live/src/main/java/com/acgist/taoyao/live/Live.java @@ -0,0 +1,17 @@ +package com.acgist.taoyao.live; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +/** + * 直播 + * + * @author acgist + */ +@Getter +@Setter +@Schema(title = "直播", description = "直播") +public class Live { + +} diff --git a/taoyao-live/src/main/java/com/acgist/taoyao/live/LiveManager.java b/taoyao-live/src/main/java/com/acgist/taoyao/live/LiveManager.java new file mode 100644 index 0000000..9433055 --- /dev/null +++ b/taoyao-live/src/main/java/com/acgist/taoyao/live/LiveManager.java @@ -0,0 +1,5 @@ +package com.acgist.taoyao.live; + +public class LiveManager { + +} diff --git a/taoyao-live/src/main/java/com/acgist/taoyao/live/controller/LiveController.java b/taoyao-live/src/main/java/com/acgist/taoyao/live/controller/LiveController.java new file mode 100644 index 0000000..10d95cd --- /dev/null +++ b/taoyao-live/src/main/java/com/acgist/taoyao/live/controller/LiveController.java @@ -0,0 +1,33 @@ +package com.acgist.taoyao.live.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.live.Live; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 直播 + * + * @author acgist + */ +@Tag(name = "直播", description = "直播管理") +@RestController +@RequestMapping("/live") +public class LiveController { + + @Operation(summary = "直播列表", description = "直播列表") + @GetMapping("/list") + @ApiResponse(content = @Content(schema = @Schema(implementation = Live.class))) + public Message list() { + return Message.success(); + } + +} diff --git a/taoyao-media/README.md b/taoyao-media/README.md new file mode 100644 index 0000000..0cece0c --- /dev/null +++ b/taoyao-media/README.md @@ -0,0 +1 @@ +# 媒体 diff --git a/taoyao-media/pom.xml b/taoyao-media/pom.xml index 0445f84..b077856 100644 --- a/taoyao-media/pom.xml +++ b/taoyao-media/pom.xml @@ -37,6 +37,20 @@ com.acgist taoyao-webrtc-kurento + + org.bytedeco + ffmpeg-platform + + + org.bytedeco + ffmpeg + ${javacv.os.version} + + + org.bytedeco + javacpp + ${javacv.os.version} + \ No newline at end of file diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/AggregateProcessor.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/AggregateProcessor.java new file mode 100644 index 0000000..45a2b6f --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/AggregateProcessor.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process; + +/** + * 责任链模式 + * + * @author acgist + */ +public class AggregateProcessor { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/Processor.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/Processor.java new file mode 100644 index 0000000..49cf274 --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/Processor.java @@ -0,0 +1,5 @@ +package com.acgist.taoyao.media.process; + +public class Processor { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/ProcessorChain.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/ProcessorChain.java new file mode 100644 index 0000000..3fbc6df --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/ProcessorChain.java @@ -0,0 +1,5 @@ +package com.acgist.taoyao.media.process; + +public class ProcessorChain { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/DenoiseProcessor.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/DenoiseProcessor.java new file mode 100644 index 0000000..1e4e628 --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/DenoiseProcessor.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process.audio; + +/** + * 降噪 + * + * @author acgist + */ +public class DenoiseProcessor { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/MixProcessor.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/MixProcessor.java new file mode 100644 index 0000000..1234729 --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/MixProcessor.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process.audio; + +/** + * 混音 + * + * @author acgist + */ +public class MixProcessor { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/WhineProcessor.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/WhineProcessor.java new file mode 100644 index 0000000..466282d --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/audio/WhineProcessor.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process.audio; + +/** + * 变声器 + * + * @author acgist + */ +public class WhineProcessor { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/BeautyHandler.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/BeautyHandler.java new file mode 100644 index 0000000..670d8f1 --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/BeautyHandler.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process.video; + +/** + * 美颜 + * + * @author acgist + */ +public class BeautyHandler { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/MarkHandler.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/MarkHandler.java new file mode 100644 index 0000000..0812121 --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/MarkHandler.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process.video; + +/** + * AI识别 + * + * @author acgist + */ +public class MarkHandler { + +} diff --git a/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/WatermarkHandler.java b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/WatermarkHandler.java new file mode 100644 index 0000000..c6914b1 --- /dev/null +++ b/taoyao-media/src/main/java/com/acgist/taoyao/media/process/video/WatermarkHandler.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.media.process.video; + +/** + * 水印 + * + * @author acgist + */ +public class WatermarkHandler { + +} diff --git a/taoyao-meeting/pom.xml b/taoyao-meeting/pom.xml index 289a424..d59724d 100644 --- a/taoyao-meeting/pom.xml +++ b/taoyao-meeting/pom.xml @@ -19,7 +19,7 @@ com.acgist - taoyao-signal + taoyao-media diff --git a/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/Meeting.java b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/Meeting.java new file mode 100644 index 0000000..a4c5d53 --- /dev/null +++ b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/Meeting.java @@ -0,0 +1,17 @@ +package com.acgist.taoyao.meeting; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +/** + * 会议 + * + * @author acgist + */ +@Getter +@Setter +@Schema(title = "会议", description = "会议") +public class Meeting { + +} diff --git a/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/MeetingManager.java b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/MeetingManager.java new file mode 100644 index 0000000..acd40bc --- /dev/null +++ b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/MeetingManager.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.meeting; + +/** + * 房间 + * + * @author acgist + */ +public class MeetingManager { + +} diff --git a/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/controller/MeetingController.java b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/controller/MeetingController.java new file mode 100644 index 0000000..e1f3baf --- /dev/null +++ b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/controller/MeetingController.java @@ -0,0 +1,33 @@ +package com.acgist.taoyao.meeting.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.meeting.Meeting; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 会议 + * + * @author acgist + */ +@Tag(name = "会议", description = "会议管理") +@RestController +@RequestMapping("/meeting") +public class MeetingController { + + @Operation(summary = "会议列表", description = "会议列表") + @GetMapping("/list") + @ApiResponse(content = @Content(schema = @Schema(implementation = Meeting.class))) + public Message list() { + return Message.success(); + } + +} diff --git a/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/room/Room.java b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/room/Room.java deleted file mode 100644 index 0dcf674..0000000 --- a/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/room/Room.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.acgist.taoyao.meeting.room; - -/** - * 房间 - * - * @author acgist - */ -public class Room { - -} diff --git a/taoyao-server/pom.xml b/taoyao-server/pom.xml index 93f78b1..c508c24 100644 --- a/taoyao-server/pom.xml +++ b/taoyao-server/pom.xml @@ -14,7 +14,7 @@ jar taoyao-server - 服务:启动服务 + 启动服务:启动服务 ${project.parent.basedir} @@ -26,18 +26,10 @@ com.acgist taoyao-live - - com.acgist - taoyao-signal - com.acgist taoyao-meeting - - org.springdoc - springdoc-openapi-ui - com.acgist diff --git a/taoyao-server/src/main/java/com/acgist/taoyao/config/TaoyaoAutoConfiguration.java b/taoyao-server/src/main/java/com/acgist/taoyao/config/TaoyaoAutoConfiguration.java index 059fa63..5321970 100644 --- a/taoyao-server/src/main/java/com/acgist/taoyao/config/TaoyaoAutoConfiguration.java +++ b/taoyao-server/src/main/java/com/acgist/taoyao/config/TaoyaoAutoConfiguration.java @@ -1,6 +1,7 @@ package com.acgist.taoyao.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -22,6 +23,7 @@ public class TaoyaoAutoConfiguration { } @Bean + @ConditionalOnProperty(prefix = "taoyao.security", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnMissingBean public SecurityInterceptor securityInterceptor() { return new SecurityInterceptor(); diff --git a/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java b/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java index d965f0c..0aeea3c 100644 --- a/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java +++ b/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java @@ -7,8 +7,12 @@ import org.springframework.web.bind.annotation.RestController; import com.acgist.taoyao.boot.config.MediaProperties; import com.acgist.taoyao.boot.config.WebrtcProperties; +import com.acgist.taoyao.boot.model.Message; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; /** @@ -28,14 +32,16 @@ public class ConfigController { @Operation(summary = "媒体配置", description = "媒体配置") @GetMapping("/media") - public MediaProperties media() { - return this.mediaProperties; + @ApiResponse(content = @Content(schema = @Schema(implementation = MediaProperties.class))) + public Message media() { + return Message.success(this.mediaProperties); } @Operation(summary = "WebRTC配置", description = "WebRTC配置") @GetMapping("/webrtc") - public WebrtcProperties webrtc() { - return this.webrtcProperties; + @ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class))) + public Message webrtc() { + return Message.success(this.webrtcProperties); } } diff --git a/taoyao-server/src/main/resources/application.yml b/taoyao-server/src/main/resources/application.yml index 583fdc5..3948293 100644 --- a/taoyao-server/src/main/resources/application.yml +++ b/taoyao-server/src/main/resources/application.yml @@ -81,6 +81,7 @@ taoyao: record: storage: /data/record security: + enabled: true realm: taoyao permit: /v3/api-docs/,/swagger-ui/,/favicon.ico,/error username: taoyao diff --git a/taoyao-server/src/main/resources/static/javascript/taoyao.js b/taoyao-server/src/main/resources/static/javascript/taoyao.js index fcee481..05bc143 100644 --- a/taoyao-server/src/main/resources/static/javascript/taoyao.js +++ b/taoyao-server/src/main/resources/static/javascript/taoyao.js @@ -1,6 +1,6 @@ /** 桃夭WebRTC终端核心功能 */ /** 配置 */ -const config = { +const taoyaoConfig = { // 当前终端SN sn: 'taoyao', // 信令授权 @@ -86,24 +86,26 @@ function Taoyao( let audioDevice = false; let videoDevice = false; list.forEach(v => { - console.log('终端媒体设备', v.kind, v.label); + console.debug('终端媒体设备', v.kind, v.label); if(v.kind === 'audioinput') { audioDevice = true; } else if(v.kind === 'videoinput') { videoDevice = true; + } else { + console.debug('没有适配设备', v.kind, v.label); } }); if(!audioDevice) { - console.log('终端没有音频输入设备'); + console.warn('终端没有音频输入设备'); self.audioEnabled = false; } if(!videoDevice) { - console.log('终端没有视频输入设备'); + console.warn('终端没有视频输入设备'); self.videoEnabled = false; } }) .catch(e => { - console.log('获取终端设备失败', e); + console.error('获取终端设备失败', e); self.videoEnabled = false; self.videoEnabled = false; }); @@ -120,19 +122,31 @@ function Taoyao( xhr.responseType = mime; xhr.send(data); xhr.onload = function() { + let response = xhr.response; if(xhr.readyState === 4 && xhr.status === 200) { - resolve(xhr.response); + if(response.code === '0000') { + resolve(response.body); + } else { + reject(response.body || response); + } } else { - reject(xhr.response); + reject(response.body || response); } } xhr.onerror = reject; } else { xhr.send(data); + let response; + try { + response = JSON.parse(xhr.response); + } catch(e) { + console.error('响应解析失败', xhr); + response = xhr.response; + } if(xhr.readyState === 4 && xhr.status === 200) { - resolve(JSON.parse(xhr.response)); + resolve(response.body || response); } else { - reject(JSON.parse(xhr.response)); + reject(response.body || response); } } }); @@ -141,13 +155,13 @@ function Taoyao( this.configMedia = function(audio = {}, video = {}) { this.audioConfig = {...this.audioConfig, ...audio}; this.videoCofnig = {...this.videoCofnig, ...video}; - console.log('终端媒体配置', this.audioConfig, this.videoConfig); + console.debug('终端媒体配置', this.audioConfig, this.videoConfig); }; /** WebRTC配置 */ this.configWebrtc = function(config = {}) { this.webSocket = config.signalAddress; this.iceServer = config.stun; - console.log('WebRTC配置', this.webSocket, this.iceServer); + console.debug('WebRTC配置', this.webSocket, this.iceServer); }; /** 信令通道 */ this.buildChannel = function(callback) { @@ -160,7 +174,7 @@ function Taoyao( }; /** 本地媒体 */ this.buildLocalMedia = function() { - console.log("获取终端媒体:", this.audioConfig, this.videoConfig); + console.debug("获取终端媒体:", this.audioConfig, this.videoConfig); let self = this; return new Promise((resolve, reject) => { if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { @@ -190,6 +204,14 @@ function Taoyao( } await this.localVideo.play(); }; + /** 关闭:关闭媒体 */ + this.close = function() { + // TODO:释放资源 + }; + /** 关机:关闭媒体、关闭信令 */ + this.shutdown = function() { + this.close(); + } /** 媒体 */ /** 视频 */ }; @@ -197,7 +219,7 @@ function Taoyao( const protocol = { pid: { /** 心跳 */ - heartbeat: 1000, + heartbeat: 2005, /** 注册 */ register: 2000 }, @@ -240,7 +262,7 @@ const signalChannel = { /** 回调事件 */ callbackMapping: new Map(), /** 心跳时间 */ - heartbeatTime: 10 * 1000, + heartbeatTime: 30 * 1000, /** 心跳定时器 */ heartbeatTimer: null, /** 防止重连 */ @@ -250,9 +272,9 @@ const signalChannel = { /** 最小重连时间 */ minReconnectionDelay: 5 * 1000, /** 最大重连时间 */ - maxReconnectionDelay: 5 * 60 * 1000, + maxReconnectionDelay: 60 * 1000, /** 自动重连失败后重连时间增长倍数 */ - reconnectionDelayGrowFactor: 1.5, + reconnectionDelayGrowFactor: 2, /** 关闭 */ close: function() { clearTimeout(this.heartbeatTimer); @@ -262,10 +284,17 @@ const signalChannel = { let self = this; self.heartbeatTimer = setTimeout(function() { if (self.channel && self.channel.readyState == WebSocket.OPEN) { - self.push(protocol.buildProtocol(config.sn, protocol.pid.heartbeat)); + self.push(protocol.buildProtocol( + taoyaoConfig.sn, + protocol.pid.heartbeat, + { + signal: 100, + battery: 100 + } + )); self.heartbeat(); } else { - console.log('发送心跳失败', self.channel); + console.warn('发送心跳失败', self.channel); } }, self.heartbeatTime); }, @@ -283,7 +312,7 @@ const signalChannel = { } // 打开定时重连 setTimeout(function() { - console.log('信令通道重连', self.address); + console.info('信令通道重连', self.address); self.connect(self.address, self.callback, true); self.lockReconnect = false; }, self.connectionTimeout); @@ -298,21 +327,21 @@ const signalChannel = { let self = this; this.address = address; this.callback = callback; - console.log("连接信令通道", address); + console.debug("连接信令通道", address); return new Promise((resolve, reject) => { self.channel = new WebSocket(address); self.channel.onopen = function(e) { - console.log('信令通道打开', e); + console.debug('信令通道打开', e); self.push(protocol.buildProtocol( - config.sn, + taoyaoConfig.sn, protocol.pid.register, { ip: null, mac: null, signal: 100, battery: 100, - username: config.username, - password: config.password + username: taoyaoConfig.username, + password: taoyaoConfig.password } )); self.connectionTimeout = self.minReconnectionDelay @@ -320,7 +349,7 @@ const signalChannel = { resolve(e); }; self.channel.onclose = function(e) { - console.log('信令通道关闭', self.channel, e); + console.error('信令通道关闭', self.channel, e); if(reconnection) { self.reconnect(); } @@ -334,17 +363,20 @@ const signalChannel = { reject(e); }; self.channel.onmessage = function(e) { - console.log('信令消息', e.data); + console.debug('信令消息', e.data); let data = JSON.parse(e.data); // 注册回调 + let done = false; if(callback) { - callback(data); + done = callback(data); } // 请求回调 if(self.callbackMapping.has(data.header.id)) { self.callbackMapping.get(data.header.id)(); self.callbackMapping.delete(data.header.id); } + // 默认回调 + done || this.defaultCallback(data); }; }); }, @@ -354,11 +386,22 @@ const signalChannel = { if(data && callback) { this.callbackMapping.set(data.header.id, callback); } + // 发送请求 if(data && data.header) { this.channel.send(JSON.stringify(data)); } else { this.channel.send(data); } + }, + /** 默认回调 */ + defaultCallback: function(data) { + console.debug('没有适配信令消息默认处理', data); + switch(data.header.pid) { + case protocol.pid.heartbeat: + break; + case protocol.pid.register: + break; + } } }; /* diff --git a/taoyao-server/src/main/resources/static/meeting.html b/taoyao-server/src/main/resources/static/meeting.html index 4d7ed53..e14d7ab 100644 --- a/taoyao-server/src/main/resources/static/meeting.html +++ b/taoyao-server/src/main/resources/static/meeting.html @@ -71,11 +71,12 @@ switch(data.header.pid) { case protocol.pid.heartbeat: // 心跳 - break; + return true; case protocol.pid.register: - // 录制 - break; + // 注册 + return true; } + return false; } // 创建房间 function create() { @@ -91,7 +92,7 @@ } // 录制视频 function record(e) { - taoyao.push(protocol.buildProtocol(config.sn, protocol.pid.heartbeat), () => { + taoyao.push(protocol.buildProtocol(taoyaoConfig.sn, protocol.pid.heartbeat), () => { classSwitch(e, 'active'); }); } diff --git a/taoyao-server/src/test/java/com/acgist/taoyao/signal/protocol/ScriptProtocolTest.java b/taoyao-server/src/test/java/com/acgist/taoyao/signal/protocol/ScriptProtocolTest.java new file mode 100644 index 0000000..7bd8d72 --- /dev/null +++ b/taoyao-server/src/test/java/com/acgist/taoyao/signal/protocol/ScriptProtocolTest.java @@ -0,0 +1,27 @@ +package com.acgist.taoyao.signal.protocol; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.acgist.taoyao.main.TaoyaoApplication; +import com.acgist.taoyao.signal.protocol.platform.ScriptProtocol; +import com.acgist.taoyao.test.annotation.TaoyaoTest; + +@TaoyaoTest(classes = TaoyaoApplication.class) +class ScriptProtocolTest { + + @Autowired + private ScriptProtocol scriptProtocol; + + @Test + void testScript() { + assertDoesNotThrow(() -> { + this.scriptProtocol.execute(null, Map.of("script", "netstat -ano"), null, null); + }); + } + +} diff --git a/taoyao-server/src/test/java/com/acgist/taoyao/signal/protocol/ShutdownProtocolTest.java b/taoyao-server/src/test/java/com/acgist/taoyao/signal/protocol/ShutdownProtocolTest.java new file mode 100644 index 0000000..a300ab6 --- /dev/null +++ b/taoyao-server/src/test/java/com/acgist/taoyao/signal/protocol/ShutdownProtocolTest.java @@ -0,0 +1,25 @@ +package com.acgist.taoyao.signal.protocol; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.acgist.taoyao.main.TaoyaoApplication; +import com.acgist.taoyao.signal.protocol.platform.ShutdownProtocol; +import com.acgist.taoyao.test.annotation.TaoyaoTest; + +@TaoyaoTest(classes = TaoyaoApplication.class) +class ShutdownProtocolTest { + + @Autowired + private ShutdownProtocol shutdownProtocol; + + @Test + void testShutdown() { + assertDoesNotThrow(() -> { + this.shutdownProtocol.execute("taoyao", null, null); + }); + } + +} diff --git a/taoyao-signal/README.md b/taoyao-signal/README.md index 9519294..35cef2d 100644 --- a/taoyao-signal/README.md +++ b/taoyao-signal/README.md @@ -1,6 +1,6 @@ # 信令 -## 格式 +## 信令 ``` { @@ -13,37 +13,179 @@ "code": "响应编码", "message": "响应描述", "body": { - // 信令参数 + // 信令主体 } } ``` -## 系统信令(1000~1999|9999) +## 平台信令(1000~1999) -### 心跳信令(1000) +### 关闭服务信令(1000) + +关闭信令服务 ``` {} ``` -### 异常信令(9999) +### 执行命令信令(1001) -## 设备信令(2000~2999) - -### 注册信令(2000) +执行系统命令 ``` { -"username": "username", -"password": "password" + "script": "命令" +} +``` + +### 异常信令(1999) + +``` +{} +``` + +## 终端信令(2000~2999) + +### 注册信令(2000) + +终端注册:响应、广播上线通知 + +``` +{ + "username": "信令授权用户", + "password": "信令授权密码", + "ip": "IP地址", + "mac": "MAC地址", + "signal": "信号强度", + "battery": "电池电量" } ``` ### 关闭信令(2001) +关闭终端(注销):广播下线通知、释放所有连接 + +``` +{} +``` + ### 上线信令(2002) +通知终端上线 + +``` +{ + "sn": "终端标识" +} +``` + ### 下线信令(2003) -## 房间信令(3000~3999) +通知终端下线 +``` +{ + "sn": "终端标识" +} +``` + +### 下发配置信令(2004) + +### 心跳信令(2005) + +心跳:响应 + +``` +{ + "signal": "信号强度", + "battery": "电池电量" +} +``` + +### 终端列表信令(2006) + +返回所有终端状态列表 + +``` +{} +``` + +### 终端状态信令(2007) + +返回指定终端状态(如果没有指定终端标识默认查询自己) + +``` +{ + "sn": "终端标识" +} +``` + +### 单播信令(2008) + +发送到指定的终端:删除`to`字段 + +``` +{ + "to": "接收终端标识", + // 主体信息 +} +``` + +### 广播信令(2009) + +发送到所有的终端:排除自己 + +``` +{ + // 主体信息 +} +``` + +## 直播信令(3000~3999) + +``` +创建会议 -> 邀请终端|踢出终端|加入会议|离开会议 -> 光比会议 +``` + +### 开启直播信令(3000) + +### 关闭直播信令(3001) + +### 直播终端列表信令(3002) + +## 会议信令(4000~4999) + +### 创建会议信令(4000) + +### 关闭会议信令(4001) + +释放资源、广播广播 + +### 进入会议信令(4002) + +广播 + +### 离开会议信令(4003) + +广播 + +### 邀请终端信令(4004) + +邀请终端进入会议,终端确认进入发送进入会议信令。 + +### 踢出终端信令(4005) + +广播 + +### 会议终端列表信令(4006) + +## 媒体信令(5000~5999) + +|发布|控制终端推流(服务端拉流)||| +|取消发布|控制终端暂停推流(服务端取消拉流)||| +|订阅|订阅终端媒体流(终端拉流)||| +|取消订阅|取消订阅终端媒体流(终端取消拉流)||| +|暂停媒体流|暂停终端媒体流分流(不关媒体流通道)||| +|恢复媒体流|恢复终端媒体流分流(不关媒体流通道)||| +|开启录像|||| +|关闭录像|||| \ No newline at end of file diff --git a/taoyao-signal/pom.xml b/taoyao-signal/pom.xml index 5965627..49d3adb 100644 --- a/taoyao-signal/pom.xml +++ b/taoyao-signal/pom.xml @@ -19,7 +19,7 @@ com.acgist - taoyao-media + taoyao-boot org.springframework.boot diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSession.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSession.java similarity index 95% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSession.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSession.java index 915185d..faecb9a 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSession.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSession.java @@ -1,11 +1,11 @@ -package com.acgist.taoyao.signal.session; +package com.acgist.taoyao.signal.client; import com.acgist.taoyao.boot.model.Message; import com.acgist.taoyao.signal.media.ClientMediaPublisher; import com.acgist.taoyao.signal.media.ClientMediaSubscriber; /** - * 会话 + * 终端会话 * * @author acgist * @@ -17,7 +17,7 @@ public interface ClientSession extends AutoCloseable { * @return 终端标识 */ String sn(); - + /** * @return 终端状态 */ diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionAdapter.java similarity index 93% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionAdapter.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionAdapter.java index 5c66432..fa485c4 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionAdapter.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionAdapter.java @@ -1,4 +1,4 @@ -package com.acgist.taoyao.signal.session; +package com.acgist.taoyao.signal.client; import org.apache.commons.lang3.StringUtils; @@ -103,12 +103,7 @@ public abstract class ClientSessionAdapter implements C @Override public void close() throws Exception { - try { - this.instance.close(); - } finally { - // TODO:退出房间 - // TODO:退出帐号 - } + this.instance.close(); } /** diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionManager.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionManager.java similarity index 74% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionManager.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionManager.java index fc103f9..9916d25 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionManager.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionManager.java @@ -1,14 +1,17 @@ -package com.acgist.taoyao.signal.session; +package com.acgist.taoyao.signal.client; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import com.acgist.taoyao.boot.config.TaoyaoProperties; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.event.client.CloseEvent; import lombok.extern.slf4j.Slf4j; @@ -21,6 +24,8 @@ import lombok.extern.slf4j.Slf4j; @Service public class ClientSessionManager { + @Autowired + private ApplicationContext context; @Autowired private TaoyaoProperties taoyaoProperties; @@ -91,6 +96,32 @@ public class ClientSessionManager { }); } + /** + * @param sn 终端标识 + * + * @return 终端会话 + */ + public ClientSession session(String sn) { + return this.sessions.stream() + .filter(v -> StringUtils.equals(sn, v.sn())) + .findFirst() + .orElse(null); + } + + /** + * @return 所有终端会话 + */ + public List sessions() { + return this.sessions; + } + + /** + * @return 所有终端状态 + */ + public List status() { + return this.sessions().stream().map(ClientSession::status).toList(); + } + /** * 关闭会话 * @@ -101,13 +132,17 @@ public class ClientSessionManager { try { if(session != null) { session.close(); + } else { + instance.close(); } - instance.close(); } catch (Exception e) { log.error("关闭会话异常", e); } finally { if(session != null) { + // 移除管理 this.sessions.remove(session); + // 关闭事件 + this.context.publishEvent(new CloseEvent(null, session)); } } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionStatus.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionStatus.java similarity index 90% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionStatus.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionStatus.java index 8740e01..8a35ea3 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionStatus.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/ClientSessionStatus.java @@ -1,4 +1,4 @@ -package com.acgist.taoyao.signal.session; +package com.acgist.taoyao.signal.client; import lombok.Getter; import lombok.Setter; diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSession.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/socket/SocketSession.java similarity index 84% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSession.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/socket/SocketSession.java index 046402d..5ade63f 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSession.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/socket/SocketSession.java @@ -1,10 +1,10 @@ -package com.acgist.taoyao.signal.session.socket; +package com.acgist.taoyao.signal.client.socket; import java.io.IOException; import java.net.Socket; import com.acgist.taoyao.boot.model.Message; -import com.acgist.taoyao.signal.session.ClientSessionAdapter; +import com.acgist.taoyao.signal.client.ClientSessionAdapter; import lombok.Getter; import lombok.Setter; diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSignal.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/socket/SocketSignal.java similarity index 61% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSignal.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/socket/SocketSignal.java index 02f40d2..10e638a 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSignal.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/socket/SocketSignal.java @@ -1,4 +1,4 @@ -package com.acgist.taoyao.signal.session.socket; +package com.acgist.taoyao.signal.client.socket; /** * Socket信令 diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/websocket/WebSocketSession.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/websocket/WebSocketSession.java similarity index 85% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/websocket/WebSocketSession.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/websocket/WebSocketSession.java index 7dd2ddf..adbcb00 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/websocket/WebSocketSession.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/websocket/WebSocketSession.java @@ -1,9 +1,9 @@ -package com.acgist.taoyao.signal.session.websocket; +package com.acgist.taoyao.signal.client.websocket; import javax.websocket.Session; import com.acgist.taoyao.boot.model.Message; -import com.acgist.taoyao.signal.session.ClientSessionAdapter; +import com.acgist.taoyao.signal.client.ClientSessionAdapter; import lombok.Getter; import lombok.Setter; diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/websocket/WebSocketSignal.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/websocket/WebSocketSignal.java similarity index 93% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/websocket/WebSocketSignal.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/websocket/WebSocketSignal.java index 81b8f9a..edff458 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/websocket/WebSocketSignal.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/client/websocket/WebSocketSignal.java @@ -1,4 +1,4 @@ -package com.acgist.taoyao.signal.session.websocket; +package com.acgist.taoyao.signal.client.websocket; import javax.websocket.OnClose; import javax.websocket.OnError; @@ -10,9 +10,9 @@ import javax.websocket.server.ServerEndpoint; import org.springframework.beans.factory.annotation.Autowired; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSessionManager; import com.acgist.taoyao.signal.protocol.ProtocolManager; -import com.acgist.taoyao.signal.protocol.system.ErrorProtocol; -import com.acgist.taoyao.signal.session.ClientSessionManager; +import com.acgist.taoyao.signal.protocol.platform.ErrorProtocol; import lombok.extern.slf4j.Slf4j; diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java index 24bfb65..cf9b19a 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java @@ -6,7 +6,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter; -import com.acgist.taoyao.signal.session.websocket.WebSocketSignal; +import com.acgist.taoyao.signal.client.websocket.WebSocketSignal; /** * 信令配置 diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/controller/ClientController.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/controller/ClientController.java new file mode 100644 index 0000000..609867c --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/controller/ClientController.java @@ -0,0 +1,33 @@ +package com.acgist.taoyao.signal.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSessionManager; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +/** + * 终端 + * + * @author acgist + */ +@Tag(name = "终端", description = "终端管理") +@RestController +@RequestMapping("/client") +public class ClientController { + + @Autowired + private ClientSessionManager clientSessionManager; + + @Operation(summary = "终端列表", description = "终端列表") + @GetMapping("/list") + public Message list() { + return Message.success(this.clientSessionManager.status()); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/ApplicationEventAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/ApplicationEventAdapter.java new file mode 100644 index 0000000..390b681 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/ApplicationEventAdapter.java @@ -0,0 +1,48 @@ +package com.acgist.taoyao.signal.event; + +import java.util.Map; + +import org.springframework.context.ApplicationEvent; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; + +import lombok.Getter; +import lombok.Setter; + +/** + * 事件适配器 + * + * @author acgist + */ +@Getter +@Setter +public abstract class ApplicationEventAdapter extends ApplicationEvent { + + private static final long serialVersionUID = 1L; + + /** + * 主体 + */ + private final Map body; + /** + * 消息 + */ + private final Message message; + /** + * 会话 + */ + private final ClientSession session; + + public ApplicationEventAdapter(Message message, ClientSession session) { + this(null, message, session); + } + + public ApplicationEventAdapter(Map body, Message message, ClientSession session) { + super(session); + this.body = body; + this.message = message; + this.session = session; + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/CloseEvent.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/CloseEvent.java new file mode 100644 index 0000000..6626361 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/CloseEvent.java @@ -0,0 +1,25 @@ +package com.acgist.taoyao.signal.event.client; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.event.ApplicationEventAdapter; + +import lombok.Getter; +import lombok.Setter; + +/** + * 关闭事件 + * + * @author acgist + */ +@Getter +@Setter +public class CloseEvent extends ApplicationEventAdapter { + + private static final long serialVersionUID = 1L; + + public CloseEvent(Message message, ClientSession session) { + super(message, session); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/RegisterEvent.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/RegisterEvent.java index e3abd2f..2ee7136 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/RegisterEvent.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/client/RegisterEvent.java @@ -2,37 +2,26 @@ package com.acgist.taoyao.signal.event.client; import java.util.Map; -import org.springframework.context.ApplicationEvent; - -import com.acgist.taoyao.signal.session.ClientSession; +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.event.ApplicationEventAdapter; import lombok.Getter; import lombok.Setter; /** - * 终端注册事件 + * 注册事件 * * @author acgist */ @Getter @Setter -public class RegisterEvent extends ApplicationEvent { - +public class RegisterEvent extends ApplicationEventAdapter { + private static final long serialVersionUID = 1L; - - /** - * 会话 - */ - private ClientSession session; - /** - * 参数 - */ - private Map data; - - public RegisterEvent(ClientSession session, Map data) { - super(session); - this.session = session; - this.data = data; + + public RegisterEvent(Map body, Message message, ClientSession session) { + super(body, message, session); } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/platform/ScriptEvent.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/platform/ScriptEvent.java new file mode 100644 index 0000000..0c5f448 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/event/platform/ScriptEvent.java @@ -0,0 +1,22 @@ +package com.acgist.taoyao.signal.event.platform; + +import java.util.Map; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.event.ApplicationEventAdapter; + +/** + * 执行命令事件 + * + * @author acgist + */ +public class ScriptEvent extends ApplicationEventAdapter { + + private static final long serialVersionUID = 1L; + + public ScriptEvent(Map body, Message message, ClientSession session) { + super(body, message, session); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/ApplicationListenerAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/ApplicationListenerAdapter.java index fc5002f..6537c64 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/ApplicationListenerAdapter.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/ApplicationListenerAdapter.java @@ -1,19 +1,19 @@ package com.acgist.taoyao.signal.listener; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; -import com.acgist.taoyao.signal.session.ClientSessionManager; +import com.acgist.taoyao.signal.client.ClientSessionManager; +import com.acgist.taoyao.signal.event.ApplicationEventAdapter; /** - * 事件监听 + * 事件监听适配器 * * @param 事件泛型 * * @author acgist */ -public abstract class ApplicationListenerAdapter implements ApplicationListener { +public abstract class ApplicationListenerAdapter implements ApplicationListener { @Autowired protected ClientSessionManager clientSessionManager; diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/CloseListener.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/CloseListener.java new file mode 100644 index 0000000..f8311f8 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/CloseListener.java @@ -0,0 +1,50 @@ +package com.acgist.taoyao.signal.listener.client; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.event.client.CloseEvent; +import com.acgist.taoyao.signal.listener.ApplicationListenerAdapter; +import com.acgist.taoyao.signal.protocol.client.OfflineProtocol; + +import lombok.extern.slf4j.Slf4j; + +/** + * 关闭监听 + * + * @author acgist + */ +@Slf4j +@Component +public class CloseListener extends ApplicationListenerAdapter { + + @Autowired + private OfflineProtocol offlineProtocol; + + @Override + public void onApplicationEvent(CloseEvent event) { + final ClientSession session = event.getSession(); + final String sn = session.sn(); + if(StringUtils.isEmpty(sn)) { + // 没有授权终端 + return; + } + log.info("关闭终端:{}", sn); + // 广播下线事件 + final Message message = this.offlineProtocol.build( + Map.of("sn", sn) + ); + this.clientSessionManager.broadcast(sn, message); + // TODO:释放连接 + // TODO:释放房间 + // TODO:退出房间 + // TODO:退出帐号 + // TODO:注意释放:是否考虑没有message(非正常的关闭)不要立即释放 + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/RegisterListener.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/RegisterListener.java index 0d906fe..be98001 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/RegisterListener.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/client/RegisterListener.java @@ -7,14 +7,14 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionStatus; import com.acgist.taoyao.signal.event.client.RegisterEvent; import com.acgist.taoyao.signal.listener.ApplicationListenerAdapter; import com.acgist.taoyao.signal.protocol.client.OnlineProtocol; -import com.acgist.taoyao.signal.session.ClientSession; -import com.acgist.taoyao.signal.session.ClientSessionStatus; /** - * 终端注册监听 + * 注册监听 * * @author acgist */ @@ -31,16 +31,19 @@ public class RegisterListener extends ApplicationListenerAdapter if (!session.authorized()) { return; } - final Message message = this.onlineProtocol.build(); - message.setBody(Map.of("sn", session.sn())); + // 广播上线事件 + final Message message = this.onlineProtocol.build( + Map.of("sn", session.sn()) + ); this.clientSessionManager.broadcast(session.sn(), message); - final Map data = event.getData(); + // 修改终端状态 + final Map body = event.getBody(); final ClientSessionStatus status = session.status(); status.setSn(session.sn()); - status.setIp((String) data.get("ip")); - status.setMac((String) data.get("mac")); - status.setSignal((Integer) data.get("signal")); - status.setBattery((Integer) data.get("battery")); + status.setIp((String) body.get("ip")); + status.setMac((String) body.get("mac")); + status.setSignal((Integer) body.get("signal")); + status.setBattery((Integer) body.get("battery")); } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/platform/ScriptListener.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/platform/ScriptListener.java new file mode 100644 index 0000000..6040a1b --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/listener/platform/ScriptListener.java @@ -0,0 +1,66 @@ +package com.acgist.taoyao.signal.listener.platform; + +import java.io.InputStream; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.signal.event.platform.ScriptEvent; +import com.acgist.taoyao.signal.listener.ApplicationListenerAdapter; + +import lombok.extern.slf4j.Slf4j; + +/** + * 执行命令监听 + * + * @author acgist + */ +@Slf4j +@Component +public class ScriptListener extends ApplicationListenerAdapter { + + @Async + @Override + public void onApplicationEvent(ScriptEvent event) { + final String script = (String) event.getBody().get("script"); + log.debug("执行命令:{}", script); + this.execute(script); + } + + /** + * 执行命令 + * + * @param script 命令 + */ + private void execute(String script) { + if(StringUtils.isEmpty(script)) { + log.warn("执行命令失败:{}", script); + return; + } + Process process = null; + try { + process = Runtime.getRuntime().exec(script); + try( + final InputStream input = process.getInputStream(); + final InputStream error = process.getErrorStream(); + ) { + log.info(""" + 执行命令:{} + 执行结果:{} + 失败结果:{} + """, script, new String(input.readAllBytes()), new String(error.readAllBytes())); + } catch (Exception e) { + log.error("命令执行异常:{}", script, e); + } + } catch (Exception e) { + log.error("执行命令异常:{}", script, e); + } finally { + if(process != null) { + process.destroy(); +// process.destroyForcibly(); + } + } + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/Protocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/Protocol.java index d4ec31a..6400418 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/Protocol.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/Protocol.java @@ -1,18 +1,18 @@ package com.acgist.taoyao.signal.protocol; -import org.springframework.context.ApplicationEvent; - import com.acgist.taoyao.boot.model.Message; -import com.acgist.taoyao.signal.session.ClientSession; +import com.acgist.taoyao.boot.model.MessageCode; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.event.ApplicationEventAdapter; /** - * 信令协议 + * 信令 * - * 1000~1999:系统信令(关机) - * 2000~2999:终端信令(注册、注销、终端列表) - * 3000~3999:直播信令 - * 4000~4999:会议信令 - * 9999:信令异常 + * 1000~1999:平台信令 + * 2000~2999:终端信令 + * 3000~3999:会议信令 + * 4000~4999:直播信令 + * 5000~5999:媒体信令 * * @author acgist */ @@ -21,7 +21,12 @@ public interface Protocol { /** * @return 信令协议标识 */ - Integer protocol(); + Integer pid(); + + /** + * @return 信令名称 + */ + String name(); /** * 处理信令消息 @@ -29,10 +34,17 @@ public interface Protocol { * @param sn 终端标识 * @param message 信令消息 * @param session 会话 - * - * @return 事件 */ - ApplicationEvent execute(String sn, Message message, ClientSession session); + void execute(String sn, Message message, ClientSession session); + + /** + * 发布事件 + * + * @param 事件类型 + * + * @param event 事件 + */ + void publishEvent(E event); /** * 创建信令消息 @@ -41,4 +53,46 @@ public interface Protocol { */ Message build(); + /** + * 创建信令消息 + * + * @param body 请求响应主体 + * + * @return 信令消息 + */ + Message build(Object body); + + /** + * 创建信令消息 + * + * @param code 响应编码 + * @param body 请求响应主体 + * + * @return 信令消息 + */ + Message build(MessageCode code, Object body); + + /** + * 创建信令消息 + * + * @param code 响应编码 + * @param message 响应描述 + * @param body 请求响应主体 + * + * @return 信令消息 + */ + Message build(MessageCode code, String message, Object body); + + /** + * 创建信令消息 + * + * @param id 请求响应标识 + * @param code 响应编码 + * @param message 响应描述 + * @param body 请求响应主体 + * + * @return 信令消息 + */ + Message build(String id, MessageCode code, String message, Object body); + } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolAdapter.java index 3b569bf..f4524cd 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolAdapter.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolAdapter.java @@ -1,49 +1,102 @@ package com.acgist.taoyao.signal.protocol; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import com.acgist.taoyao.boot.config.TaoyaoProperties; import com.acgist.taoyao.boot.model.Header; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.boot.model.MessageCode; import com.acgist.taoyao.boot.service.IdService; +import com.acgist.taoyao.signal.event.ApplicationEventAdapter; /** - * 信令协议适配器 + * 信令适配器 * * @author acgist */ public abstract class ProtocolAdapter implements Protocol { @Autowired - private IdService idService; + protected IdService idService; + @Autowired + protected ApplicationContext context; @Autowired protected TaoyaoProperties taoyaoProperties; /** - * 信令协议标识 + * 信令标识 */ - protected final Integer protocol; + protected final Integer pid; + /** + * 信令名称 + */ + protected final String name; - protected ProtocolAdapter(Integer protocol) { - this.protocol = protocol; + protected ProtocolAdapter(Integer pid, String name) { + this.pid = pid; + this.name = name; } @Override - public Integer protocol() { - return this.protocol; + public Integer pid() { + return this.pid; + } + + @Override + public String name() { + return this.name; + } + + @Override + public void publishEvent(E event) { + this.context.publishEvent(event); } @Override public Message build() { + return this.build(null, null, null, null); + } + + @Override + public Message build(Object body) { + return this.build(null, null, null, body); + } + + @Override + public Message build(MessageCode code, Object body) { + return this.build(null, code, null, body); + } + + @Override + public Message build(MessageCode code, String message, Object body) { + return this.build(null, code, message, body); + } + + @Override + public Message build(String id, MessageCode code, String message, Object body) { + if(StringUtils.isEmpty(id)) { + id = this.taoyaoProperties.getVersion(); + } final Header header = Header.builder() .v(this.taoyaoProperties.getVersion()) - .id(this.idService.buildIdToString()) - .pid(this.protocol) + .id(id) + .pid(this.pid) .build(); - final Message message = Message.builder() + final Message build = Message.builder() .header(header) .build(); - return message; + if(code != null) { + build.setCode(code); + } + if(StringUtils.isNotEmpty(message)) { + build.setMessage(message); + } + if(body != null) { + build.setBody(body); + } + return build; } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolBodyMapAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolBodyMapAdapter.java deleted file mode 100644 index 22fb3e6..0000000 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolBodyMapAdapter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.acgist.taoyao.signal.protocol; - -import java.util.Map; - -import org.springframework.context.ApplicationEvent; - -import com.acgist.taoyao.boot.model.Message; -import com.acgist.taoyao.boot.model.MessageCodeException; -import com.acgist.taoyao.signal.session.ClientSession; - -/** - * 信令协议Map主体适配器 - * - * @author acgist - */ -public abstract class ProtocolBodyMapAdapter extends ProtocolAdapter { - - protected ProtocolBodyMapAdapter(Integer protocol) { - super(protocol); - } - - @Override - public ApplicationEvent execute(String sn, Message message, ClientSession session) { - final Object body = message.getBody(); - if(body instanceof Map map) { - return this.execute(sn, map, message, session); - } else { - throw MessageCodeException.of("信令主体类型错误:" + message); - } - } - - /** - * 处理信令消息 - * - * @param sn 终端标识 - * @param body 消息主体 - * @param message 信令消息 - * @param session 会话 - * - * @return 事件 - */ - public abstract ApplicationEvent execute(String sn, Map body, Message message, ClientSession session); - -} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolBodyObjectAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolJavaAdapter.java similarity index 59% rename from taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolBodyObjectAdapter.java rename to taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolJavaAdapter.java index c5388e5..a6c394f 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolBodyObjectAdapter.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolJavaAdapter.java @@ -3,38 +3,37 @@ package com.acgist.taoyao.signal.protocol; import java.util.Map; import org.springframework.cglib.beans.BeanMap; -import org.springframework.context.ApplicationEvent; import com.acgist.taoyao.boot.model.Message; import com.acgist.taoyao.boot.model.MessageCodeException; import com.acgist.taoyao.boot.utils.BeanUtils; -import com.acgist.taoyao.signal.session.ClientSession; +import com.acgist.taoyao.signal.client.ClientSession; /** - * 信令协议对象主体适配器 + * Java主体信令适配器 * * @author acgist */ -public abstract class ProtocolBodyObjectAdapter extends ProtocolAdapter { +public abstract class ProtocolJavaAdapter extends ProtocolAdapter { /** * 对象类型 */ private final Class clazz; - protected ProtocolBodyObjectAdapter(Integer protocol, Class clazz) { - super(protocol); + protected ProtocolJavaAdapter(Integer pid, String name, Class clazz) { + super(pid, name); this.clazz = clazz; } @Override - public ApplicationEvent execute(String sn, Message message, ClientSession session) { + public void execute(String sn, Message message, ClientSession session) { final Object body = message.getBody(); if(body instanceof Map map) { final T t = BeanUtils.newInstance(this.clazz); final BeanMap beanMap = BeanMap.create(t); beanMap.putAll(map); - return this.execute(sn, t, message, session); + this.execute(sn, t, message, session); } else { throw MessageCodeException.of("信令主体类型错误:" + message); } @@ -47,9 +46,7 @@ public abstract class ProtocolBodyObjectAdapter extends ProtocolAdapter { * @param body 消息主体 * @param message 信令消息 * @param session 会话 - * - * @return 事件 */ - public abstract ApplicationEvent execute(String sn, T body, Message message, ClientSession session); + public abstract void execute(String sn, T body, Message message, ClientSession session); } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolManager.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolManager.java index 4d03193..6f88e0e 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolManager.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolManager.java @@ -5,19 +5,19 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PostConstruct; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; import org.springframework.stereotype.Service; import com.acgist.taoyao.boot.model.Header; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.boot.model.MessageCode; import com.acgist.taoyao.boot.model.MessageCodeException; import com.acgist.taoyao.boot.utils.JSONUtils; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionManager; import com.acgist.taoyao.signal.protocol.client.RegisterProtocol; -import com.acgist.taoyao.signal.session.ClientSession; -import com.acgist.taoyao.signal.session.ClientSessionManager; +import com.acgist.taoyao.signal.protocol.platform.ErrorProtocol; import lombok.extern.slf4j.Slf4j; @@ -38,18 +38,25 @@ public class ProtocolManager { @Autowired private ApplicationContext context; @Autowired + private ErrorProtocol errorProtocol; + @Autowired private ClientSessionManager clientSessionManager; @PostConstruct public void init() { final Map map = this.context.getBeansOfType(Protocol.class); - map.forEach((k, v) -> { - final Integer protocol = v.protocol(); - if(this.protocolMapping.containsKey(protocol)) { - throw MessageCodeException.of("存在重复信令协议:" + protocol); + map.entrySet().stream() + .sorted((a, z) -> Integer.compare(a.getValue().pid(), z.getValue().pid())) + .forEach(e -> { + final String k = e.getKey(); + final Protocol v = e.getValue(); + final Integer pid = v.pid(); + final String name = v.name(); + if(this.protocolMapping.containsKey(pid)) { + throw MessageCodeException.of("存在重复信令协议:" + pid); } - log.info("注册信令协议:{}-{}", protocol, k); - this.protocolMapping.put(protocol, v); + log.info("注册信令协议:{}-{}-{}", pid, name, k); + this.protocolMapping.put(pid, v); }); } @@ -61,38 +68,39 @@ public class ProtocolManager { */ public void execute(String message, AutoCloseable instance) { log.debug("执行信令消息:{}", message); - if(StringUtils.isEmpty(message)) { - log.warn("消息为空:{}", message); + // 验证请求 + final Message value = JSONUtils.toJava(message, Message.class); + if(value == null) { + log.warn("消息格式错误(解析失败):{}", message); return; } - final Message value = JSONUtils.toJava(message, Message.class); final Header header = value.getHeader(); if(header == null) { log.warn("消息格式错误(没有头部):{}", message); return; } + final String id = header.getId(); final String sn = header.getSn(); final Integer pid = header.getPid(); - if(sn == null || pid == null) { - log.warn("消息格式错误(没有SN或者PID):{}", message); + if(id == null || sn == null || pid == null) { + log.warn("消息格式错误(id|sn|pid):{}", message); return; } + // 设置缓存ID + this.errorProtocol.set(id); + // 开始处理协议 final Protocol protocol = this.protocolMapping.get(pid); if(protocol == null) { log.warn("不支持的信令协议:{}", message); return; } - ApplicationEvent event = null; final ClientSession session = this.clientSessionManager.session(instance); - if(session != null && protocol instanceof RegisterProtocol) { - event = protocol.execute(sn, value, session); - } else if(session != null && session.authorized()) { - event = protocol.execute(sn, value, session); + if(protocol instanceof RegisterProtocol) { + protocol.execute(sn, value, session); + } else if(session.authorized() && sn.equals(session.sn())) { + protocol.execute(sn, value, session); } else { - log.warn("会话没有权限:{}", message); - } - if(event != null) { - this.context.publishEvent(event); + session.push(this.errorProtocol.build(MessageCode.CODE_3401, "终端会话没有授权")); } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolMapAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolMapAdapter.java new file mode 100644 index 0000000..27fb94e --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/ProtocolMapAdapter.java @@ -0,0 +1,40 @@ +package com.acgist.taoyao.signal.protocol; + +import java.util.Map; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.boot.model.MessageCodeException; +import com.acgist.taoyao.signal.client.ClientSession; + +/** + * Map主体信令适配器 + * + * @author acgist + */ +public abstract class ProtocolMapAdapter extends ProtocolAdapter { + + protected ProtocolMapAdapter(Integer pid, String name) { + super(pid, name); + } + + @Override + public void execute(String sn, Message message, ClientSession session) { + final Object body = message.getBody(); + if(body instanceof Map map) { + this.execute(sn, map, message, session); + } else { + throw MessageCodeException.of("信令主体类型错误:" + message); + } + } + + /** + * 处理信令消息 + * + * @param sn 终端标识 + * @param body 消息主体 + * @param message 信令消息 + * @param session 会话 + */ + public abstract void execute(String sn, Map body, Message message, ClientSession session); + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/BroadcastProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/BroadcastProtocol.java new file mode 100644 index 0000000..8444468 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/BroadcastProtocol.java @@ -0,0 +1,36 @@ +package com.acgist.taoyao.signal.protocol.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionManager; +import com.acgist.taoyao.signal.protocol.ProtocolAdapter; + +/** + * 广播信令 + * + * @author acgist + */ +@Component +public class BroadcastProtocol extends ProtocolAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 2009; + + @Autowired + private ClientSessionManager clientSessionManager; + + public BroadcastProtocol() { + super(PID, "广播信令"); + } + + @Override + public void execute(String sn, Message message, ClientSession session) { + this.clientSessionManager.broadcast(sn, message); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/CloseProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/CloseProtocol.java index 7899054..545dc28 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/CloseProtocol.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/CloseProtocol.java @@ -1,17 +1,19 @@ package com.acgist.taoyao.signal.protocol.client; -import org.springframework.context.ApplicationEvent; import org.springframework.stereotype.Component; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; import com.acgist.taoyao.signal.protocol.ProtocolAdapter; -import com.acgist.taoyao.signal.session.ClientSession; + +import lombok.extern.slf4j.Slf4j; /** - * 关闭信令协议 + * 关闭信令 * * @author acgist */ +@Slf4j @Component public class CloseProtocol extends ProtocolAdapter { @@ -21,13 +23,18 @@ public class CloseProtocol extends ProtocolAdapter { public static final Integer PID = 2001; public CloseProtocol() { - super(PID); + super(PID, "关闭信令"); } @Override - public ApplicationEvent execute(String sn, Message message, ClientSession session) { - // TODO - return null; + public void execute(String sn, Message message, ClientSession session) { + // 关闭不会响应 + try { + session.close(); + } catch (Exception e) { + log.error("关闭终端异常", e); + } + // 不用发布事件:关闭连接后会发布事件 } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/HeartbeatProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/HeartbeatProtocol.java new file mode 100644 index 0000000..19053c2 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/HeartbeatProtocol.java @@ -0,0 +1,39 @@ +package com.acgist.taoyao.signal.protocol.client; + +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionStatus; +import com.acgist.taoyao.signal.protocol.ProtocolMapAdapter; + +/** + * 心跳信令 + * + * @author acgist + */ +@Component +public class HeartbeatProtocol extends ProtocolMapAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 2005; + + public HeartbeatProtocol() { + super(PID, "心跳信令"); + } + + @Override + public void execute(String sn, Map body, Message message, ClientSession session) { + // 回应心跳 + session.push(message.cloneWidthoutBody()); + // 设置状态 + final ClientSessionStatus status = session.status(); + status.setSignal((Integer) body.get("signal")); + status.setBattery((Integer) body.get("battery")); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/ListProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/ListProtocol.java new file mode 100644 index 0000000..0233750 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/ListProtocol.java @@ -0,0 +1,37 @@ +package com.acgist.taoyao.signal.protocol.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionManager; +import com.acgist.taoyao.signal.protocol.ProtocolAdapter; + +/** + * 终端列表信令 + * + * @author acgist + */ +@Component +public class ListProtocol extends ProtocolAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 2006; + + @Autowired + private ClientSessionManager clientSessionManager; + + public ListProtocol() { + super(PID, "终端列表信令"); + } + + @Override + public void execute(String sn, Message message, ClientSession session) { + message.setBody(this.clientSessionManager.status()); + session.push(message); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OfflineProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OfflineProtocol.java index 16ab85c..adba5d4 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OfflineProtocol.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OfflineProtocol.java @@ -1,10 +1,31 @@ package com.acgist.taoyao.signal.protocol.client; -public class OfflineProtocol { +import org.springframework.stereotype.Component; +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.protocol.ProtocolAdapter; + +/** + * 终端下线信令 + * + * @author acgist + */ +@Component +public class OfflineProtocol extends ProtocolAdapter { + /** * 信令协议标识 */ public static final Integer PID = 2003; + + public OfflineProtocol() { + super(PID, "终端下线信令"); + } + + @Override + public void execute(String sn, Message message, ClientSession session) { + // 忽略 + } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OnlineProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OnlineProtocol.java index 0e911d0..8214788 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OnlineProtocol.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/OnlineProtocol.java @@ -1,14 +1,13 @@ package com.acgist.taoyao.signal.protocol.client; -import org.springframework.context.ApplicationEvent; import org.springframework.stereotype.Component; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; import com.acgist.taoyao.signal.protocol.ProtocolAdapter; -import com.acgist.taoyao.signal.session.ClientSession; /** - * 上线信令协议 + * 上线信令 * * @author acgist */ @@ -21,12 +20,12 @@ public class OnlineProtocol extends ProtocolAdapter { public static final Integer PID = 2002; public OnlineProtocol() { - super(PID); + super(PID, "上线信令"); } @Override - public ApplicationEvent execute(String sn, Message message, ClientSession session) { - return null; + public void execute(String sn, Message message, ClientSession session) { + // 忽略 } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/RegisterProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/RegisterProtocol.java index 3be60fb..60f8dca 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/RegisterProtocol.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/RegisterProtocol.java @@ -4,23 +4,22 @@ import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEvent; import org.springframework.stereotype.Component; import com.acgist.taoyao.boot.config.SecurityProperties; import com.acgist.taoyao.boot.model.Message; import com.acgist.taoyao.boot.model.MessageCode; +import com.acgist.taoyao.signal.client.ClientSession; import com.acgist.taoyao.signal.event.client.RegisterEvent; -import com.acgist.taoyao.signal.protocol.ProtocolBodyMapAdapter; -import com.acgist.taoyao.signal.session.ClientSession; +import com.acgist.taoyao.signal.protocol.ProtocolMapAdapter; /** - * 注册信令协议 + * 注册信令 * * @author acgist */ @Component -public class RegisterProtocol extends ProtocolBodyMapAdapter { +public class RegisterProtocol extends ProtocolMapAdapter { /** * 信令协议标识 @@ -31,14 +30,16 @@ public class RegisterProtocol extends ProtocolBodyMapAdapter { private SecurityProperties securityProperties; public RegisterProtocol() { - super(PID); + super(PID, "注册信令"); } @Override - public ApplicationEvent execute(String sn, Map body, Message message, ClientSession session) { + public void execute(String sn, Map body, Message message, ClientSession session) { final String username = (String) body.get("username"); final String password = (String) body.get("password"); + // 如果需要终端鉴权在此实现 if( + Boolean.FALSE.equals(this.securityProperties.getEnabled()) || StringUtils.equals(this.securityProperties.getUsername(), username) && StringUtils.equals(this.securityProperties.getPassword(), password) ) { @@ -47,8 +48,10 @@ public class RegisterProtocol extends ProtocolBodyMapAdapter { } else { message.setCode(MessageCode.CODE_3401); } - session.push(message); - return new RegisterEvent(session, body); + // 推送消息 + session.push(message.cloneWidthoutBody()); + // 发送事件 + this.publishEvent(new RegisterEvent(body, message, session)); } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/StatusProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/StatusProtocol.java new file mode 100644 index 0000000..43e8692 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/StatusProtocol.java @@ -0,0 +1,53 @@ +package com.acgist.taoyao.signal.protocol.client; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionManager; +import com.acgist.taoyao.signal.protocol.ProtocolMapAdapter; + +import lombok.extern.slf4j.Slf4j; + +/** + * 终端状态信令 + * + * @author acgist + */ +@Slf4j +@Component +public class StatusProtocol extends ProtocolMapAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 2007; + + @Autowired + private ClientSessionManager clientSessionManager; + + public StatusProtocol() { + super(PID, "终端状态信令"); + } + + @Override + public void execute(String sn, Map body, Message message, ClientSession session) { + String querySn = (String) body.get("sn"); + // 如果没有指定终端标识默认查询自己 + if(StringUtils.isEmpty(querySn)) { + querySn = sn; + } + final ClientSession clientSession = this.clientSessionManager.session(querySn); + if(clientSession != null) { + message.setBody(clientSession.status()); + session.push(message); + } else { + log.warn("终端无效:{}", querySn); + } + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/UnicastProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/UnicastProtocol.java new file mode 100644 index 0000000..64267f0 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/client/UnicastProtocol.java @@ -0,0 +1,47 @@ +package com.acgist.taoyao.signal.protocol.client; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.client.ClientSessionManager; +import com.acgist.taoyao.signal.protocol.ProtocolMapAdapter; + +import lombok.extern.slf4j.Slf4j; + +/** + * 单播信令 + * + * @author acgist + */ +@Slf4j +@Component +public class UnicastProtocol extends ProtocolMapAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 2008; + + @Autowired + private ClientSessionManager clientSessionManager; + + public UnicastProtocol() { + super(PID, "单播信令"); + } + + @Override + public void execute(String sn, Map body, Message message, ClientSession session) { + final String to = (String) body.remove("to"); + if(StringUtils.isNotEmpty(to)) { + this.clientSessionManager.unicast(to, message); + } else { + log.warn("单播消息没有接收终端标识:{}", to); + } + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ErrorProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ErrorProtocol.java new file mode 100644 index 0000000..6b8776c --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ErrorProtocol.java @@ -0,0 +1,56 @@ +package com.acgist.taoyao.signal.protocol.platform; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.boot.model.MessageCode; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.protocol.ProtocolAdapter; + +/** + * 异常信令 + * + * @author acgist + */ +@Component +public class ErrorProtocol extends ProtocolAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 1999; + + /** + * 请求ID缓存 + */ + private InheritableThreadLocal idLocal = new InheritableThreadLocal<>(); + + public ErrorProtocol() { + super(PID, "异常信令"); + } + + /** + * @param id 请求ID + */ + public void set(String id) { + this.idLocal.set(id); + } + + @Override + public void execute(String sn, Message message, ClientSession session) { + } + + @Override + public Message build(String id, MessageCode code, String message, Object body) { + final String oldId = this.idLocal.get(); + if(StringUtils.isEmpty(oldId)) { + id = this.idService.buildIdToString(); + } else { + id = oldId; + this.idLocal.remove(); + } + return super.build(id, code, message, body); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ScriptProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ScriptProtocol.java new file mode 100644 index 0000000..1c11342 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ScriptProtocol.java @@ -0,0 +1,34 @@ +package com.acgist.taoyao.signal.protocol.platform; + +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.event.platform.ScriptEvent; +import com.acgist.taoyao.signal.protocol.ProtocolMapAdapter; + +/** + * 执行命令信令 + * + * @author acgist + */ +@Component +public class ScriptProtocol extends ProtocolMapAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 1001; + + public ScriptProtocol() { + super(PID, "执行命令信令"); + } + + @Override + public void execute(String sn, Map body, Message message, ClientSession session) { + this.publishEvent(new ScriptEvent(body, message, session)); + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ShutdownProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ShutdownProtocol.java new file mode 100644 index 0000000..3bc4f15 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/platform/ShutdownProtocol.java @@ -0,0 +1,42 @@ +package com.acgist.taoyao.signal.protocol.platform; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.client.ClientSession; +import com.acgist.taoyao.signal.protocol.ProtocolAdapter; + +import lombok.extern.slf4j.Slf4j; + +/** + * 关闭服务信令 + * + * @author acgist + */ +@Slf4j +@Component +public class ShutdownProtocol extends ProtocolAdapter { + + /** + * 信令协议标识 + */ + public static final Integer PID = 1000; + + public ShutdownProtocol() { + super(PID, "关闭服务信令"); + } + + @Override + public void execute(String sn, Message message, ClientSession session) { + if(this.context instanceof ConfigurableApplicationContext context) { + log.info("关闭服务:{}", sn); + if(context.isActive()) { + context.close(); + } + } else { + log.info("关闭服务失败:{}", sn); + } + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/system/ErrorProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/system/ErrorProtocol.java deleted file mode 100644 index 6449219..0000000 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/system/ErrorProtocol.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.acgist.taoyao.signal.protocol.system; - -import org.springframework.context.ApplicationEvent; -import org.springframework.stereotype.Component; - -import com.acgist.taoyao.boot.model.Message; -import com.acgist.taoyao.signal.protocol.ProtocolAdapter; -import com.acgist.taoyao.signal.session.ClientSession; - -/** - * 异常信令协议 - * - * @author acgist - */ -@Component -public class ErrorProtocol extends ProtocolAdapter { - - /** - * 信令协议标识 - */ - public static final Integer PID = 9999; - - public ErrorProtocol() { - super(PID); - } - - @Override - public ApplicationEvent execute(String sn, Message message, ClientSession session) { - return null; - } - -} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/system/HeartbeatProtocol.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/system/HeartbeatProtocol.java deleted file mode 100644 index 0e52318..0000000 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/system/HeartbeatProtocol.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.acgist.taoyao.signal.protocol.system; - -import org.springframework.context.ApplicationEvent; -import org.springframework.stereotype.Component; - -import com.acgist.taoyao.boot.model.Message; -import com.acgist.taoyao.signal.protocol.ProtocolAdapter; -import com.acgist.taoyao.signal.session.ClientSession; - -/** - * 心跳信令协议 - * - * @author acgist - */ -@Component -public class HeartbeatProtocol extends ProtocolAdapter { - - /** - * 信令协议标识 - */ - public static final Integer PID = 1000; - - public HeartbeatProtocol() { - super(PID); - } - - @Override - public ApplicationEvent execute(String sn, Message message, ClientSession session) { - session.push(message); - return null; - } - -} diff --git a/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTestTestExecutionListener.java b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTestTestExecutionListener.java index 96d3667..fa9eb10 100644 --- a/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTestTestExecutionListener.java +++ b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTestTestExecutionListener.java @@ -22,6 +22,9 @@ public class CostedTestTestExecutionListener implements TestExecutionListener { @Override public void afterTestMethod(TestContext testContext) throws Exception { final CostedTest costedTest = testContext.getTestMethod().getDeclaredAnnotation(CostedTest.class); + if(costedTest == null) { + return; + } final int count = costedTest.count(); final int thread = costedTest.thread(); final long timeout = costedTest.timeout(); diff --git a/taoyao-webrtc/README.md b/taoyao-webrtc/README.md index 766668a..1a25a90 100644 --- a/taoyao-webrtc/README.md +++ b/taoyao-webrtc/README.md @@ -50,8 +50,3 @@ SDP只是一种信息格式的描述标准,不属于传输协议,但是可 |会话通道|SIP/SDP| |媒体通道|RTP/RTCP/SRTP/SRTCP| -## WebRTC资料 - -[GB28181](https://blog.csdn.net/jisuanji111111/article/details/121634199) -[WebRTC协议](http://www.manoner.com/post/音视频基础/WebRTC核心组件和协议栈/) -[WebRTC开源项目](https://blog.csdn.net/ababab12345/article/details/115585378) diff --git a/taoyao-webrtc/pom.xml b/taoyao-webrtc/pom.xml index 79dbf4c..830ce97 100644 --- a/taoyao-webrtc/pom.xml +++ b/taoyao-webrtc/pom.xml @@ -27,7 +27,7 @@ com.acgist - taoyao-boot + taoyao-signal