[+] 结构调整

This commit is contained in:
acgist
2023-02-22 07:42:40 +08:00
parent a4696a9b9b
commit 6358255458
103 changed files with 1056 additions and 250 deletions

View File

@@ -10,13 +10,11 @@ import org.springframework.stereotype.Component;
/**
* 信令描述
* 生成文档采用`RUNTIME`
*
* @author acgist
*/
@Target(ElementType.TYPE)
@Component
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Description {

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
/**
* 字符常量
@@ -95,10 +95,6 @@ public interface Constant {
* 密码
*/
String PASSWORD = "password";
/**
* 时间
*/
String TIME = "time";
/**
* 媒体
*/
@@ -107,6 +103,10 @@ public interface Constant {
* WebRTC
*/
String WEBRTC = "webrtc";
/**
* 日期时间
*/
String DATETIME = "datetime";
/**
* PeerId
*
@@ -151,9 +151,25 @@ public interface Constant {
* 数据消费者ID
*/
String DATA_CONSUMER_ID = "dataConsumerId";
/**
* ICE服务P2P直连使用
*/
String ICE_SERVERS = "iceServers";
/**
* ICE候选
*/
String ICE_CANDIDATES = "iceCandidates";
/**
* ICE参数
*/
String ICE_PARAMETERS = "iceParameters";
/**
* DTLS参数
*/
String DTLS_PARAMETERS = "dtlsParameters";
/**
* SCTP参数
*/
String SCTP_PARAMETERS = "sctpParameters";
}

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
@@ -18,6 +18,8 @@ public class MediaServerProperties {
private String mediaId;
@Schema(title = "是否启用", description = "是否启用")
private Boolean enabled;
@Schema(title = "是否启用重写本地IP", description = "内外网多网卡环境重写IP地址")
private Boolean rewriteIp;
@Schema(title = "主机", description = "主机")
private String host;
@Schema(title = "端口", description = "端口")

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import java.util.LinkedHashMap;
import java.util.Map;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -8,6 +8,7 @@ import lombok.Setter;
/**
* 安全配置
* 注意没有配置`UsernamePasswordService`使用帐号密码
*
* @author acgist
*/

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -25,6 +25,8 @@ public class TaoyaoProperties {
private String version;
@Schema(title = "项目描述", description = "项目描述")
private String description;
@Schema(title = "子网掩码", description = "子网掩码")
private Integer ipMask;
@Schema(title = "超时时间", description = "超时时间")
private Long timeout;

View File

@@ -1,4 +1,4 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import java.util.ArrayList;
import java.util.HashMap;
@@ -13,6 +13,7 @@ import lombok.Setter;
/**
* WebRTC配置
* P2P视频监控会用正常会议不会使用需要自己搭建`coturn`服务
*
* @author acgist
*/

View File

@@ -1,6 +1,7 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -12,6 +13,7 @@ import lombok.Setter;
@Getter
@Setter
@Schema(title = "WebRTC STUN配置", description = "WebRTC STUN配置")
@EqualsAndHashCode(of = { "host", "port" })
public class WebrtcStunProperties {
@Schema(title = "主机", description = "主机")

View File

@@ -1,6 +1,7 @@
package com.acgist.taoyao.boot.property;
package com.acgist.taoyao.boot.config;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -12,6 +13,7 @@ import lombok.Setter;
@Getter
@Setter
@Schema(title = "WebRTC TURN配置", description = "WebRTC TURN配置")
@EqualsAndHashCode(callSuper = true)
public class WebrtcTurnProperties extends WebrtcStunProperties {
@Schema(title = "帐号", description = "帐号")

View File

@@ -45,18 +45,21 @@ import org.springframework.web.context.request.async.AsyncRequestTimeoutExceptio
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.acgist.taoyao.boot.config.IdProperties;
import com.acgist.taoyao.boot.config.MediaProperties;
import com.acgist.taoyao.boot.config.ScriptProperties;
import com.acgist.taoyao.boot.config.SecurityProperties;
import com.acgist.taoyao.boot.config.SocketProperties;
import com.acgist.taoyao.boot.config.TaoyaoProperties;
import com.acgist.taoyao.boot.config.WebrtcProperties;
import com.acgist.taoyao.boot.controller.TaoyaoControllerAdvice;
import com.acgist.taoyao.boot.controller.TaoyaoErrorController;
import com.acgist.taoyao.boot.model.MessageCode;
import com.acgist.taoyao.boot.property.IdProperties;
import com.acgist.taoyao.boot.property.MediaProperties;
import com.acgist.taoyao.boot.property.ScriptProperties;
import com.acgist.taoyao.boot.property.SecurityProperties;
import com.acgist.taoyao.boot.property.SocketProperties;
import com.acgist.taoyao.boot.property.TaoyaoProperties;
import com.acgist.taoyao.boot.property.WebrtcProperties;
import com.acgist.taoyao.boot.runner.OrderedCommandLineRunner;
import com.acgist.taoyao.boot.service.IdService;
import com.acgist.taoyao.boot.service.IpService;
import com.acgist.taoyao.boot.service.impl.IdServiceImpl;
import com.acgist.taoyao.boot.service.impl.IpServiceImpl;
import com.acgist.taoyao.boot.utils.ErrorUtils;
import com.acgist.taoyao.boot.utils.FileUtils;
import com.acgist.taoyao.boot.utils.HTTPUtils;
@@ -103,6 +106,12 @@ public class BootAutoConfiguration {
return new IdServiceImpl();
}
@Bean
@ConditionalOnMissingBean
public IpService ipService() {
return new IpServiceImpl();
}
@Bean
@Primary
@ConditionalOnMissingBean
@@ -142,10 +151,15 @@ public class BootAutoConfiguration {
TaskExecutor taskExecutor,
TaoyaoProperties taoyaoProperties
) {
return new CommandLineRunner() {
return new OrderedCommandLineRunner() {
@Override
public int getOrder() {
return Integer.MAX_VALUE;
}
@Override
public void run(String ... args) throws Exception {
HTTPUtils.init(taoyaoProperties.getTimeout(), taskExecutor);
BootAutoConfiguration.this.registerException();
log.info("项目启动成功:{}", BootAutoConfiguration.this.name);
}
};
@@ -181,7 +195,6 @@ public class BootAutoConfiguration {
this.applicationContext.getBeansOfType(TaskScheduler.class).forEach((k, v) -> {
log.info("系统定时任务线程池:{}-{}", k, v);
});
this.registerException();
}
/**

View File

@@ -11,7 +11,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import com.acgist.taoyao.boot.property.TaoyaoProperties;
import com.acgist.taoyao.boot.config.TaoyaoProperties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
@@ -26,7 +26,7 @@ import io.swagger.v3.oas.models.security.SecurityScheme;
*
* @author acgist
*/
@Profile({ "dev", "local" })
@Profile({ "dev", "sit" })
@Configuration
@ConditionalOnClass(OpenAPI.class)
public class SpringDocAutoConfiguration {

View File

@@ -0,0 +1,18 @@
package com.acgist.taoyao.boot.runner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
/**
* Ordered + CommandLineRunner
*
* @author acgist
*/
public interface OrderedCommandLineRunner extends Ordered, CommandLineRunner {
@Override
default int getOrder() {
return 0;
}
}

View File

@@ -0,0 +1,48 @@
package com.acgist.taoyao.boot.service;
/**
* 内外网多网卡环境IP服务
* 支持配置域名
*
* @author acgist
*/
public interface IpService {
/**
* @see #subnetIp(String, String, String)
*/
default boolean subnetIp(String sourceIp, String clientIp) {
return this.subnetIp(sourceIp, clientIp, null);
}
/**
* 内网是否相同网段
*
* @param sourceIp 原始IP
* @param clientIp 终端IP
* @param defaultSourceIp 默认原始IP
*
* @return 是否匹配
*/
boolean subnetIp(String sourceIp, String clientIp, String defaultSourceIp);
/**
* @see #rewriteIp(String, String, String)
*/
default String rewriteIp(String sourceIp, String clientIp) {
return this.rewriteIp(sourceIp, clientIp, null);
}
/**
* 重写IP地址
* 内网环境重写IP地址修改网络号保留主机号
*
* @param sourceIp 原始IP
* @param clientIp 终端IP
* @param defaultSourceIp 默认原始IP
*
* @return 替换IP
*/
String rewriteIp(String sourceIp, String clientIp, String defaultSourceIp);
}

View File

@@ -4,7 +4,7 @@ import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import com.acgist.taoyao.boot.property.IdProperties;
import com.acgist.taoyao.boot.config.IdProperties;
import com.acgist.taoyao.boot.service.IdService;
public class IdServiceImpl implements IdService {

View File

@@ -0,0 +1,145 @@
package com.acgist.taoyao.boot.service.impl;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.BitSet;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.acgist.taoyao.boot.config.TaoyaoProperties;
import com.acgist.taoyao.boot.service.IpService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class IpServiceImpl implements IpService {
@Autowired
private TaoyaoProperties taoyaoProperties;
/**
* 本机IP
*/
private String localIp;
/**
* 本机环回IP
*/
private String loopbackIp;
@PostConstruct
public void init() {
try {
final InetAddress localHost = InetAddress.getLocalHost();
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
this.localIp = localHost.getHostAddress();
this.loopbackIp = loopbackAddress.getHostAddress();
log.info("本机IP{}", this.localIp);
log.info("环回IP{}", this.loopbackIp);
} catch (UnknownHostException e) {
log.error("获取本机IP地址异常", e);
}
}
@Override
public boolean subnetIp(final String sourceIp, final String clientIp, final String defaultSourceIp) {
try {
InetAddress clientAddress = InetAddress.getByName(clientIp);
// 通配地址或者本地地址替换本机IP
if(this.localAnyOrLoopAddress(clientAddress)) {
clientAddress = InetAddress.getByName(this.localIp);
}
InetAddress sourceAddress = InetAddress.getByName(sourceIp);
// 通配地址或者本地换回地址替换默认地址
if(StringUtils.isNotEmpty(defaultSourceIp) && this.localAnyOrLoopAddress(sourceAddress)) {
sourceAddress = InetAddress.getByName(defaultSourceIp);
}
if(this.localAddress(sourceAddress) && this.localAddress(clientAddress)) {
final byte[] sourceBytes = sourceAddress.getAddress();
final byte[] clientBytes = clientAddress.getAddress();
final int length = (sourceBytes.length & clientBytes.length) * Byte.SIZE;
final BitSet sourceBit = BitSet.valueOf(sourceBytes);
final BitSet clientBit = BitSet.valueOf(clientBytes);
sourceBit.set(this.taoyaoProperties.getIpMask(), length, true);
clientBit.set(this.taoyaoProperties.getIpMask(), length, true);
final BigInteger source = new BigInteger(sourceBit.toByteArray());
final BigInteger client = new BigInteger(clientBit.toByteArray());
return source.equals(client);
}
} catch (Exception e) {
log.error("IP地址转换异常{}-{}", sourceIp, clientIp, e);
}
return true;
}
@Override
public String rewriteIp(final String sourceIp, final String clientIp, final String defaultSourceIp) {
try {
InetAddress clientAddress = InetAddress.getByName(clientIp);
// 通配地址或者本地地址替换本机IP
if(this.localAnyOrLoopAddress(clientAddress)) {
clientAddress = InetAddress.getByName(this.localIp);
}
InetAddress sourceAddress = InetAddress.getByName(sourceIp);
// 通配地址或者本地换回地址替换默认地址
if(this.localAnyOrLoopAddress(sourceAddress) && StringUtils.isNotEmpty(defaultSourceIp)) {
sourceAddress = InetAddress.getByName(defaultSourceIp);
}
if(this.localAddress(sourceAddress) && this.localAddress(clientAddress)) {
final byte[] sourceBytes = sourceAddress.getAddress();
final byte[] clientBytes = clientAddress.getAddress();
final int length = (sourceBytes.length & clientBytes.length) * Byte.SIZE;
final BitSet sourceBit = BitSet.valueOf(sourceBytes);
final BitSet clientBit = BitSet.valueOf(clientBytes);
// 替换网络号保留主机号
for (int index = 0; index < this.taoyaoProperties.getIpMask(); index++) {
sourceBit.set(index, clientBit.get(index));
}
final byte[] bytes = sourceBit.toByteArray();
if(bytes.length < length) {
final byte[] fillBytes = new byte[length / Byte.SIZE];
System.arraycopy(bytes, 0, fillBytes, 0, bytes.length);
return InetAddress.getByAddress(fillBytes).getHostAddress();
} else {
return InetAddress.getByAddress(bytes).getHostAddress();
}
}
} catch (Exception e) {
log.error("IP地址转换异常{}-{}", sourceIp, clientIp, e);
}
return sourceIp;
}
/**
* @param inetAddress IP地址
*
* @return 通配或者换回地址
*/
private boolean localAnyOrLoopAddress(InetAddress inetAddress) {
return
inetAddress.isAnyLocalAddress() ||
inetAddress.isLoopbackAddress();
}
/**
* @param inetAddress IP地址
*
* @return 本地IP
*/
private boolean localAddress(InetAddress inetAddress) {
return
// 通配地址0.0.0.0
inetAddress.isAnyLocalAddress() ||
// 环回地址127.0.0.1 | 0:0:0:0:0:0:0:1
inetAddress.isLoopbackAddress() ||
// 链接地址:虚拟网卡
inetAddress.isLinkLocalAddress() ||
// 组播地址
inetAddress.isMulticastAddress() ||
// 本地地址A/B/C类本地地址
inetAddress.isSiteLocalAddress();
}
}

View File

@@ -8,11 +8,15 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.concurrent.Executor;
import java.util.function.Function;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.lang3.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
/**
@@ -31,6 +35,10 @@ public final class HTTPUtils {
* 线程池
*/
private static Executor executor;
/**
* 无效IP验证
*/
private static final Function<String, Boolean> NEXT_IP = ip -> StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip);
private HTTPUtils() {
}
@@ -57,6 +65,22 @@ public final class HTTPUtils {
// .followRedirects(Redirect.ALWAYS)
.build();
}
/**
* @param request HTTP请求
*
* @return IP地址
*/
public static final String httpIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (NEXT_IP.apply(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (NEXT_IP.apply(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* @return {@link SSLContext}

View File

@@ -99,15 +99,7 @@
</root>
</springProfile>
<springProfile name="test">
<root level="INFO">
<appender-ref ref="fileDebugAsync" />
<appender-ref ref="fileInfoAsync" />
<appender-ref ref="fileErrorAsync" />
</root>
</springProfile>
<springProfile name="release">
<springProfile name="sit | uat | prd">
<root level="INFO">
<appender-ref ref="fileDebugAsync" />
<appender-ref ref="fileInfoAsync" />
@@ -115,7 +107,7 @@
</root>
</springProfile>
<springProfile name="!dev &amp; !test &amp; !release">
<springProfile name="!dev &amp; !sit &amp; !uat &amp; !prd">
<root level="DEBUG">
<appender-ref ref="console" />
<appender-ref ref="fileDebugAsync" />