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
+
+
+ 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 {};
+
+}