From 605e0fbbe7c43562e6396494a282af0a6f701606 Mon Sep 17 00:00:00 2001 From: acgist <289547414@qq.com> Date: Fri, 11 Nov 2022 19:28:02 +0800 Subject: [PATCH] =?UTF-8?q?[+]=20=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 72 +++++++------- pom.xml | 6 ++ .../boot/config/BootAutoConfiguration.java | 18 +++- .../taoyao/boot/config/IdProperties.java | 27 ++++++ .../boot/config/OpenApiAutoConfiguration.java | 39 ++++---- .../taoyao/boot/config/TaoyaoProperties.java | 1 - .../WebMvcConfigurerAutoConfiguration.java | 14 ++- .../taoyao/boot/config/WebrtcProperties.java | 6 +- .../boot/interceptor/InterceptorAdapter.java | 28 ++++++ .../boot/interceptor/SecurityInterceptor.java | 34 ++++--- .../boot/interceptor/SlowInterceptor.java | 59 ++++++++++++ .../com/acgist/taoyao/boot/model/Header.java | 12 ++- .../com/acgist/taoyao/boot/model/Message.java | 12 +-- .../acgist/taoyao/boot/model/MessageCode.java | 19 ++-- .../boot/model/MessageCodeException.java | 87 +++++------------ .../com/acgist/taoyao/boot/model/Model.java | 5 + .../acgist/taoyao/boot/service/IdService.java | 2 +- .../boot/service/impl/IdServiceImpl.java | 21 ++--- .../acgist/taoyao/boot/utils/ErrorUtils.java | 6 +- .../acgist/taoyao/boot/utils/JSONUtils.java | 12 +-- taoyao-server/pom.xml | 6 ++ .../main/resources/application-release.yml | 3 + .../src/main/resources/application-test.yml | 3 + .../src/main/resources/application.yml | 18 +++- .../src/main/resources/static/favicon.ico | Bin 0 -> 16958 bytes .../taoyao/boot/service/IdServiceTest.java | 35 +++++++ .../listener/client/RegisterListener.java | 8 +- .../signal/media/ClientMediaHandler.java | 30 ++++++ .../signal/media/ClientMediaPublisher.java | 14 +++ .../signal/media/ClientMediaSubscriber.java | 40 ++++++++ .../media/router/ClientMediaStreamRouter.java | 10 ++ .../ClientMediaStreamRouterAdapter.java | 10 ++ .../media/stream/ClientMediaStream.java | 89 ++++++++++++++++++ .../stream/ClientMediaStreamAdapter.java | 19 ++++ .../signal/protocol/ProtocolManager.java | 1 + .../taoyao/signal/session/ClientSession.java | 17 ++++ .../signal/session/ClientSessionAdapter.java | 33 +++++++ .../signal/session/ClientSessionManager.java | 3 +- .../signal/session/ClientSessionStatus.java | 26 ++++- .../signal/session/socket/SocketSession.java | 36 +++++++ .../session/websocket/WebSocketSession.java | 10 +- .../session/websocket/WebSocketSignal.java | 10 +- taoyao-test/pom.xml | 27 ++++++ .../taoyao/test/annotation/CostedTest.java | 42 +++++++++ .../CostedTestTestExecutionListener.java | 55 +++++++++++ .../taoyao/test/annotation/TaoyaoTest.java | 31 ++++++ 46 files changed, 841 insertions(+), 215 deletions(-) create mode 100644 taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/IdProperties.java create mode 100644 taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/InterceptorAdapter.java create mode 100644 taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SlowInterceptor.java create mode 100644 taoyao-server/src/main/resources/static/favicon.ico create mode 100644 taoyao-server/src/test/java/com/acgist/taoyao/boot/service/IdServiceTest.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouter.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouterAdapter.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStreamAdapter.java create mode 100644 taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSession.java create mode 100644 taoyao-test/pom.xml create mode 100644 taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTest.java create mode 100644 taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTestTestExecutionListener.java create mode 100644 taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/TaoyaoTest.java diff --git a/README.md b/README.md index d12a075..fd62d3f 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,16 @@ |taoyao-nat|内网穿透|STUN/TURN| |taoyao-boot|基础|启动模块| |taoyao-live|直播|直播、连麦| -|taoyao-media|媒体|录制、视频(美颜、AI识别)、音频(混音、变声)| +|taoyao-test|测试|测试工具| +|taoyao-media|媒体|录制、视频(美颜、AI识别)、音频(混音、变声、降噪)| |taoyao-signal|信令|信令服务| |taoyao-server|服务|启动服务| |taoyao-meeting|会议|会议模式、广播模式、单人对讲| -|taoyao-webrtc|WebRTC模块|| +|taoyao-webrtc|WebRTC模块|WebRTC模块| |taoyao-webrtc-jni|WebRTC JNI|WebRTC本地接口| -|taoyao-webrtc-sfu|WebRTC SFU架构实现|| -|taoyao-webrtc-mcu|WebRTC MCU架构实现|| -|taoyao-webrtc-mesh|WebRTC MESH架构实现|| +|taoyao-webrtc-sfu|WebRTC SFU架构|SFU架构| +|taoyao-webrtc-mcu|WebRTC MCU架构|MCU架构| +|taoyao-webrtc-mesh|WebRTC MESH架构|MESH架构| ## STUN/TURN公共服务 @@ -30,46 +31,41 @@ stun:stun4.l.google.com:19302 stun:stun.stunprotocol.org:3478 ``` -## 终端 - -帐号(移动端|浏览器) -摄像头 - -### 功能 - -|功能|场景|描述|帐号|摄像头| -注册 -注销 -心跳 -推流 -拉流 -邀请 -踢出 -绑定设备 -解绑设备 -进入会议:没有自动创建 -关闭会议: -订阅 -取消订阅 -暂停推流 -恢复推流 -掉线重连 - ## 信令 -### 信息 - -IP -MAC -信号 -电量 -通话状态 -录制状态 +|功能|描述| +|:--|:--| +|注册|终端注册(同步信息)| +|关闭|终端关闭(注销)| +|心跳|终端心跳| +|进入会议|没有会议自动创建| +|离开会议|离开会议| +|关闭会议|关闭会议(所有人员离开)| +|邀请终端|会议邀请终端| +|踢出终端|会议踢出终端| +|推流|控制终端推流| +|暂停推流|控制终端暂停推流| +|订阅(分流)|控制终端暂停推流| +|暂停订阅(分流)|控制终端暂停推流| ## 直播 +终端推流到服务端,由服务端分流。 + ## 会议 +### Mesh + +流媒体点对点连接,不经过服务端。 + +### MCU + +终端推流到服务端,由服务端分流并且混音。 + +### SFU + +终端推流到服务端,由服务端分流没有混音。 + ## 证书 ``` diff --git a/pom.xml b/pom.xml index a44aa27..1ddc91c 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ taoyao-nat taoyao-boot taoyao-live + taoyao-test taoyao-media taoyao-signal taoyao-webrtc @@ -117,6 +118,11 @@ taoyao-live ${project.version} + + com.acgist + taoyao-test + ${project.version} + com.acgist taoyao-media diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java index 7cd6d34..bcbc8c0 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java @@ -1,6 +1,7 @@ package com.acgist.taoyao.boot.config; import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; import java.util.Timer; import java.util.TimerTask; import java.util.stream.Collectors; @@ -50,6 +51,7 @@ import org.springframework.web.servlet.NoHandlerFoundException; import com.acgist.taoyao.boot.controller.TaoyaoControllerAdvice; import com.acgist.taoyao.boot.controller.TaoyaoErrorController; import com.acgist.taoyao.boot.interceptor.SecurityInterceptor; +import com.acgist.taoyao.boot.interceptor.SlowInterceptor; import com.acgist.taoyao.boot.model.MessageCode; import com.acgist.taoyao.boot.service.IdService; import com.acgist.taoyao.boot.service.impl.IdServiceImpl; @@ -73,7 +75,7 @@ import lombok.extern.slf4j.Slf4j; @Configuration @EnableScheduling @EnableAspectJAutoProxy(exposeProxy = true) -@EnableConfigurationProperties({ TaoyaoProperties.class, WebrtcProperties.class, SecurityProperties.class }) +@EnableConfigurationProperties({ IdProperties.class, TaoyaoProperties.class, WebrtcProperties.class, SecurityProperties.class }) public class BootAutoConfiguration { @Value("${spring.application.name:taoyao}") @@ -119,6 +121,12 @@ public class BootAutoConfiguration { }; } + @Bean + @ConditionalOnMissingBean + public SlowInterceptor slowInterceptor() { + return new SlowInterceptor(); + } + @Bean @ConditionalOnMissingBean public SecurityInterceptor securityInterceptor() { @@ -139,15 +147,15 @@ public class BootAutoConfiguration { @PostConstruct public void init() { - final var runtime = Runtime.getRuntime(); - final var runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + final Runtime runtime = Runtime.getRuntime(); + final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); final String freeMemory = FileUtils.formatSize(runtime.freeMemory()); final String totalMemory = FileUtils.formatSize(runtime.totalMemory()); final String maxMemory = FileUtils.formatSize(runtime.maxMemory()); log.info("操作系统名称:{}", System.getProperty("os.name")); log.info("操作系统架构:{}", System.getProperty("os.arch")); log.info("操作系统版本:{}", System.getProperty("os.version")); - log.info("操作系统可用处理器数量:{}", runtime.availableProcessors()); + log.info("可用的处理器数量:{}", runtime.availableProcessors()); log.info("Java版本:{}", System.getProperty("java.version")); log.info("Java主目录:{}", System.getProperty("java.home")); log.info("Java库目录:{}", System.getProperty("java.library.path")); @@ -184,8 +192,8 @@ public class BootAutoConfiguration { ErrorUtils.register(MessageCode.CODE_3400, MethodArgumentNotValidException.class); ErrorUtils.register(MessageCode.CODE_3500, ConversionNotSupportedException.class); ErrorUtils.register(MessageCode.CODE_3500, HttpMessageNotWritableException.class); - ErrorUtils.register(MessageCode.CODE_3415, HttpMediaTypeNotSupportedException.class); ErrorUtils.register(MessageCode.CODE_3400, MissingServletRequestPartException.class); + ErrorUtils.register(MessageCode.CODE_3415, HttpMediaTypeNotSupportedException.class); ErrorUtils.register(MessageCode.CODE_3406, HttpMediaTypeNotAcceptableException.class); ErrorUtils.register(MessageCode.CODE_3405, HttpRequestMethodNotSupportedException.class); ErrorUtils.register(MessageCode.CODE_3400, MissingServletRequestParameterException.class); diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/IdProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/IdProperties.java new file mode 100644 index 0000000..3a8f802 --- /dev/null +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/IdProperties.java @@ -0,0 +1,27 @@ +package com.acgist.taoyao.boot.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Getter; +import lombok.Setter; + +/** + * ID配置 + * + * @author acgist + */ +@Getter +@Setter +@ConfigurationProperties(prefix = "taoyao.id") +public class IdProperties { + + /** + * 机器序号 + */ + private Integer sn; + /** + * 最大序号 + */ + private Integer maxIndex; + +} diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/OpenApiAutoConfiguration.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/OpenApiAutoConfiguration.java index efe75a4..2de9c28 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/OpenApiAutoConfiguration.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/OpenApiAutoConfiguration.java @@ -1,5 +1,7 @@ package com.acgist.taoyao.boot.config; +import java.util.List; + import org.springdoc.core.GroupedOpenApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -9,8 +11,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.security.SecurityRequirement; @@ -61,46 +63,45 @@ public class OpenApiAutoConfiguration { public OpenAPI openAPI() { return new OpenAPI() .info(this.buildInfo()) - .externalDocs(this.buildExternalDocumentation()) - .addSecurityItem(this.buildSecurityRequirement()) + .security(this.buildSecurity()) .components(this.buildComponents()); } /** - * @return 文档基本信息 + * @return 基本信息 */ private Info buildInfo() { return new Info() + .contact(this.buildContact()) + .license(this.buildLicense()) .title(this.taoyaoProperties.getName()) .version(this.taoyaoProperties.getVersion()) - .description(this.taoyaoProperties.getDescription()) - .license(this.buildLicense()); + .description(this.taoyaoProperties.getDescription()); } /** - * @return 授权协议信息 + * @return 联系方式 + */ + private Contact buildContact() { + return new Contact() + .url(this.taoyaoProperties.getUrl()) + .name(this.taoyaoProperties.getName()); + } + + /** + * @return 开源信息 */ private License buildLicense() { return new License() .name("Apache 2.0") .url("https://www.apache.org/licenses/LICENSE-2.0.html"); } - - /** - * @return 外部文档信息 - */ - private ExternalDocumentation buildExternalDocumentation() { - return new ExternalDocumentation() - .description(this.taoyaoProperties.getDescription()) - .url(this.taoyaoProperties.getUrl()); - } /** * @return 授权 */ - private SecurityRequirement buildSecurityRequirement() { - return new SecurityRequirement() - .addList(SecurityProperties.BASIC); + private List buildSecurity() { + return List.of(new SecurityRequirement().addList(SecurityProperties.BASIC)); } /** 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 2c736a0..391274b 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 @@ -36,5 +36,4 @@ public class TaoyaoProperties { */ private String description; - } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebMvcConfigurerAutoConfiguration.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebMvcConfigurerAutoConfiguration.java index df3dfbc..d82d53a 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebMvcConfigurerAutoConfiguration.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebMvcConfigurerAutoConfiguration.java @@ -1,11 +1,12 @@ package com.acgist.taoyao.boot.config; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import com.acgist.taoyao.boot.interceptor.SecurityInterceptor; +import com.acgist.taoyao.boot.interceptor.InterceptorAdapter; import lombok.extern.slf4j.Slf4j; @@ -19,12 +20,17 @@ import lombok.extern.slf4j.Slf4j; public class WebMvcConfigurerAutoConfiguration implements WebMvcConfigurer { @Autowired - private SecurityInterceptor securityInterceptor; + private ApplicationContext context; @Override public void addInterceptors(InterceptorRegistry registry) { - log.info("加载拦截器:securityInterceptor"); - registry.addInterceptor(this.securityInterceptor).addPathPatterns("/**"); + this.context.getBeansOfType(InterceptorAdapter.class).entrySet().stream() + .sorted((a, z) -> a.getValue().compareTo(z.getValue())) + .forEach(entry -> { + final InterceptorAdapter value = entry.getValue(); + log.info("加载拦截器:{}-{}", entry.getKey(), value.name()); + registry.addInterceptor(value).addPathPatterns(value.pathPattern()); + }); } } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java index 25c3cd3..ae15457 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java @@ -13,7 +13,7 @@ import lombok.Setter; */ @Getter @Setter -@Schema(name = "WebRTC配置") +@Schema(title = "WebRTC配置", description = "WebRTC配置") @ConfigurationProperties(prefix = "taoyao.webrtc") public class WebrtcProperties { @@ -42,15 +42,17 @@ public class WebrtcProperties { /** * 类型 */ - @Schema(name = "架构类型", description = "WebRTC架构类型") + @Schema(title = "架构类型", description = "WebRTC架构类型") private Type type; /** * stun服务器 */ + @Schema(title = "stun服务器", description = "stun服务器") private String[] stun; /** * turn服务器 */ + @Schema(title = "turn服务器", description = "turn服务器") private String[] turn; } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/InterceptorAdapter.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/InterceptorAdapter.java new file mode 100644 index 0000000..bf17ca8 --- /dev/null +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/InterceptorAdapter.java @@ -0,0 +1,28 @@ +package com.acgist.taoyao.boot.interceptor; + +import org.springframework.core.Ordered; +import org.springframework.web.servlet.HandlerInterceptor; + +/** + * 拦截器适配器 + * + * @author acgist + */ +public abstract class InterceptorAdapter implements Ordered, HandlerInterceptor, Comparable { + + /** + * @return 名称 + */ + public abstract String name(); + + /** + * @return 拦截地址 + */ + public abstract String[] pathPattern(); + + @Override + public int compareTo(InterceptorAdapter o) { + return Integer.compare(this.getOrder(), o.getOrder()); + } + +} diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SecurityInterceptor.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SecurityInterceptor.java index e5987e3..b22f55a 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SecurityInterceptor.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SecurityInterceptor.java @@ -10,7 +10,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.web.servlet.HandlerInterceptor; import com.acgist.taoyao.boot.config.SecurityProperties; @@ -22,20 +21,29 @@ import lombok.extern.slf4j.Slf4j; * @author acgist */ @Slf4j -public class SecurityInterceptor implements HandlerInterceptor { +public class SecurityInterceptor extends InterceptorAdapter { - /** - * 时间 - */ - private ThreadLocal local = new ThreadLocal<>(); - @Autowired private SecurityProperties securityProperties; + @Override + public String name() { + return "安全拦截"; + } + + @Override + public String[] pathPattern() { + return new String[] { "/**" }; + } + + @Override + public int getOrder() { + return Integer.MIN_VALUE + 1; + } + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if(this.permit(request) || this.authorization(request)) { - this.local.set(System.currentTimeMillis()); return true; } response.setStatus(HttpStatus.UNAUTHORIZED.value()); @@ -85,14 +93,4 @@ public class SecurityInterceptor implements HandlerInterceptor { return true; } - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { - final long duration; - final Long last = this.local.get(); - if(last != null && (duration = System.currentTimeMillis() - last) > 1000) { - log.info("执行时间过慢:{}-{}", request.getRequestURI(), duration); - } - this.local.remove(); - } - } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SlowInterceptor.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SlowInterceptor.java new file mode 100644 index 0000000..c50599f --- /dev/null +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/interceptor/SlowInterceptor.java @@ -0,0 +1,59 @@ +package com.acgist.taoyao.boot.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.acgist.taoyao.boot.config.TaoyaoProperties; + +import lombok.extern.slf4j.Slf4j; + +/** + * 过慢请求统计拦截 + * + * @author acgist + */ +@Slf4j +public class SlowInterceptor extends InterceptorAdapter { + + /** + * 时间 + */ + private ThreadLocal local = new ThreadLocal<>(); + + @Autowired + private TaoyaoProperties taoyaoProperties; + + @Override + public String name() { + return "过慢请求统计拦截"; + } + + @Override + public String[] pathPattern() { + return new String[] { "/**" }; + } + + @Override + public int getOrder() { + return Integer.MIN_VALUE; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + this.local.set(System.currentTimeMillis()); + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception { + final long duration; + final Long last = this.local.get(); + if(last != null && (duration = System.currentTimeMillis() - last) > this.taoyaoProperties.getTimeout()) { + log.info("请求执行时间过慢:{}-{}", request.getRequestURI(), duration); + } + this.local.remove(); + } + +} diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Header.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Header.java index 0ad4867..452c97b 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Header.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Header.java @@ -2,6 +2,7 @@ package com.acgist.taoyao.boot.model; import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -9,12 +10,13 @@ import lombok.NoArgsConstructor; import lombok.Setter; /** - * 信令头部 + * 请求响应头部 * * @author acgist */ @Getter @Setter +@Schema( title = "请求响应头部", description = "请求响应头部") @Builder @NoArgsConstructor @AllArgsConstructor @@ -23,20 +25,24 @@ public class Header implements Serializable { private static final long serialVersionUID = 1L; /** - * 信令版本 + * 请求响应版本 */ + @Schema(title = "请求响应版本", description = "请求响应版本") private String v; /** - * 请求标识 + * 请求响应标识 */ + @Schema(title = "请求响应标识", description = "请求响应标识") private Long id; /** * 终端标识 */ + @Schema(title = "终端标识", description = "终端标识") private String sn; /** * 协议标识 */ + @Schema(title = "协议标识", description = "协议标识") private Integer pid; } 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 ceeefd4..a46ce7a 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 @@ -14,13 +14,13 @@ import lombok.NoArgsConstructor; import lombok.Setter; /** - * 消息 + * 请求响应消息 * * @author acgist */ @Getter @Setter -@Schema(name = "消息", description = "请求响应消息") +@Schema(title = "请求响应消息", description = "请求响应消息") @Builder @NoArgsConstructor @AllArgsConstructor @@ -31,22 +31,22 @@ public class Message implements Serializable { /** * 响应编码 */ - @Schema(name = "响应编码", description = "响应消息标识响应状态") + @Schema(title = "响应编码", description = "响应消息标识响应状态") private String code; /** * 响应描述 */ - @Schema(name = "响应描述", description = "响应消息描述响应编码") + @Schema(title = "响应描述", description = "响应消息描述响应编码") private String message; /** * 请求响应头部 */ - @Schema(name = "请求响应头部", description = "请求响应头部") + @Schema(title = "请求响应头部", description = "请求响应头部") private Header header; /** * 请求响应主体 */ - @Schema(name = "请求响应主体", description = "请求响应主体") + @Schema(title = "请求响应主体", description = "请求响应主体") private Object body; /** diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCode.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCode.java index 0e46da4..c337cd7 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCode.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCode.java @@ -5,10 +5,10 @@ import lombok.Getter; /** * 状态编码 * - * 1xxx=前置错误:前置校验错误(数据校验) - * 2xxx=内部错误:服务内部错误 + * 1xxx=前置错误:数据校验 + * 2xxx=内部错误 * 3xxx=请求错误:HTTP错误 - * 9999=未知错误:没有适配异常 + * 9999=未知错误 * * @author acgist */ @@ -41,7 +41,7 @@ public enum MessageCode { CODE_9999("9999", 500, "未知错误"); /** - * HTTP状态编码头部 + * HTTP状态编码前缀 */ public static final String HTTP_STATUS = "3"; @@ -54,7 +54,7 @@ public enum MessageCode { */ private final Integer status; /** - * 状态信息 + * 状态描述 */ private final String message; @@ -85,14 +85,7 @@ public enum MessageCode { * @return 状态编码 */ public static final MessageCode of(Integer status) { - final String code = HTTP_STATUS + status; - final MessageCode[] values = MessageCode.values(); - for (MessageCode value : values) { - if (value.code.equals(code)) { - return value; - } - } - return of(String.valueOf(status)); + return of(HTTP_STATUS + status); } } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCodeException.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCodeException.java index 873c132..23a5551 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCodeException.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/MessageCodeException.java @@ -2,14 +2,16 @@ package com.acgist.taoyao.boot.model; import java.util.Objects; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import lombok.Getter; + /** * 状态编码异常 * * @author acgist */ +@Getter public class MessageCodeException extends RuntimeException { private static final long serialVersionUID = 1L; @@ -20,104 +22,59 @@ public class MessageCodeException extends RuntimeException { private final MessageCode code; /** - * @param messages 错误消息 + * @param message 错误消息 * * @return 状态编码异常 */ - public static final MessageCodeException of(Object ... messages) { - return of(null, MessageCode.CODE_9999, messages); + public static final MessageCodeException of(String message) { + return of(null, null, message); } /** * @param t 异常 - * @param messages 错误消息 + * @param message 错误消息 * * @return 状态编码异常 */ - public static final MessageCodeException of(Throwable t, Object ... messages) { - return of(t, MessageCode.CODE_9999, messages); + public static final MessageCodeException of(Throwable t, String message) { + return of(t, null, message); } /** * @param code 状态编码 - * @param messages 错误消息 + * @param message 错误消息 * * @return 状态编码异常 */ - public static final MessageCodeException of(MessageCode code, Object ... messages) { - return of(null, code, messages); + public static final MessageCodeException of(MessageCode code, String message) { + return of(null, code, message); } /** * @param t 异常 * @param code 状态编码 - * @param messages 错误消息 + * @param message 错误消息 * * @return 状态编码异常 */ - public static final MessageCodeException of(Throwable t, MessageCode code, Object ... messages) { - final String message; - if(ArrayUtils.isEmpty(messages)) { - message = Objects.isNull(t) ? code.getMessage() : t.getMessage(); - } else { - // 拼接错误描述 - final StringBuilder builder = new StringBuilder(); - for (Object value : messages) { - builder.append(value); - } - message = builder.toString(); + public static final MessageCodeException of(Throwable t, MessageCode code, String message) { + if(code == null) { + code = MessageCode.CODE_9999; } - return new MessageCodeException(code, message, t); - } - - /** - * @param code 状态编码 - */ - public MessageCodeException(MessageCode code) { - this(code, code.getMessage()); + if(StringUtils.isEmpty(message)) { + message = Objects.isNull(t) ? code.getMessage() : t.getMessage(); + } + return new MessageCodeException(t, code, message); } /** + * @param t 异常 * @param code 状态编码 * @param message 错误消息 */ - public MessageCodeException(MessageCode code, String message) { - this(code, message, null); - } - - /** - * @param code 状态编码 - * @param t 异常 - */ - public MessageCodeException(MessageCode code, Throwable t) { - this(code, Objects.isNull(t) ? code.getMessage() : t.getMessage(), t); - } - - /** - * @param code 状态编码 - * @param message 错误消息 - * @param t 异常 - */ - public MessageCodeException(MessageCode code, String message, Throwable t) { + public MessageCodeException(Throwable t, MessageCode code, String message) { super(message, t); this.code = code; } - /** - * @return 状态编码 - */ - public MessageCode getCode() { - return this.code; - } - - @Override - public String getMessage() { - final String message = super.getMessage(); - if (StringUtils.isEmpty(message)) { - return this.code.getMessage(); - } else { - return message; - } - } - } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Model.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Model.java index 47f6b78..c74533d 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Model.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/model/Model.java @@ -5,6 +5,7 @@ import java.time.LocalDateTime; import com.acgist.taoyao.boot.utils.JSONUtils; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -16,6 +17,7 @@ import lombok.Setter; */ @Getter @Setter +@Schema(title = "模型", description = "模型") @EqualsAndHashCode(callSuper = false, of = "id") public abstract class Model implements Cloneable, Serializable { @@ -24,14 +26,17 @@ public abstract class Model implements Cloneable, Serializable { /** * ID */ + @Schema(title = "标识", description = "标识") private Long id; /** * 创建时间 */ + @Schema(title = "创建时间", description = "创建时间") private LocalDateTime createDate; /** * 修改时间 */ + @Schema(title = "修改时间", description = "修改时间") private LocalDateTime modifyDate; @Override diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/IdService.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/IdService.java index f81a533..c2d79b1 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/IdService.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/IdService.java @@ -1,7 +1,7 @@ package com.acgist.taoyao.boot.service; /** - * ID + * ID生成器 * * @author acgist */ diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/impl/IdServiceImpl.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/impl/IdServiceImpl.java index 155e7ea..bb293ff 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/impl/IdServiceImpl.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/service/impl/IdServiceImpl.java @@ -2,30 +2,25 @@ package com.acgist.taoyao.boot.service.impl; import java.time.LocalDateTime; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Autowired; +import com.acgist.taoyao.boot.config.IdProperties; import com.acgist.taoyao.boot.service.IdService; public class IdServiceImpl implements IdService { - - /** - * 机器序号 - */ - @Value("${taoyao.sn:0}") - private int sn = 9; + /** * 当前索引 */ private int index; - /** - * 最大索引 - */ - private static final int MAX_INDEX = 999999; + + @Autowired + private IdProperties idProperties; @Override public long id() { synchronized (this) { - if (++this.index > MAX_INDEX) { + if (++this.index > this.idProperties.getMaxIndex()) { this.index = 0; } } @@ -38,7 +33,7 @@ public class IdServiceImpl implements IdService { 1000000000L * time.getMinute() + 10000000L * time.getSecond() + // 机器序号一位 - 1000000L * this.sn + + 1000000L * this.idProperties.getSn() + // 每秒并发数量 this.index; } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java index d66bf26..87173ca 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java @@ -125,7 +125,8 @@ public final class ErrorUtils { 请求参数:{} 请求方法:{} 错误信息:{} - """, path, query, method, message, globalError); + 响应状态:{} + """, path, query, method, message, status, globalError); } else { log.warn(""" 请求错误 @@ -133,8 +134,9 @@ public final class ErrorUtils { 请求参数:{} 请求方法:{} 错误信息:{} + 响应状态:{} 原始信息:{} - """, path, query, method, message, globalError); + """, path, query, method, message, status, globalError); } return message; } diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/JSONUtils.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/JSONUtils.java index 0a3a49b..3019091 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/JSONUtils.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/JSONUtils.java @@ -60,7 +60,7 @@ public final class JSONUtils { try { return MAPPER.writeValueAsString(object); } catch (JsonProcessingException e) { - throw MessageCodeException.of(e, "Java转JSON失败:", object); + throw MessageCodeException.of(e, "Java转JSON失败:" + object); } } @@ -81,7 +81,7 @@ public final class JSONUtils { return MAPPER.readValue(json, new TypeReference() { }); } catch (IOException e) { - throw MessageCodeException.of(e, "JSON转Java失败:", json); + throw MessageCodeException.of(e, "JSON转Java失败:" + json); } } @@ -102,7 +102,7 @@ public final class JSONUtils { try { return MAPPER.readValue(json, clazz); } catch (IOException e) { - throw MessageCodeException.of(e, "JSON转Java失败:", json); + throw MessageCodeException.of(e, "JSON转Java失败:" + json); } } @@ -124,7 +124,7 @@ public final class JSONUtils { return MAPPER.readValue(json, new TypeReference>() { }); } catch (IOException e) { - throw MessageCodeException.of(e, "JSON转Map失败:", json); + throw MessageCodeException.of(e, "JSON转Map失败:" + json); } } @@ -145,7 +145,7 @@ public final class JSONUtils { return MAPPER.readValue(json, new TypeReference>() { }); } catch (IOException e) { - throw MessageCodeException.of(e, "JSON转List失败:", json); + throw MessageCodeException.of(e, "JSON转List失败:" + json); } } @@ -169,7 +169,7 @@ public final class JSONUtils { return MAPPER.readValue(json, new TypeReference>() { }); } catch (IOException e) { - throw MessageCodeException.of(e, "JSON转List失败:", json); + throw MessageCodeException.of(e, "JSON转List失败:" + json); } } diff --git a/taoyao-server/pom.xml b/taoyao-server/pom.xml index 2027045..442ad00 100644 --- a/taoyao-server/pom.xml +++ b/taoyao-server/pom.xml @@ -50,6 +50,12 @@ org.springdoc springdoc-openapi-ui + + + com.acgist + taoyao-test + test + diff --git a/taoyao-server/src/main/resources/application-release.yml b/taoyao-server/src/main/resources/application-release.yml index e69de29..62fcb53 100644 --- a/taoyao-server/src/main/resources/application-release.yml +++ b/taoyao-server/src/main/resources/application-release.yml @@ -0,0 +1,3 @@ +taoyao: + security: + permit: /favicon.ico,/error diff --git a/taoyao-server/src/main/resources/application-test.yml b/taoyao-server/src/main/resources/application-test.yml index e69de29..62fcb53 100644 --- a/taoyao-server/src/main/resources/application-test.yml +++ b/taoyao-server/src/main/resources/application-test.yml @@ -0,0 +1,3 @@ +taoyao: + security: + permit: /favicon.ico,/error diff --git a/taoyao-server/src/main/resources/application.yml b/taoyao-server/src/main/resources/application.yml index 0ed7da7..369adc8 100644 --- a/taoyao-server/src/main/resources/application.yml +++ b/taoyao-server/src/main/resources/application.yml @@ -1,11 +1,16 @@ server: port: 8888 + http2: + enabled: true ssl: key-alias: taoyao key-store: classpath:taoyao.jks key-store-password: 123456 key-password: 123456 tomcat: + thread: + max: 128 + min-spare: 4 remoteip: host-header: X-Forwarded-Host port-header: X-Forwarded-Port @@ -16,8 +21,6 @@ spring: active: dev application: name: taoyao-server - jackson: - time-zone: GMT+8 servlet: multipart: max-file-size: 256MB @@ -47,6 +50,9 @@ taoyao: timeout: 5000 version: 1.0.0 description: WebRTC信令服务 + id: + sn: 0 + max-index: 999999 webrtc: type: SFU stun: @@ -56,10 +62,12 @@ taoyao: - stun:stun4.l.google.com:19302 - stun:stun.stunprotocol.org:3478 turn: + record: + storage: /data/record security: realm: taoyao - permit: /v3/api-docs/,/swagger-ui/,/error - username: - password: + permit: /v3/api-docs/,/swagger-ui/,/favicon.ico,/error + username: taoyao + password: taoyao scheduled: session: 0 * * * * ? diff --git a/taoyao-server/src/main/resources/static/favicon.ico b/taoyao-server/src/main/resources/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e7cf988d07ffe5c6b007459e6794f0d1f4e06368 GIT binary patch literal 16958 zcmeI4d+c3B5yvkAB9LeV1O-tL&>9hAj4^?jR1h&V5{wWrm>@oRDlrNaS_&dkT0sP* zvCs#|qx@PPmPcuM{CLQ#Ahy&}3YDf%ftEL=Ev1xkK0Uw5nY(w-IeYFszy9-MnsfKu zduC_nyJu&2W_EvVwKmg#!-u!@bGO#8{adXaTdmeGz4WKnnR@a2MjD&g6`&wE~m9Pz$w+;0l}@4PGWq_%nOe38rMicEN@{kl|tn>J5m z;fo^cly|UcuznV5!NSiw z{^dVJwmUNoYf7Jd_zaO>Trct;9UDzi)A;B8PvkpOGn-1m)D6#OI)1)&naG37dhdm% z@UK{vy_*l{8d`>lG5z%kBFEhzGPYmjoV#-V(X&Oy-7Rv$jUvPUmS!tQ^@%Khz59M> z0{^YLhU|P!jw8gsI`VASzuU=f-9`nt+%2$WF#lKeH zTTmJFYDr8tJq@L_Z%nk$aCdw#h!MH-(;~C z?tMX|4|M)a83%RnGxiR=i$)f%A~dJN3dAs^)___(#v_Y~yh4 zkFxo#syCXzPaEL;*>#=zov3qS8KvT%^His7*1TS@qgPY-k;Q!bg@`Sbt&J)8UtTS; zOTqen&oi{#JvE7c*=r(Op4R!EwpagP`5SQ^Q}DB{ny*1g8|LR7s&>~4HHrUt^&3sk z4+i~k)U|OftMEUuBFAd7$IQume7@t0!_zG_g@5H+B3lh${>nun=ii(6h3Wm!vQ90l z@Q3sLXU-F0{h#}6F8|1BopMuuX$t>YcjWq9Gf!l_`Ujzpbdau7A(i1@`l`qlBXha* z!STNdTde>F2imiD~~{O4)RXnIb3IByq!C5#uyA9yOlzd_g2j|VZ=q`AIkc8{&m zHh$T zw9Wf@vmoXwo=?=t?~bu85JiF?6MJ{cX!slE7Sr(X68 zcI)%b#ObDE4F3x%%dk^^`OhY)xb*fi<7mx0-?6=qjLGWlqj|4X>K4D{AQ+oqsG<`BA08hGis9$|`Mw%8JL9eT{Pj(F zy_ru`ac9rF!TKm#+&l_(;4l3=likgd;ITIx@~d0 zUUl%ZSD8xmXVW-~|I#q9rX z^^Z*_$|?+*r1npXjftP1d8PfC|CWk>)w(>!-D_NX9O~s2-TT}Sn9QbQ_*brK$Im`i zUGhG}NxCi;Q7V2P=8~JKMXY^mAtsem~x*!#+n{A|Jnp+A8&VZ>!aYL#o10d`(UZ8D%kUDA#{y@16Q~ zaTdp@2>$~0F^!*+yh%)dlT%dU)0vzL|Jlh^g`c?F>KBcnPO14XjB{_x$nxt<5q{p? zC;yPQO})B)09p`xn(b1W-I<0}`1f-$F8+003fFzc5V>KaBK$n(Jc{)_Nd6~MzJG432yg!?G;XI*+l*A9z~KYxDvxrj3S z2V9!rC&ncgUza$8VYn$-#}*H)dnT(4KRicX(=G#>NZD66`BwUKGCnpg!q53f;yd(a z52h|*cQ$WYA8;-$q$>PNUe^6S_2EngCFc?A(sMeNOb)(?Q4xOft=1+yb%}E*R-cl- zjLE6OPrKwxy)0r7pF>X7?dNWP{;q-8EruW8%;KC8Q&Oepe4Ile$LDnp_dSd|1wUsy z$ZL9eyQ&?OLow`y^=Q6PI5I=K^wZZ(IO2h==UNv&6e5N}1(dFpATtCwjABCKGDjhhmt}!3_H3~l+ z{{*>vjZgPAUR@*d%>kLF6D8*piNngME`G)sv4C%f`%j&lJ}1szoY(hp>30Wg19`E% z)))@XG}!)|*NOOzGn!RY7eDeCYq35c*KxA0733H<FToNJX z6O-|G3n$IYeSG7?M?89Zw&z+ju8f!G_)2wibH0a~!f!I4)_CEE)AF-urfZWW>n8Ir zF;cJ8G=9^E*cp3dE^G=r=aEjGRi00`_EXEj!f)-9gJ8dwd6G3b%te*;4QDV8nw0&G z5a*HXT${;mq8x1ep^n-e8)FgnSlDM`AIe|k_SrkYpR7BVhi#>N-_-b1blQ|W9zXed f;*p_r@i*VZwalrML-E>}m-7D^!29<@t_S`Pa1+=1 literal 0 HcmV?d00001 diff --git a/taoyao-server/src/test/java/com/acgist/taoyao/boot/service/IdServiceTest.java b/taoyao-server/src/test/java/com/acgist/taoyao/boot/service/IdServiceTest.java new file mode 100644 index 0000000..346f87a --- /dev/null +++ b/taoyao-server/src/test/java/com/acgist/taoyao/boot/service/IdServiceTest.java @@ -0,0 +1,35 @@ +package com.acgist.taoyao.boot.service; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.acgist.taoyao.main.TaoyaoApplication; +import com.acgist.taoyao.test.annotation.TaoyaoTest; +import com.acgist.taoyao.test.annotation.CostedTest; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@TaoyaoTest(classes = TaoyaoApplication.class) +//@SpringBootTest(classes = TaoyaoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +class IdServiceTest { + + @Autowired + private IdService idService; + + @Test +// @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) +// @Rollback() +// @RepeatedTest(10) + void testId() { + final long id = this.idService.id(); + log.info("生成ID:{}", id); + } + + @Test + @CostedTest(count = 100000, thread = 10) + void testIdCosted() { + this.idService.id(); + } + +} 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 4f8d365..327dcca 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 @@ -22,17 +22,19 @@ public class RegisterListener extends ApplicationListenerAdapter @Autowired private OnlineProtocol onlineProtocol; - + @Async @Override public void onApplicationEvent(RegisterEvent event) { final ClientSession session = event.getSession(); - if(!session.authorized()) { + if (!session.authorized()) { return; } final Message message = this.onlineProtocol.build(); message.setBody(Map.of("sn", session.sn())); - this.clientSessionManager.broadcast(message); + this.clientSessionManager.broadcast(session.sn(), message); + // TODO:ip等等 + // TODO:重新注册上来需要掉线重连 } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java new file mode 100644 index 0000000..4cab741 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java @@ -0,0 +1,30 @@ +package com.acgist.taoyao.signal.media; + +/** + * 终端媒体操作 + * + * @author acgist + */ +public interface ClientMediaHandler { + + /** + * 打开 + */ + void open(String id); + + /** + * 暂停 + */ + void pause(); + + /** + * 恢复 + */ + void resume(); + + /** + * 关闭 + */ + void close(); + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java new file mode 100644 index 0000000..3283317 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java @@ -0,0 +1,14 @@ +package com.acgist.taoyao.signal.media; + +/** + * 终端推流 + */ +public class ClientMediaPublisher { + + public void publish(String id) { + } + + public void unpublish(String id) { + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java new file mode 100644 index 0000000..4531dcb --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java @@ -0,0 +1,40 @@ +package com.acgist.taoyao.signal.media; + +/** + * 终端媒体订阅者(终端拉流) + * + * @author acgist + */ +public class ClientMediaSubscriber implements ClientMediaHandler { + + public void subscribe(String id) { + } + + public void unsubscribe(String id) { + } + + @Override + public void open(String id) { + // TODO Auto-generated method stub + + } + + @Override + public void pause() { + // TODO Auto-generated method stub + + } + + @Override + public void resume() { + // TODO Auto-generated method stub + + } + + @Override + public void close() { + // TODO Auto-generated method stub + + } + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouter.java new file mode 100644 index 0000000..a76aa2c --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouter.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.signal.media.router; + +/** + * 终端媒体流路由(推流->拉流) + * + * @author acgist + */ +public interface ClientMediaStreamRouter { + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouterAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouterAdapter.java new file mode 100644 index 0000000..cfb2b0c --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/router/ClientMediaStreamRouterAdapter.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.signal.media.router; + +import com.acgist.taoyao.signal.media.stream.ClientMediaStream; + +public class ClientMediaStreamRouterAdapter { + + ClientMediaStream source; + ClientMediaStream target; + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java new file mode 100644 index 0000000..bc2616b --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java @@ -0,0 +1,89 @@ +package com.acgist.taoyao.signal.media.stream; + +/** + * 终端媒体流 + * + * @author acgist + */ +public interface ClientMediaStream { + + /** + * 终端媒体类型 + * + * @author acgist + */ + public enum Type { + + /** + * 音频 + */ + AUDIO, + /** + * 视频 + */ + VIDEO; + + } + + /** + * 终端媒体流状态 + * + * @author acgist + */ + public enum Status { + + /** + * 没有激活 + */ + IDLE, + /** + * 已经激活 + */ + BUSY, + /** + * 已经暂停 + */ + PAUSE, + /** + * 已经关闭 + */ + CLOSE; + + } + + /** + * @return 终端媒体流ID + */ + String id(); + + /** + * 打开终端媒体流 + */ + void open(); + + /** + * 暂停终端媒体流 + */ + void pause(); + + /** + * 恢复终端媒体流 + */ + void resume(); + + /** + * 关闭终端媒体流 + */ + void close(); + + /** + * @return 终端媒体流类型 + */ + Type type(); + + /** + * @return 终端媒体流状态 + */ + Status status(); + +} diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStreamAdapter.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStreamAdapter.java new file mode 100644 index 0000000..c3f63e4 --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStreamAdapter.java @@ -0,0 +1,19 @@ +package com.acgist.taoyao.signal.media.stream; + +/** + * 终端媒体流适配器 + * + * @author acgist + */ +public abstract class ClientMediaStreamAdapter implements ClientMediaStream { + + /** + * 媒体标识 + */ + private String id; + /** + * 真实流 + */ + protected T stream; + +} 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 661470f..8b87c89 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 @@ -60,6 +60,7 @@ public class ProtocolManager { * @param instance 会话实例 */ public void execute(String message, AutoCloseable instance) { + log.debug("执行信令消息:{}", message); if(StringUtils.isEmpty(message)) { log.warn("消息为空:{}", message); return; 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/session/ClientSession.java index 83a83c7..915185d 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSession.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSession.java @@ -1,6 +1,8 @@ package com.acgist.taoyao.signal.session; import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.media.ClientMediaPublisher; +import com.acgist.taoyao.signal.media.ClientMediaSubscriber; /** * 会话 @@ -15,6 +17,21 @@ public interface ClientSession extends AutoCloseable { * @return 终端标识 */ String sn(); + + /** + * @return 终端状态 + */ + ClientSessionStatus status(); + + /** + * @return 终端媒体发布者 + */ + ClientMediaPublisher publisher(); + + /** + * @return 终端媒体订阅者 + */ + ClientMediaSubscriber subscriber(); /** * 推送消息 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/session/ClientSessionAdapter.java index c3e5824..1323149 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionAdapter.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionAdapter.java @@ -2,6 +2,9 @@ package com.acgist.taoyao.signal.session; import org.apache.commons.lang3.StringUtils; +import com.acgist.taoyao.signal.media.ClientMediaPublisher; +import com.acgist.taoyao.signal.media.ClientMediaSubscriber; + /** * 会话适配器 * @@ -25,11 +28,26 @@ public abstract class ClientSessionAdapter implements C * 是否授权 */ protected boolean authorized; + /** + * 终端状态 + */ + protected ClientSessionStatus status; + /** + * 终端媒体发布者 + */ + protected ClientMediaPublisher publisher; + /** + * 终端媒体订阅者 + */ + protected ClientMediaSubscriber subscriber; protected ClientSessionAdapter(T instance) { this.time = System.currentTimeMillis(); this.instance = instance; this.authorized = false; + this.status = new ClientSessionStatus(); + this.publisher = new ClientMediaPublisher(); + this.subscriber = new ClientMediaSubscriber(); } @Override @@ -37,6 +55,21 @@ public abstract class ClientSessionAdapter implements C return this.sn; } + @Override + public ClientSessionStatus status() { + return this.status; + } + + @Override + public ClientMediaPublisher publisher() { + return this.publisher; + } + + @Override + public ClientMediaSubscriber subscriber() { + return this.subscriber; + } + @Override public boolean timeout(long timeout) { return !(this.authorized && System.currentTimeMillis() - this.time <= timeout); 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/session/ClientSessionManager.java index 24a39e4..fc103f9 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionManager.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionManager.java @@ -101,9 +101,8 @@ public class ClientSessionManager { try { if(session != null) { session.close(); - } else { - instance.close(); } + instance.close(); } catch (Exception e) { log.error("关闭会话异常", e); } finally { 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/session/ClientSessionStatus.java index e9f78a5..8740e01 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionStatus.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/ClientSessionStatus.java @@ -1,12 +1,36 @@ package com.acgist.taoyao.signal.session; +import lombok.Getter; +import lombok.Setter; + /** * 终端状态 * * @author acgist */ +@Getter +@Setter public class ClientSessionStatus { - + /** + * 终端标识 + */ + private String sn; + /** + * IP + */ + private String ip; + /** + * MAC + */ + private String mac; + /** + * 信号强度(0~100) + */ + private Integer signal = 0; + /** + * 电量(0~100) + */ + private Integer battery = 0; } 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/session/socket/SocketSession.java new file mode 100644 index 0000000..046402d --- /dev/null +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/session/socket/SocketSession.java @@ -0,0 +1,36 @@ +package com.acgist.taoyao.signal.session.socket; + +import java.io.IOException; +import java.net.Socket; + +import com.acgist.taoyao.boot.model.Message; +import com.acgist.taoyao.signal.session.ClientSessionAdapter; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * Socket会话 + * + * @author acgist + */ +@Slf4j +@Getter +@Setter +public class SocketSession extends ClientSessionAdapter { + + public SocketSession(Socket instance) { + super(instance); + } + + @Override + public void push(Message message) { + try { + this.instance.getOutputStream().write(message.toString().getBytes()); + } catch (IOException e) { + log.error("Socket发送消息异常:{}", message, e); + } + } + +} 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/session/websocket/WebSocketSession.java index 6212d29..7dd2ddf 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/session/websocket/WebSocketSession.java @@ -1,7 +1,5 @@ package com.acgist.taoyao.signal.session.websocket; -import java.io.IOException; - import javax.websocket.Session; import com.acgist.taoyao.boot.model.Message; @@ -28,8 +26,12 @@ public class WebSocketSession extends ClientSessionAdapter { @Override public void push(Message message) { try { - this.instance.getBasicRemote().sendText(message.toString()); - } catch (IOException e) { + if(this.instance.isOpen()) { + this.instance.getBasicRemote().sendText(message.toString()); + } else { + log.error("会话已经关闭:{}", this.instance); + } + } catch (Exception e) { log.error("WebSocket发送消息异常:{}", message, e); } } 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/session/websocket/WebSocketSignal.java index 3c9a2a9..81b8f9a 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/session/websocket/WebSocketSignal.java @@ -1,7 +1,5 @@ package com.acgist.taoyao.signal.session.websocket; -import java.io.IOException; - import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; @@ -70,8 +68,12 @@ public class WebSocketSignal { */ private void push(Session session, Message message) { try { - session.getBasicRemote().sendText(message.toString()); - } catch (IOException e) { + if(session.isOpen()) { + session.getBasicRemote().sendText(message.toString()); + } else { + log.error("会话已经关闭:{}", session); + } + } catch (Exception e) { log.error("推送消息异常:{}", message, e); } } diff --git a/taoyao-test/pom.xml b/taoyao-test/pom.xml new file mode 100644 index 0000000..ada4e9e --- /dev/null +++ b/taoyao-test/pom.xml @@ -0,0 +1,27 @@ + + + + + 4.0.0 + + + com.acgist + taoyao + 1.0.0 + + + taoyao-test + jar + + taoyao-test + 测试:测试工具 + + + + org.springframework.boot + spring-boot-starter-test + true + + + + \ No newline at end of file diff --git a/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTest.java b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTest.java new file mode 100644 index 0000000..d350938 --- /dev/null +++ b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTest.java @@ -0,0 +1,42 @@ +package com.acgist.taoyao.test.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * 多线程测试 + * + * @author acgist + */ +@Target(ElementType.METHOD) +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface CostedTest { + + /** + * @return 执行次数 + */ + int count() default 1; + + /** + * @return 线程数量 + */ + int thread() default 1; + + /** + * @return 超时时间 + */ + long timeout() default 1000; + + /** + * @return 超时时间单位 + */ + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + +} 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 new file mode 100644 index 0000000..96d3667 --- /dev/null +++ b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/CostedTestTestExecutionListener.java @@ -0,0 +1,55 @@ +package com.acgist.taoyao.test.annotation; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestExecutionListener; + +import lombok.extern.slf4j.Slf4j; + +/** + * 多线程测试监听 + * + * @author acgist + */ +@Slf4j +public class CostedTestTestExecutionListener implements TestExecutionListener { + + @Override + public void afterTestMethod(TestContext testContext) throws Exception { + final CostedTest costedTest = testContext.getTestMethod().getDeclaredAnnotation(CostedTest.class); + final int count = costedTest.count(); + final int thread = costedTest.thread(); + final long timeout = costedTest.timeout(); + final TimeUnit timeUnit = costedTest.timeUnit(); + final long aTime = System.currentTimeMillis(); + if(thread == 1) { + for (int index = 0; index < count; index++) { + testContext.getTestMethod().invoke(testContext.getTestInstance()); + } + } else { + final CountDownLatch countDownLatch = new CountDownLatch(count); + final ExecutorService executor = Executors.newFixedThreadPool(thread); + for (int index = 0; index < count; index++) { + executor.execute(() -> { + try { + testContext.getTestMethod().invoke(testContext.getTestInstance()); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + log.error("多线程测试异常", e); + } finally { + countDownLatch.countDown(); + } + }); + } + countDownLatch.await(timeout, timeUnit); + } + final long zTime = System.currentTimeMillis(); + final long costed = zTime - aTime; + log.info("多线程测试消耗时间:{}", costed); + } + +} diff --git a/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/TaoyaoTest.java b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/TaoyaoTest.java new file mode 100644 index 0000000..8dc269a --- /dev/null +++ b/taoyao-test/src/main/java/com/acgist/taoyao/test/annotation/TaoyaoTest.java @@ -0,0 +1,31 @@ +package com.acgist.taoyao.test.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.annotation.AliasFor; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.TestExecutionListeners.MergeMode; + +/** + * 测试启动 + * + * @author acgist + */ +@Target(ElementType.TYPE) +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Documented +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@TestExecutionListeners(listeners = CostedTestTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS) +public @interface TaoyaoTest { + + @AliasFor(annotation = SpringBootTest.class) + Class[] classes() default {}; + +}