[*] 日常优化

This commit is contained in:
acgist
2023-07-18 08:24:44 +08:00
parent 9f6fdd564d
commit 6f9b66cb6f
17 changed files with 720 additions and 699 deletions

View File

@@ -1,282 +1,282 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version> <version>3.1.0</version>
<relativePath /> <relativePath />
</parent> </parent>
<groupId>com.acgist</groupId> <groupId>com.acgist</groupId>
<artifactId>taoyao</artifactId> <artifactId>taoyao</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<url>https://gitee.com/acgist/taoyao</url> <url>https://gitee.com/acgist/taoyao</url>
<name>taoyao</name> <name>taoyao</name>
<description>桃夭:桃夭是套基于`Mediasoup`开发的`WebRTC`音视频信令服务,可以非常方便的扩展信令接入更多智能终端。</description> <description>桃夭:桃夭是套基于`Mediasoup`开发的`WebRTC`音视频信令服务,可以非常方便的扩展信令接入更多智能终端。</description>
<inceptionYear>2022</inceptionYear> <inceptionYear>2022</inceptionYear>
<properties> <properties>
<!-- 版本 --> <!-- 版本 -->
<java.version>17</java.version> <java.version>17</java.version>
<lombok.version>1.18.28</lombok.version> <lombok.version>1.18.28</lombok.version>
<springdoc.version>2.1.0</springdoc.version> <springdoc.version>2.1.0</springdoc.version>
<mapstruct.version>1.5.5.Final</mapstruct.version> <mapstruct.version>1.5.5.Final</mapstruct.version>
<!-- 配置 --> <!-- 配置 -->
<taoyao.maven.basedir>${project.basedir}</taoyao.maven.basedir> <taoyao.maven.basedir>${project.basedir}</taoyao.maven.basedir>
<taoyao.maven.encoding>UTF-8</taoyao.maven.encoding> <taoyao.maven.encoding>UTF-8</taoyao.maven.encoding>
<taoyao.maven.skip.assembly>true</taoyao.maven.skip.assembly> <taoyao.maven.skip.assembly>true</taoyao.maven.skip.assembly>
</properties> </properties>
<modules> <modules>
<module>taoyao-boot</module> <module>taoyao-boot</module>
<module>taoyao-signal</module> <module>taoyao-signal</module>
<module>taoyao-server</module> <module>taoyao-server</module>
</modules> </modules>
<dependencies> <dependencies>
<!-- 快速开发 --> <!-- 快速开发 -->
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId> <artifactId>mapstruct</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId> <artifactId>mapstruct-processor</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</dependency> </dependency>
<!-- 开发工具 --> <!-- 开发工具 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
</dependency> </dependency>
<!-- Jackson --> <!-- Jackson -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId> <artifactId>jackson-datatype-jsr310</artifactId>
</dependency> </dependency>
<!-- 接口文档 --> <!-- 接口文档 -->
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency> </dependency>
<!-- AOP --> <!-- AOP -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>spring-boot-starter-aop</artifactId>
</dependency> </dependency>
<!-- 日志框架 --> <!-- 日志框架 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId> <artifactId>spring-boot-starter-logging</artifactId>
</dependency> </dependency>
<!-- 单元测试 --> <!-- 单元测试 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.acgist</groupId> <groupId>com.acgist</groupId>
<artifactId>taoyao-boot</artifactId> <artifactId>taoyao-boot</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.acgist</groupId> <groupId>com.acgist</groupId>
<artifactId>taoyao-signal</artifactId> <artifactId>taoyao-signal</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.acgist</groupId> <groupId>com.acgist</groupId>
<artifactId>taoyao-server</artifactId> <artifactId>taoyao-server</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<!-- mapstruct --> <!-- mapstruct -->
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId> <artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version> <version>${mapstruct.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId> <artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version> <version>${mapstruct.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- lombok --> <!-- lombok -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>${lombok.version}</version> <version>${lombok.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<build> <build>
<resources> <resources>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<includes> <includes>
<include>**/*.yml</include> <include>**/*.yml</include>
<include>**/*.properties</include> <include>**/*.properties</include>
</includes> </includes>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<includes> <includes>
<!-- 匹配所有文件:**/* --> <!-- 匹配所有文件:**/* -->
<!-- 匹配所有带有后缀文件:**/*.* --> <!-- 匹配所有带有后缀文件:**/*.* -->
<include>**/*.*</include> <include>**/*.*</include>
</includes> </includes>
<excludes> <excludes>
<exclude>**/*.yml</exclude> <exclude>**/*.yml</exclude>
<exclude>**/*.properties</exclude> <exclude>**/*.properties</exclude>
</excludes> </excludes>
<filtering>false</filtering> <filtering>false</filtering>
</resource> </resource>
</resources> </resources>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
</plugin> </plugin>
</plugins> </plugins>
<pluginManagement> <pluginManagement>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<source>${java.version}</source> <source>${java.version}</source>
<target>${java.version}</target> <target>${java.version}</target>
<encoding>${taoyao.maven.encoding}</encoding> <encoding>${taoyao.maven.encoding}</encoding>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<configuration> <configuration>
<!-- Jar配置独立config目录 --> <!-- Jar配置独立config目录 -->
<excludes> <excludes>
<include>*.cer</include> <include>*.cer</include>
<include>*.jks</include> <include>*.jks</include>
<include>*.p12</include> <include>*.p12</include>
<include>*.pfx</include> <include>*.pfx</include>
<exclude>*.yml</exclude> <exclude>*.yml</exclude>
<exclude>*.properties</exclude> <exclude>*.properties</exclude>
</excludes> </excludes>
<archive> <archive>
<manifestEntries> <manifestEntries>
<!-- 配置文件 --> <!-- 配置文件 -->
<Class-Path>../config/</Class-Path> <Class-Path>../config/</Class-Path>
</manifestEntries> </manifestEntries>
</archive> </archive>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>assembly</id> <id>assembly</id>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>single</goal> <goal>single</goal>
</goals> </goals>
<configuration> <configuration>
<attach>false</attach> <attach>false</attach>
<skipAssembly>${taoyao.maven.skip.assembly}</skipAssembly> <skipAssembly>${taoyao.maven.skip.assembly}</skipAssembly>
<appendAssemblyId>false</appendAssemblyId> <appendAssemblyId>false</appendAssemblyId>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
</build> </build>
<profiles> <profiles>
<profile> <profile>
<id>dev</id> <id>dev</id>
<activation> <activation>
<activeByDefault>true</activeByDefault> <activeByDefault>true</activeByDefault>
</activation> </activation>
<properties> <properties>
<profile>dev</profile> <profile>dev</profile>
<taoyao.maven.jvm.arg></taoyao.maven.jvm.arg> <taoyao.maven.jvm.arg></taoyao.maven.jvm.arg>
<taoyao.maven.jvm.mem>-Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem> <taoyao.maven.jvm.mem>-Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem>
</properties> </properties>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<configuration> <configuration>
<descriptors> <descriptors>
<descriptor>${taoyao.maven.basedir}/docs/assembly/dev.xml</descriptor> <descriptor>${taoyao.maven.basedir}/docs/assembly/dev.xml</descriptor>
</descriptors> </descriptors>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version> <version>${springdoc.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
</profile> </profile>
<profile> <profile>
<id>prd</id> <id>prd</id>
<properties> <properties>
<profile>prd</profile> <profile>prd</profile>
<taoyao.maven.jvm.arg></taoyao.maven.jvm.arg> <taoyao.maven.jvm.arg></taoyao.maven.jvm.arg>
<taoyao.maven.jvm.mem>-Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem> <taoyao.maven.jvm.mem>-Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem>
</properties> </properties>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<configuration> <configuration>
<descriptors> <descriptors>
<descriptor>${taoyao.maven.basedir}/docs/assembly/prd.xml</descriptor> <descriptor>${taoyao.maven.basedir}/docs/assembly/prd.xml</descriptor>
</descriptors> </descriptors>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version> <version>${springdoc.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
</profile> </profile>
</profiles> </profiles>
</project> </project>

View File

@@ -118,8 +118,11 @@ public final class NetUtils {
final InetAddress clientAddress = NetUtils.realAddress(clientIP); final InetAddress clientAddress = NetUtils.realAddress(clientIP);
final boolean sourceLocal = NetUtils.localAddress(sourceAddress); final boolean sourceLocal = NetUtils.localAddress(sourceAddress);
final boolean clientLocal = NetUtils.localAddress(clientAddress); final boolean clientLocal = NetUtils.localAddress(clientAddress);
// 内网服务 && 内网设备 // 内网服务 && 内网设备 => 重写服务地址
if(sourceLocal && clientLocal) { if(sourceLocal && clientLocal) {
if(NetUtils.subnetIP(sourceIP, clientIP)) {
return sourceIP;
}
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream() final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP)) .filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP))
.findFirst() .findFirst()
@@ -127,11 +130,10 @@ public final class NetUtils {
if(rule == null) { if(rule == null) {
return sourceIP; return sourceIP;
} }
log.debug("地址重写:{} - {} - {}", sourceIP, clientIP, rule.getNetwork());
// 明确配置
if(StringUtils.isNotEmpty(rule.getInnerHost())) { if(StringUtils.isNotEmpty(rule.getInnerHost())) {
return rule.getInnerHost(); return rule.getInnerHost();
} }
log.debug("地址重写:{} - {} - {}", sourceIP, clientIP, rule.getNetwork());
// 地址 = 网络号 + 主机号 // 地址 = 网络号 + 主机号
final byte[] sourceBytes = sourceAddress.getAddress(); final byte[] sourceBytes = sourceAddress.getAddress();
final byte[] clientBytes = clientAddress.getAddress(); final byte[] clientBytes = clientAddress.getAddress();
@@ -151,7 +153,7 @@ public final class NetUtils {
return InetAddress.getByAddress(bytes).getHostAddress(); return InetAddress.getByAddress(bytes).getHostAddress();
} }
} }
// 内网服务 && 公网设备 // 内网服务 && 公网设备 => 公网服务地址
if(sourceLocal && !clientLocal) { if(sourceLocal && !clientLocal) {
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream() final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), sourceIP)) .filter(v -> NetUtils.subnetIP(v.getNetwork(), sourceIP))
@@ -164,7 +166,7 @@ public final class NetUtils {
return rule.getOuterHost(); return rule.getOuterHost();
} }
} }
// 公网服务 && 内网设备 // 公网服务 && 内网设备 => 内网服务地址
if(!sourceLocal && clientLocal) { if(!sourceLocal && clientLocal) {
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream() final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP)) .filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP))

View File

@@ -2,52 +2,52 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.acgist</groupId> <groupId>com.acgist</groupId>
<artifactId>taoyao</artifactId> <artifactId>taoyao</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</parent> </parent>
<artifactId>taoyao-server</artifactId> <artifactId>taoyao-server</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>taoyao-server</name> <name>taoyao-server</name>
<description>启动服务</description> <description>启动服务</description>
<properties> <properties>
<taoyao.maven.basedir>${project.parent.basedir}</taoyao.maven.basedir> <taoyao.maven.basedir>${project.parent.basedir}</taoyao.maven.basedir>
<taoyao.maven.skip.assembly>false</taoyao.maven.skip.assembly> <taoyao.maven.skip.assembly>false</taoyao.maven.skip.assembly>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.acgist</groupId> <groupId>com.acgist</groupId>
<artifactId>taoyao-signal</artifactId> <artifactId>taoyao-signal</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hibernate.validator</groupId> <groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
<mainClass>com.acgist.taoyao.main.TaoyaoApplication</mainClass> <mainClass>com.acgist.taoyao.main.TaoyaoApplication</mainClass>
<addClasspath>true</addClasspath> <addClasspath>true</addClasspath>
<classpathPrefix>./</classpathPrefix> <classpathPrefix>./</classpathPrefix>
</manifest> </manifest>
</archive> </archive>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@@ -22,29 +22,29 @@ import com.acgist.taoyao.signal.service.impl.SecurityServiceImpl;
@AutoConfiguration @AutoConfiguration
public class TaoyaoAutoConfiguration { public class TaoyaoAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SlowInterceptor slowInterceptor(TaoyaoProperties taoyaoProperties) { public SlowInterceptor slowInterceptor(TaoyaoProperties taoyaoProperties) {
return new SlowInterceptor(taoyaoProperties); return new SlowInterceptor(taoyaoProperties);
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SecurityService securityService( public SecurityService securityService(
SecurityProperties securityProperties, @Autowired(required = true) SecurityProperties securityProperties,
@Autowired(required = false) UsernamePasswordService usernamePasswordService @Autowired(required = false) UsernamePasswordService usernamePasswordService
) { ) {
return new SecurityServiceImpl(securityProperties, usernamePasswordService); return new SecurityServiceImpl(securityProperties, usernamePasswordService);
} }
@Bean @Bean
@ConditionalOnProperty(prefix = "taoyao.security", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = "taoyao.security", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SecurityInterceptor securityInterceptor( public SecurityInterceptor securityInterceptor(
SecurityService securityService, SecurityService securityService,
SecurityProperties securityProperties SecurityProperties securityProperties
) { ) {
return new SecurityInterceptor(securityService, securityProperties); return new SecurityInterceptor(securityService, securityProperties);
} }
} }

View File

@@ -5,8 +5,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.acgist.taoyao.boot.config.FfmpegProperties; import com.acgist.taoyao.boot.config.FfmpegProperties;
import com.acgist.taoyao.boot.config.RewriteProperties;
import com.acgist.taoyao.boot.config.MediaProperties; import com.acgist.taoyao.boot.config.MediaProperties;
import com.acgist.taoyao.boot.config.RewriteProperties;
import com.acgist.taoyao.boot.config.SocketProperties; import com.acgist.taoyao.boot.config.SocketProperties;
import com.acgist.taoyao.boot.config.WebrtcProperties; import com.acgist.taoyao.boot.config.WebrtcProperties;
import com.acgist.taoyao.boot.model.Message; import com.acgist.taoyao.boot.model.Message;
@@ -29,18 +29,18 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ConfigController { public class ConfigController {
private final MediaProperties mediaProperties; private final MediaProperties mediaProperties;
private final FfmpegProperties ffmpegProperties; private final FfmpegProperties ffmpegProperties;
private final SocketProperties socketProperties; private final SocketProperties socketProperties;
private final WebrtcProperties webrtcProperties; private final WebrtcProperties webrtcProperties;
private final RewriteProperties rewriteProperties; private final RewriteProperties rewriteProperties;
@Operation(summary = "媒体配置", description = "媒体配置") @Operation(summary = "媒体配置", description = "媒体配置")
@GetMapping("/media") @GetMapping("/media")
@ApiResponse(content = @Content(schema = @Schema(implementation = MediaProperties.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = MediaProperties.class)))
public Message media() { public Message media() {
return Message.success(this.mediaProperties); return Message.success(this.mediaProperties);
} }
@Operation(summary = "FFmpeg配置", description = "FFmpeg配置") @Operation(summary = "FFmpeg配置", description = "FFmpeg配置")
@GetMapping("/ffmpeg") @GetMapping("/ffmpeg")
@@ -55,19 +55,19 @@ public class ConfigController {
public Message socket() { public Message socket() {
return Message.success(this.socketProperties); return Message.success(this.socketProperties);
} }
@Operation(summary = "WebRTC配置", description = "WebRTC配置") @Operation(summary = "WebRTC配置", description = "WebRTC配置")
@GetMapping("/webrtc") @GetMapping("/webrtc")
@ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class)))
public Message webrtc() { public Message webrtc() {
return Message.success(this.webrtcProperties); return Message.success(this.webrtcProperties);
} }
@Operation(summary = "地址重写配置", description = "地址重写配置") @Operation(summary = "地址重写配置", description = "地址重写配置")
@GetMapping("/rewrite") @GetMapping("/rewrite")
@ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class)))
public Message rewrite() { public Message rewrite() {
return Message.success(this.rewriteProperties); return Message.success(this.rewriteProperties);
} }
} }

View File

@@ -17,6 +17,7 @@ import com.acgist.taoyao.signal.protocol.control.IControlPhotographProtocol;
import com.acgist.taoyao.signal.protocol.control.IControlServerRecordProtocol; import com.acgist.taoyao.signal.protocol.control.IControlServerRecordProtocol;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@@ -34,31 +35,22 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ControlController { public class ControlController {
private final IControlBellProtocol controlBellProtocol; private final IControlBellProtocol controlBellProtocol;
private final IControlPhotographProtocol controlPhotographProtocol; private final IControlPhotographProtocol controlPhotographProtocol;
private final IControlConfigAudioProtocol controlConfigAudioProtocol; private final IControlConfigAudioProtocol controlConfigAudioProtocol;
private final IControlConfigVideoProtocol controlConfigVideoProtocol; private final IControlConfigVideoProtocol controlConfigVideoProtocol;
private final IControlClientRecordProtocol controlClientRecordProtocol; private final IControlClientRecordProtocol controlClientRecordProtocol;
private final IControlServerRecordProtocol controlServerRecordProtocol; private final IControlServerRecordProtocol controlServerRecordProtocol;
@Operation(summary = "响铃", description = "响铃控制") @Operation(summary = "响铃", description = "响铃控制")
@GetMapping("/bell/{clientId}") @GetMapping("/bell/{clientId}")
public Message bell(@PathVariable String clientId, @NotNull(message = "没有指定操作状态") Boolean enabled) { public Message bell(
@PathVariable String clientId,
@NotNull(message = "没有指定操作状态") Boolean enabled
) {
return this.controlBellProtocol.execute(clientId, enabled); return this.controlBellProtocol.execute(clientId, enabled);
} }
@Operation(summary = "录像", description = "终端录像控制")
@GetMapping("/client/record/{clientId}")
public Message record(@PathVariable String clientId, @NotNull(message = "没有指定操作状态") Boolean enabled) {
return this.controlClientRecordProtocol.execute(clientId, enabled);
}
@Operation(summary = "录像", description = "服务端录像控制")
@GetMapping("/server/record/{roomId}/{clientId}")
public Message record(@PathVariable String roomId, @PathVariable String clientId, @NotNull(message = "没有指定操作状态") Boolean enabled) {
return this.controlServerRecordProtocol.execute(roomId, clientId, enabled);
}
@Operation(summary = "拍照", description = "拍照控制") @Operation(summary = "拍照", description = "拍照控制")
@GetMapping("/photograph/{clientId}") @GetMapping("/photograph/{clientId}")
public Message photograph(@PathVariable String clientId) { public Message photograph(@PathVariable String clientId) {
@@ -67,14 +59,39 @@ public class ControlController {
@Operation(summary = "配置音频", description = "配置音频") @Operation(summary = "配置音频", description = "配置音频")
@GetMapping("/config/audio/{clientId}") @GetMapping("/config/audio/{clientId}")
public Message configAudio(@PathVariable String clientId, @Valid MediaAudioProperties mediaAudioProperties) { public Message configAudio(
@PathVariable String clientId,
@Valid @RequestBody MediaAudioProperties mediaAudioProperties
) {
return this.controlConfigAudioProtocol.execute(clientId, mediaAudioProperties); return this.controlConfigAudioProtocol.execute(clientId, mediaAudioProperties);
} }
@Operation(summary = "配置视频", description = "配置视频") @Operation(summary = "配置视频", description = "配置视频")
@GetMapping("/config/video/{clientId}") @GetMapping("/config/video/{clientId}")
public Message configVideo(@PathVariable String clientId, @Valid MediaVideoProperties mediaVideoProperties) { public Message configVideo(
@PathVariable String clientId,
@Valid @RequestBody MediaVideoProperties mediaVideoProperties
) {
return this.controlConfigVideoProtocol.execute(clientId, mediaVideoProperties); return this.controlConfigVideoProtocol.execute(clientId, mediaVideoProperties);
} }
@Operation(summary = "录像", description = "终端录像控制")
@GetMapping("/client/record/{clientId}")
public Message record(
@PathVariable String clientId,
@NotNull(message = "没有指定操作状态") Boolean enabled
) {
return this.controlClientRecordProtocol.execute(clientId, enabled);
}
@Operation(summary = "录像", description = "服务端录像控制")
@GetMapping("/server/record/{roomId}/{clientId}")
public Message record(
@PathVariable String roomId,
@PathVariable String clientId,
@NotNull(message = "没有指定操作状态") Boolean enabled
) {
return this.controlServerRecordProtocol.execute(roomId, clientId, enabled);
}
} }

View File

@@ -25,14 +25,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@RequestMapping("/platform") @RequestMapping("/platform")
public class PlatformController { public class PlatformController {
private final PlatformRebootProtocol platformRebootProtocol; private final PlatformRebootProtocol platformRebootProtocol;
private final PlatformShutdownProtocol platformShutdownProtocol; private final PlatformShutdownProtocol platformShutdownProtocol;
public PlatformController( public PlatformController(
@Autowired(required = false) PlatformRebootProtocol platformRebootProtocol, @Autowired(required = false) PlatformRebootProtocol platformRebootProtocol,
@Autowired(required = false) PlatformShutdownProtocol platformShutdownProtocol @Autowired(required = false) PlatformShutdownProtocol platformShutdownProtocol
) { ) {
this.platformRebootProtocol = platformRebootProtocol; this.platformRebootProtocol = platformRebootProtocol;
this.platformShutdownProtocol = platformShutdownProtocol; this.platformShutdownProtocol = platformShutdownProtocol;
} }

View File

@@ -25,14 +25,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@RequestMapping("/system") @RequestMapping("/system")
public class SystemController { public class SystemController {
private final SystemRebootProtocol systemRebootProtocol; private final SystemRebootProtocol systemRebootProtocol;
private final SystemShutdownProtocol systemShutdownProtocol; private final SystemShutdownProtocol systemShutdownProtocol;
public SystemController( public SystemController(
@Autowired(required = false) SystemRebootProtocol systemRebootProtocol, @Autowired(required = false) SystemRebootProtocol systemRebootProtocol,
@Autowired(required = false) SystemShutdownProtocol systemShutdownProtocol @Autowired(required = false) SystemShutdownProtocol systemShutdownProtocol
) { ) {
this.systemRebootProtocol = systemRebootProtocol; this.systemRebootProtocol = systemRebootProtocol;
this.systemShutdownProtocol = systemShutdownProtocol; this.systemShutdownProtocol = systemShutdownProtocol;
} }

View File

@@ -24,96 +24,99 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class SecurityInterceptor extends InterceptorAdapter { public class SecurityInterceptor extends InterceptorAdapter {
private final SecurityService securityService; private final SecurityService securityService;
private final SecurityProperties securityProperties; private final SecurityProperties securityProperties;
/** /**
* 鉴权信息 * 鉴权信息
*/ */
private final String authenticate; private final String authenticate;
/** /**
* 地址匹配 * 地址匹配
*/ */
private final AntPathMatcher matcher; private final AntPathMatcher matcher;
public SecurityInterceptor(SecurityService securityService, SecurityProperties securityProperties) { public SecurityInterceptor(
SecurityService securityService,
SecurityProperties securityProperties
) {
this.securityService = securityService; this.securityService = securityService;
this.securityProperties = securityProperties; this.securityProperties = securityProperties;
this.authenticate = "Basic Realm=\"" + this.securityProperties.getRealm() + "\""; this.authenticate = "Basic Realm=\"" + this.securityProperties.getRealm() + "\"";
this.matcher = new AntPathMatcher(); this.matcher = new AntPathMatcher();
log.info("安全拦截密码:{}", securityProperties.getPassword()); log.info("安全拦截密码:{}", securityProperties.getPassword());
} }
@Override @Override
public String name() { public String name() {
return "安全拦截器"; return "安全拦截器";
} }
@Override @Override
public String[] pathPattern() { public String[] pathPattern() {
return new String[] { "/**" }; return new String[] { "/**" };
} }
@Override @Override
public int getOrder() { public int getOrder() {
return Integer.MIN_VALUE + 1; return Integer.MIN_VALUE + 1;
} }
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(this.permit(request) || this.authorization(request)) { if(this.permit(request) || this.authorization(request)) {
return true; return true;
} }
if(log.isDebugEnabled()) { if(log.isDebugEnabled()) {
log.debug("授权失败:{}", request.getRequestURL()); log.debug("授权失败:{}", request.getRequestURL());
} }
response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, this.authenticate); response.setHeader(HttpHeaders.WWW_AUTHENTICATE, this.authenticate);
return false; return false;
} }
/** /**
* @param request 请求 * @param request 请求
* *
* @return 是否许可请求 * @return 是否许可请求
*/ */
private boolean permit(HttpServletRequest request) { private boolean permit(HttpServletRequest request) {
final String uri = request.getRequestURI(); final String uri = request.getRequestURI();
final String[] permit = this.securityProperties.getPermit(); final String[] permit = this.securityProperties.getPermit();
if(ArrayUtils.isEmpty(permit)) { if(ArrayUtils.isEmpty(permit)) {
return false; return false;
} }
for (String pattern : permit) { for (String pattern : permit) {
if(this.matcher.match(pattern, uri)) { if(this.matcher.match(pattern, uri)) {
return true; return true;
} }
} }
return false; return false;
} }
/** /**
* @param request 请求 * @param request 请求
* *
* @return 是否授权成功 * @return 是否授权成功
*/ */
private boolean authorization(HttpServletRequest request) { private boolean authorization(HttpServletRequest request) {
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION); String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
if(StringUtils.isEmpty(authorization)) { if(StringUtils.isEmpty(authorization)) {
return false; return false;
} }
int index = authorization.indexOf(' '); int index = authorization.indexOf(' ');
if(index < 0) { if(index < 0) {
return false; return false;
} }
authorization = authorization.substring(index + 1).strip(); authorization = authorization.substring(index + 1).strip();
authorization = new String(Base64.getMimeDecoder().decode(authorization)); authorization = new String(Base64.getMimeDecoder().decode(authorization));
index = authorization.indexOf(':'); index = authorization.indexOf(':');
if(index < 0) { if(index < 0) {
return false; return false;
} }
final String username = authorization.substring(0, index); final String username = authorization.substring(0, index);
final String password = authorization.substring(index + 1); final String password = authorization.substring(index + 1);
return this.securityService.authenticate(username, password); return this.securityService.authenticate(username, password);
} }
} }

View File

@@ -14,48 +14,47 @@ import lombok.extern.slf4j.Slf4j;
*/ */
@Slf4j @Slf4j
public class SlowInterceptor extends InterceptorAdapter { public class SlowInterceptor extends InterceptorAdapter {
private final TaoyaoProperties taoyaoProperties; private final TaoyaoProperties taoyaoProperties;
/** /**
* 请求开始时间 * 请求开始时间
*/ */
private final ThreadLocal<Long> local; private final ThreadLocal<Long> local;
public SlowInterceptor(TaoyaoProperties taoyaoProperties) { public SlowInterceptor(TaoyaoProperties taoyaoProperties) {
this.taoyaoProperties = taoyaoProperties; this.taoyaoProperties = taoyaoProperties;
this.local = new ThreadLocal<>(); this.local = new ThreadLocal<>();
} }
@Override @Override
public String name() { public String name() {
return "过慢请求拦截器"; return "过慢请求拦截器";
} }
@Override @Override
public String[] pathPattern() { public String[] pathPattern() {
return new String[] { "/**" }; return new String[] { "/**" };
} }
@Override @Override
public int getOrder() { public int getOrder() {
return Integer.MIN_VALUE; return Integer.MIN_VALUE;
} }
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
this.local.set(System.currentTimeMillis()); this.local.set(System.currentTimeMillis());
return true; return true;
} }
@Override @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception { public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {
final long duration; final long duration = System.currentTimeMillis() - this.local.get();
final Long last = this.local.get(); if(duration > this.taoyaoProperties.getTimeout()) {
if(last != null && (duration = System.currentTimeMillis() - last) > this.taoyaoProperties.getTimeout()) { log.info("请求执行时间过慢:{} - {}", request.getRequestURI(), duration);
log.info("请求执行时间过慢:{} - {}", request.getRequestURI(), duration); }
} this.local.remove();
this.local.remove(); }
}
} }

View File

@@ -8,8 +8,8 @@ import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication @SpringBootApplication
public class TaoyaoApplication { public class TaoyaoApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(TaoyaoApplication.class, args); SpringApplication.run(TaoyaoApplication.class, args);
} }
} }

View File

@@ -1,15 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>桃夭信令服务</title> <title>桃夭信令服务</title>
<style type="text/css"> <style type="text/css">
p{text-align:center;} p{text-align:center;}
a{text-decoration:none;} a{text-decoration:none;}
</style> </style>
</head> </head>
<body> <body>
<p><a href="https://gitee.com/acgist/taoyao">taoyao-signal-server</a></p> <p><a href="https://gitee.com/acgist/taoyao">taoyao-signal-server</a></p>
<p><a href="https://www.acgist.com">acgist</a></p> <p><a href="https://www.acgist.com">acgist</a></p>
</body> </body>
</html> </html>

View File

@@ -19,29 +19,29 @@ import java.util.concurrent.TimeUnit;
@Documented @Documented
public @interface CostedTest { public @interface CostedTest {
/** /**
* @return 执行次数 * @return 执行次数
*/ */
int count() default 1; int count() default 1;
/** /**
* @return 线程数量 * @return 线程数量
*/ */
int thread() default 1; int thread() default 1;
/** /**
* @return 超时时间 * @return 超时时间
*/ */
long timeout() default 1000L; long timeout() default 1000L;
/** /**
* @return 等待资源释放时间 * @return 等待资源释放时间
*/ */
long waitRelease() default 0L; long waitRelease() default 0L;
/** /**
* @return 超时时间单位 * @return 超时时间单位
*/ */
TimeUnit timeUnit() default TimeUnit.MILLISECONDS; TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
} }

View File

@@ -18,46 +18,46 @@ import lombok.extern.slf4j.Slf4j;
*/ */
@Slf4j @Slf4j
public class CostedTestTestExecutionListener implements TestExecutionListener { public class CostedTestTestExecutionListener implements TestExecutionListener {
@Override @Override
public void afterTestMethod(TestContext testContext) throws Exception { public void afterTestMethod(TestContext testContext) throws Exception {
final CostedTest costedTest = testContext.getTestMethod().getDeclaredAnnotation(CostedTest.class); final CostedTest costedTest = testContext.getTestMethod().getDeclaredAnnotation(CostedTest.class);
if(costedTest == null) { if(costedTest == null) {
return; return;
} }
final int count = costedTest.count(); final int count = costedTest.count();
final int thread = costedTest.thread(); final int thread = costedTest.thread();
final long timeout = costedTest.timeout(); final long timeout = costedTest.timeout();
final TimeUnit timeUnit = costedTest.timeUnit(); final TimeUnit timeUnit = costedTest.timeUnit();
final long aTime = System.currentTimeMillis(); final long aTime = System.currentTimeMillis();
if(thread == 1) { if(thread == 1) {
for (int index = 0; index < count; index++) { for (int index = 0; index < count; index++) {
testContext.getTestMethod().invoke(testContext.getTestInstance()); testContext.getTestMethod().invoke(testContext.getTestInstance());
} }
} else { } else {
final CountDownLatch countDownLatch = new CountDownLatch(count); final CountDownLatch countDownLatch = new CountDownLatch(count);
final ExecutorService executor = Executors.newFixedThreadPool(thread); final ExecutorService executor = Executors.newFixedThreadPool(thread);
for (int index = 0; index < count; index++) { for (int index = 0; index < count; index++) {
executor.execute(() -> { executor.execute(() -> {
try { try {
testContext.getTestMethod().invoke(testContext.getTestInstance()); testContext.getTestMethod().invoke(testContext.getTestInstance());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
log.error("多线程测试异常", e); log.error("多线程测试异常", e);
} finally { } finally {
countDownLatch.countDown(); countDownLatch.countDown();
} }
}); });
} }
countDownLatch.await(timeout, timeUnit); countDownLatch.await(timeout, timeUnit);
executor.shutdown(); executor.shutdown();
} }
final long zTime = System.currentTimeMillis(); final long zTime = System.currentTimeMillis();
final long costed = zTime - aTime; final long costed = zTime - aTime;
log.info("多线程测试消耗时间:{}", costed); log.info("多线程测试消耗时间:{}", costed);
final long waitRelease = costedTest.waitRelease(); final long waitRelease = costedTest.waitRelease();
if(waitRelease > 0) { if(waitRelease > 0) {
Thread.sleep(waitRelease); Thread.sleep(waitRelease);
} }
} }
} }

View File

@@ -25,7 +25,7 @@ import org.springframework.test.context.TestExecutionListeners.MergeMode;
@TestExecutionListeners(listeners = CostedTestTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS) @TestExecutionListeners(listeners = CostedTestTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public @interface TaoyaoTest { public @interface TaoyaoTest {
@AliasFor(annotation = SpringBootTest.class) @AliasFor(annotation = SpringBootTest.class)
Class<?>[] classes() default {}; Class<?>[] classes() default {};
} }

View File

@@ -21,99 +21,99 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class RtpTest { public class RtpTest {
@Test @Test
void testSocket() throws Exception { void testSocket() throws Exception {
final Socket socket = new Socket(); final Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1", 9999)); socket.connect(new InetSocketAddress("127.0.0.1", 9999));
final InputStream inputStream = socket.getInputStream(); final InputStream inputStream = socket.getInputStream();
final OutputStream outputStream = socket.getOutputStream(); final OutputStream outputStream = socket.getOutputStream();
// 随机密码https://localhost:8888/config/socket // 随机密码https://localhost:8888/config/socket
final String secret = "TSFXzB7hcfE=".strip(); final String secret = "TSFXzB7hcfE=".strip();
final Cipher encrypt = CipherUtils.buildCipher(Cipher.ENCRYPT_MODE, Encrypt.DES, secret); final Cipher encrypt = CipherUtils.buildCipher(Cipher.ENCRYPT_MODE, Encrypt.DES, secret);
final Cipher decrypt = CipherUtils.buildCipher(Cipher.DECRYPT_MODE, Encrypt.DES, secret); final Cipher decrypt = CipherUtils.buildCipher(Cipher.DECRYPT_MODE, Encrypt.DES, secret);
// 接收 // 接收
new Thread(() -> { new Thread(() -> {
int length = 0; int length = 0;
short messageLength = 0; short messageLength = 0;
final byte[] bytes = new byte[1024]; final byte[] bytes = new byte[1024];
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
try { try {
while((length = inputStream.read(bytes)) >= 0) { while((length = inputStream.read(bytes)) >= 0) {
buffer.put(bytes, 0, length); buffer.put(bytes, 0, length);
while(buffer.position() > 0) { while(buffer.position() > 0) {
if(messageLength <= 0) { if(messageLength <= 0) {
if(buffer.position() < Short.BYTES) { if(buffer.position() < Short.BYTES) {
// 不够消息长度 // 不够消息长度
break; break;
} else { } else {
buffer.flip(); buffer.flip();
messageLength = buffer.getShort(); messageLength = buffer.getShort();
buffer.compact(); buffer.compact();
if(messageLength > 16 * 1024) { if(messageLength > 16 * 1024) {
throw MessageCodeException.of("超过最大数据大小:" + messageLength); throw MessageCodeException.of("超过最大数据大小:" + messageLength);
} }
} }
} else { } else {
if(buffer.position() < messageLength) { if(buffer.position() < messageLength) {
// 不够消息长度 // 不够消息长度
break; break;
} else { } else {
final byte[] message = new byte[messageLength]; final byte[] message = new byte[messageLength];
messageLength = 0; messageLength = 0;
buffer.flip(); buffer.flip();
buffer.get(message); buffer.get(message);
buffer.compact(); buffer.compact();
log.debug("收到消息:{}", new String(decrypt.doFinal(message))); log.debug("收到消息:{}", new String(decrypt.doFinal(message)));
} }
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("读取异常", e); log.error("读取异常", e);
} }
}).start(); }).start();
// 发送 // 发送
String line = """ String line = """
{ {
"header":{"v":"1.0.0","id":1215293599999001,"signal":"client::register"}, "header":{"v":"1.0.0","id":1215293599999001,"signal":"client::register"},
"body":{"clientId":"ffmpeg","name":"ffmpeg","clientType":"WEB","battery":100,"charging":true,"username":"taoyao","password":"taoyao"} "body":{"clientId":"ffmpeg","name":"ffmpeg","clientType":"WEB","battery":100,"charging":true,"username":"taoyao","password":"taoyao"}
} }
"""; """;
// {"header":{"v":"1.0.0","id":1215310510002009,"signal":"room::enter"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9"}} // {"header":{"v":"1.0.0","id":1215310510002009,"signal":"room::enter"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9"}}
// {"header":{"v":"1.0.0","id":1215310510002010,"signal":"media::transport::plain"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","rtcpMux":false,"comedia":true}} // {"header":{"v":"1.0.0","id":1215310510002010,"signal":"media::transport::plain"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","rtcpMux":false,"comedia":true}}
// {"header":{"v":"1.0.0","id":1215375110006012,"signal":"media::produce"},"body":{"kind":"video","roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","transportId":"14dc9307-bf9c-4442-a9ad-ce6a97623ef4","appData":{},"rtpParameters":{"codecs":[{"mimeType":"video/vp8","clockRate":90000,"payloadType":102,"rtcpFeedback":[]}],"encodings":[{"ssrc":123123}]}}} // {"header":{"v":"1.0.0","id":1215375110006012,"signal":"media::produce"},"body":{"kind":"video","roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","transportId":"14dc9307-bf9c-4442-a9ad-ce6a97623ef4","appData":{},"rtpParameters":{"codecs":[{"mimeType":"video/vp8","clockRate":90000,"payloadType":102,"rtcpFeedback":[]}],"encodings":[{"ssrc":123123}]}}}
// 音频转为PCM // 音频转为PCM
// ffmpeg.exe -i .\a.m4a -f s16le a.pcm // ffmpeg.exe -i .\a.m4a -f s16le a.pcm
// ffmpeg.exe -i .\a.m4a -f s16le -ac 2 -ar 8000 a.pcm // ffmpeg.exe -i .\a.m4a -f s16le -ac 2 -ar 8000 a.pcm
// ffplay.exe -ar 48000 -ac 2 -f s16le -i a.pcm // ffplay.exe -ar 48000 -ac 2 -f s16le -i a.pcm
// ffmpeg不支持rtcpMux // ffmpeg不支持rtcpMux
// ffmpeg -re -i video.mp4 -c:v vp8 -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218" // ffmpeg -re -i video.mp4 -c:v vp8 -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
// ffmpeg -re -i video.mp4 -c:v libvpx -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218" // ffmpeg -re -i video.mp4 -c:v libvpx -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
// 音频视频同时传输 // 音频视频同时传输
// ffmpeg -re -i video.mp4 -c:a libopus -vn -f rtp rtp://192.168.1.110:8888 -c:v libx264 -an -f rtp rtp://192.168.1.110:9999 -sdp_file taoyao.sdp // ffmpeg -re -i video.mp4 -c:a libopus -vn -f rtp rtp://192.168.1.110:8888 -c:v libx264 -an -f rtp rtp://192.168.1.110:9999 -sdp_file taoyao.sdp
// ffplay -protocol_whitelist "file,rtp,udp" -i taoyao.sdp // ffplay -protocol_whitelist "file,rtp,udp" -i taoyao.sdp
// ffmpeg -protocol_whitelist "file,rtp,udp" -i taoyao.sdp taoyao.mp4 // ffmpeg -protocol_whitelist "file,rtp,udp" -i taoyao.sdp taoyao.mp4
final Scanner scanner = new Scanner(System.in); final Scanner scanner = new Scanner(System.in);
do { do {
if(StringUtils.isEmpty(line)) { if(StringUtils.isEmpty(line)) {
break; break;
} }
try { try {
final byte[] bytes = line.getBytes(); final byte[] bytes = line.getBytes();
final byte[] encryptBytes = encrypt.doFinal(bytes); final byte[] encryptBytes = encrypt.doFinal(bytes);
final ByteBuffer buffer = ByteBuffer.allocateDirect(Short.BYTES + encryptBytes.length); final ByteBuffer buffer = ByteBuffer.allocateDirect(Short.BYTES + encryptBytes.length);
buffer.putShort((short) encryptBytes.length); buffer.putShort((short) encryptBytes.length);
buffer.put(encryptBytes); buffer.put(encryptBytes);
buffer.flip(); buffer.flip();
final byte[] message = new byte[buffer.capacity()]; final byte[] message = new byte[buffer.capacity()];
buffer.get(message); buffer.get(message);
outputStream.write(message); outputStream.write(message);
} catch (Exception e) { } catch (Exception e) {
log.error("发送异常", e); log.error("发送异常", e);
} }
} while((line = scanner.next()) != null); } while((line = scanner.next()) != null);
socket.close(); socket.close();
scanner.close(); scanner.close();
} }
} }

View File

@@ -15,29 +15,29 @@ import lombok.extern.slf4j.Slf4j;
//@SpringBootTest(classes = TaoyaoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) //@SpringBootTest(classes = TaoyaoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class IdServiceTest { class IdServiceTest {
@Autowired @Autowired
private IdService idService; private IdService idService;
@Test @Test
// @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS) // @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
// @Rollback() // @Rollback()
// @RepeatedTest(10) // @RepeatedTest(10)
void testId() { void testId() {
final long id = this.idService.buildId(); final long id = this.idService.buildId();
log.info("生成ID{}", id); log.info("生成ID{}", id);
log.info("生成ID{}", String.valueOf(id).length()); log.info("生成ID{}", String.valueOf(id).length());
} }
@Test @Test
@CostedTest(count = 100000, thread = 10) @CostedTest(count = 100000, thread = 10)
void testIdCosted() { void testIdCosted() {
this.idService.buildId(); this.idService.buildId();
} }
@Test @Test
@CostedTest(count = 100000, thread = 10) @CostedTest(count = 100000, thread = 10)
void testUuidCosted() { void testUuidCosted() {
this.idService.buildUuid(); this.idService.buildUuid();
} }
} }