[*] 日常优化

This commit is contained in:
acgist
2023-07-21 08:15:34 +08:00
parent eb84cc3d8d
commit 21dfb0df9e
12 changed files with 276 additions and 266 deletions

View File

@@ -17,8 +17,6 @@ import com.acgist.taoyao.boot.model.MessageCodeException;
import com.acgist.taoyao.signal.client.ClientAdapter; import com.acgist.taoyao.signal.client.ClientAdapter;
import com.acgist.taoyao.signal.utils.CipherUtils; import com.acgist.taoyao.signal.utils.CipherUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /**
@@ -27,8 +25,6 @@ import lombok.extern.slf4j.Slf4j;
* @author acgist * @author acgist
*/ */
@Slf4j @Slf4j
@Getter
@Setter
public class SocketClient extends ClientAdapter<AsynchronousSocketChannel> { public class SocketClient extends ClientAdapter<AsynchronousSocketChannel> {
/** /**

View File

@@ -133,7 +133,7 @@ public final class SocketSignalMessageHandler implements CompletionHandler<Integ
final String message = this.decrypt(bytes); final String message = this.decrypt(bytes);
log.debug("Socket信令消息{} - {}", this.channel, message); log.debug("Socket信令消息{} - {}", this.channel, message);
// 处理 // 处理
this.execute(message.strip()); this.execute(message);
} }
} }
} }

View File

@@ -5,8 +5,6 @@ import com.acgist.taoyao.boot.model.Message;
import com.acgist.taoyao.signal.client.ClientAdapter; import com.acgist.taoyao.signal.client.ClientAdapter;
import jakarta.websocket.Session; import jakarta.websocket.Session;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /**
@@ -15,32 +13,30 @@ import lombok.extern.slf4j.Slf4j;
* @author acgist * @author acgist
*/ */
@Slf4j @Slf4j
@Getter
@Setter
public class WebSocketClient extends ClientAdapter<Session> { public class WebSocketClient extends ClientAdapter<Session> {
public WebSocketClient(long timeout, Session instance) { public WebSocketClient(long timeout, Session instance) {
super(timeout, instance); super(timeout, instance);
} }
@Override @Override
public void push(Message message) { public void push(Message message) {
synchronized (this.instance) { synchronized (this.instance) {
try { try {
if(this.instance.isOpen()) { if(this.instance.isOpen()) {
this.instance.getBasicRemote().sendText(message.toString(), true); this.instance.getBasicRemote().sendText(message.toString(), true);
} else { } else {
log.error("WebSocket终端已经关闭{}", this.instance); log.error("WebSocket终端已经关闭{}", this.instance);
} }
} catch (Exception e) { } catch (Exception e) {
log.error("WebSocket终端发送消息异常{}", message, e); log.error("WebSocket终端发送消息异常{}", message, e);
} }
} }
} }
@Override @Override
protected String getClientIP(Session instance) { protected String getClientIP(Session instance) {
return (String) instance.getUserProperties().get(Constant.IP); return (String) instance.getUserProperties().get(Constant.IP);
} }
} }

View File

@@ -24,58 +24,58 @@ import lombok.extern.slf4j.Slf4j;
@ServerEndpoint(value = "/websocket.signal", configurator = WebSocketSignalConfigurator.class) @ServerEndpoint(value = "/websocket.signal", configurator = WebSocketSignalConfigurator.class)
public class WebSocketSignal { public class WebSocketSignal {
private static ClientManager clientManager; private static ClientManager clientManager;
private static ProtocolManager protocolManager; private static ProtocolManager protocolManager;
private static TaoyaoProperties taoyaoProperties; private static TaoyaoProperties taoyaoProperties;
private static PlatformErrorProtocol platformErrorProtocol; private static PlatformErrorProtocol platformErrorProtocol;
@OnOpen @OnOpen
public void open(Session session) { public void open(Session session) {
log.debug("WebSocket信令终端连接成功{}", session); log.debug("WebSocket信令终端连接成功{}", session);
WebSocketSignal.clientManager.open(new WebSocketClient(WebSocketSignal.taoyaoProperties.getTimeout(), session)); WebSocketSignal.clientManager.open(new WebSocketClient(WebSocketSignal.taoyaoProperties.getTimeout(), session));
} }
@OnMessage @OnMessage
public void message(Session session, String message) { public void message(Session session, String message) {
log.debug("WebSocket信令消息{}-{}", session, message); log.debug("WebSocket信令消息{} - {}", session, message);
try { try {
WebSocketSignal.protocolManager.execute(message.strip(), session); WebSocketSignal.protocolManager.execute(message, session);
} catch (Exception e) { } catch (Exception e) {
log.error("处理WebSocket信令消息异常{}-{}", WebSocketSignal.clientManager.clients(session), message, e); log.error("处理WebSocket信令消息异常{} - {}", WebSocketSignal.clientManager.clients(session), message, e);
WebSocketSignal.clientManager.push(session, WebSocketSignal.platformErrorProtocol.build(e)); WebSocketSignal.clientManager.push(session, WebSocketSignal.platformErrorProtocol.build(e));
} }
} }
@OnClose @OnClose
public void close(Session session) { public void close(Session session) {
log.debug("WebSocket信令终端关闭{}", session); log.debug("WebSocket信令终端关闭{}", session);
WebSocketSignal.clientManager.close(session); WebSocketSignal.clientManager.close(session);
} }
@OnError @OnError
public void error(Session session, Throwable e) { public void error(Session session, Throwable e) {
log.error("WebSocket信令终端异常{}", session, e); log.error("WebSocket信令终端异常{}", session, e);
this.close(session); WebSocketSignal.clientManager.close(session);
} }
@Autowired @Autowired
public void setClientManager(ClientManager clientManager) { public void setClientManager(ClientManager clientManager) {
WebSocketSignal.clientManager = clientManager; WebSocketSignal.clientManager = clientManager;
} }
@Autowired @Autowired
public void setProtocolManager(ProtocolManager protocolManager) { public void setProtocolManager(ProtocolManager protocolManager) {
WebSocketSignal.protocolManager = protocolManager; WebSocketSignal.protocolManager = protocolManager;
} }
@Autowired @Autowired
public void setTaoyaoProperties(TaoyaoProperties taoyaoProperties) { public void setTaoyaoProperties(TaoyaoProperties taoyaoProperties) {
WebSocketSignal.taoyaoProperties = taoyaoProperties; WebSocketSignal.taoyaoProperties = taoyaoProperties;
} }
@Autowired @Autowired
public void setPlatformErrorProtocol(PlatformErrorProtocol platformErrorProtocol) { public void setPlatformErrorProtocol(PlatformErrorProtocol platformErrorProtocol) {
WebSocketSignal.platformErrorProtocol = platformErrorProtocol; WebSocketSignal.platformErrorProtocol = platformErrorProtocol;
} }
} }

View File

@@ -25,7 +25,7 @@ public class WebSocketSignalConfigurator extends ServerEndpointConfig.Configurat
field.setAccessible(true); field.setAccessible(true);
config.getUserProperties().put(Constant.IP, ((RequestFacade) field.get(request)).getRemoteAddr()); config.getUserProperties().put(Constant.IP, ((RequestFacade) field.get(request)).getRemoteAddr());
} catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
throw MessageCodeException.of(e, "无效终端IP" + request); throw MessageCodeException.of(e, "无效终端IP" + request);
} }
super.modifyHandshake(config, request, response); super.modifyHandshake(config, request, response);
} }

View File

@@ -21,34 +21,34 @@ import com.acgist.taoyao.signal.protocol.system.SystemShutdownProtocol;
@ConditionalOnProperty(prefix = "taoyao.script", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = "taoyao.script", name = "enabled", havingValue = "true", matchIfMissing = true)
public class ScriptAutoConfiguration { public class ScriptAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SystemRebootProtocol systemRebootProtocol(ScriptProperties scriptProperties) { public SystemRebootProtocol systemRebootProtocol(ScriptProperties scriptProperties) {
return new SystemRebootProtocol(scriptProperties); return new SystemRebootProtocol(scriptProperties);
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SystemShutdownProtocol systemShutdownProtocol(ScriptProperties scriptProperties) { public SystemShutdownProtocol systemShutdownProtocol(ScriptProperties scriptProperties) {
return new SystemShutdownProtocol(scriptProperties); return new SystemShutdownProtocol(scriptProperties);
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PlatformRebootProtocol platformRebootProtocol(ScriptProperties scriptProperties) { public PlatformRebootProtocol platformRebootProtocol(ScriptProperties scriptProperties) {
return new PlatformRebootProtocol(scriptProperties); return new PlatformRebootProtocol(scriptProperties);
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PlatformShutdownProtocol platformShutdownProtocol(ScriptProperties scriptProperties) { public PlatformShutdownProtocol platformShutdownProtocol(ScriptProperties scriptProperties) {
return new PlatformShutdownProtocol(scriptProperties); return new PlatformShutdownProtocol(scriptProperties);
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PlatformScriptProtocol platformScriptProtocol() { public PlatformScriptProtocol platformScriptProtocol() {
return new PlatformScriptProtocol(); return new PlatformScriptProtocol();
} }
} }

View File

@@ -30,53 +30,53 @@ import lombok.extern.slf4j.Slf4j;
@ConditionalOnProperty(prefix = "taoyao.socket", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = "taoyao.socket", name = "enabled", havingValue = "true", matchIfMissing = true)
public class SocketSignalAutoConfiguration { public class SocketSignalAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SocketSignal socketSignal( public SocketSignal socketSignal(
ClientManager clientManager, ClientManager clientManager,
ProtocolManager protocolManager, ProtocolManager protocolManager,
SocketProperties socketProperties, SocketProperties socketProperties,
PlatformErrorProtocol platformErrorProtocol PlatformErrorProtocol platformErrorProtocol
) { ) {
this.buildSecret(socketProperties); this.buildSecret(socketProperties);
return new SocketSignal(clientManager, protocolManager, socketProperties, platformErrorProtocol); return new SocketSignal(clientManager, protocolManager, socketProperties, platformErrorProtocol);
} }
@Bean @Bean
@ConditionalOnBean(SocketSignal.class) @ConditionalOnBean(SocketSignal.class)
public CommandLineRunner socketSignalCommandLineRunner(SocketSignal socketSignal) { public CommandLineRunner socketSignalCommandLineRunner(SocketSignal socketSignal) {
return new OrderedCommandLineRunner() { return new OrderedCommandLineRunner() {
@Override @Override
public void run(String ... args) throws Exception { public void run(String ... args) throws Exception {
socketSignal.init(); socketSignal.init();
} }
};
}
/**
* @param socketProperties 加密配置
*/
private void buildSecret(SocketProperties socketProperties) {
log.info("Socket信令加密策略{}", socketProperties.getEncrypt());
if(socketProperties.getEncrypt() == null) {
return;
}
if(StringUtils.isNotEmpty(socketProperties.getEncryptSecret())) {
log.info("Socket信令加密密码固定{}", socketProperties.getEncryptSecret());
return;
}
final byte[] bytes = switch (socketProperties.getEncrypt()) {
case AES -> new byte[16];
case DES -> new byte[8];
default -> null;
}; };
if(bytes == null) { }
final Random random = new Random();
random.nextBytes(bytes); /**
socketProperties.setEncryptSecret(Base64.getMimeEncoder().encodeToString(bytes)); * @param socketProperties 加密配置
log.info("Socket信令加密密码随机{}", socketProperties.getEncryptSecret()); */
} else { private void buildSecret(SocketProperties socketProperties) {
log.warn("Socket信令加密密码算法不支持的算法{}", socketProperties.getEncrypt()); log.info("Socket信令加密策略{}", socketProperties.getEncrypt());
} if(socketProperties.getEncrypt() == null) {
return;
}
if(StringUtils.isNotEmpty(socketProperties.getEncryptSecret())) {
log.info("Socket信令加密密码固定{}", socketProperties.getEncryptSecret());
return;
}
final byte[] bytes = switch (socketProperties.getEncrypt()) {
case AES -> new byte[16];
case DES -> new byte[8];
default -> null;
};
if(bytes == null) {
final Random random = new Random();
random.nextBytes(bytes);
socketProperties.setEncryptSecret(Base64.getMimeEncoder().encodeToString(bytes));
log.info("Socket信令加密密码随机{}", socketProperties.getEncryptSecret());
} else {
log.warn("Socket信令加密密码算法不支持的算法{}", socketProperties.getEncrypt());
}
} }

View File

@@ -17,16 +17,16 @@ import com.acgist.taoyao.signal.client.websocket.WebSocketSignal;
@AutoConfiguration @AutoConfiguration
public class WebSocketSignalAutoConfiguration { public class WebSocketSignalAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public WebSocketSignal webSocketSignal() { public WebSocketSignal webSocketSignal() {
return new WebSocketSignal(); return new WebSocketSignal();
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ServerEndpointExporter serverEndpointExporter() { public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter(); return new ServerEndpointExporter();
} }
} }

View File

@@ -30,44 +30,44 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ClientController { public class ClientController {
private final ClientManager clientManager; private final ClientManager clientManager;
private final ClientWakeupProtocol clientWakeupProtocol; private final ClientWakeupProtocol clientWakeupProtocol;
private final ClientRebootProtocol clientRebootProtocol; private final ClientRebootProtocol clientRebootProtocol;
private final ClientShutdownProtocol clientShutdownProtocol; private final ClientShutdownProtocol clientShutdownProtocol;
@Operation(summary = "终端列表", description = "终端列表") @Operation(summary = "终端列表", description = "终端列表")
@GetMapping("/list") @GetMapping("/list")
@ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class)))
public Message list() { public Message list() {
return Message.success(this.clientManager.status()); return Message.success(this.clientManager.status());
} }
@Operation(summary = "终端状态", description = "终端状态") @Operation(summary = "终端状态", description = "终端状态")
@GetMapping("/status/{clientId}") @GetMapping("/status/{clientId}")
@ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class)))
public Message status(@PathVariable String clientId) { public Message status(@PathVariable String clientId) {
return Message.success(this.clientManager.status(clientId)); return Message.success(this.clientManager.status(clientId));
} }
@Operation(summary = "唤醒终端", description = "唤醒终端") @Operation(summary = "唤醒终端", description = "唤醒终端")
@GetMapping("/wakeup/{clientId}") @GetMapping("/wakeup/{clientId}")
public Message wakeup(@PathVariable String clientId) { public Message wakeup(@PathVariable String clientId) {
this.clientWakeupProtocol.execute(clientId); this.clientWakeupProtocol.execute(clientId);
return Message.success(); return Message.success();
} }
@Operation(summary = "重启终端", description = "重启终端") @Operation(summary = "重启终端", description = "重启终端")
@GetMapping("/reboot/{clientId}") @GetMapping("/reboot/{clientId}")
public Message reboot(@PathVariable String clientId) { public Message reboot(@PathVariable String clientId) {
this.clientRebootProtocol.execute(clientId); this.clientRebootProtocol.execute(clientId);
return Message.success(); return Message.success();
} }
@Operation(summary = "关闭终端", description = "关闭终端") @Operation(summary = "关闭终端", description = "关闭终端")
@GetMapping("/shutdown/{clientId}") @GetMapping("/shutdown/{clientId}")
public Message shutdown(@PathVariable String clientId) { public Message shutdown(@PathVariable String clientId) {
this.clientShutdownProtocol.execute(clientId); this.clientShutdownProtocol.execute(clientId);
return Message.success(); return Message.success();
} }
} }

View File

@@ -41,13 +41,13 @@ public class ProtocolController {
``` ```
{ {
"code" : "状态编码",
"message": "状态描述",
"header": { "header": {
"v": "消息版本", "v" : "消息版本",
"id": "消息标识", "id" : "消息标识",
"signal": "信令标识" "signal": "信令标识"
}, },
"code": "状态编码",
"message": "状态描述",
"body": { "body": {
... ...
} }
@@ -64,49 +64,60 @@ public class ProtocolController {
...:其他自定义的透传内容 ...:其他自定义的透传内容
``` ```
> 没有指定消息类型时表示和信令消息类型相同 > 消息类型可以省略表示和前面一致
"""); """);
this.applicationContext.getBeansOfType(Protocol.class).entrySet().stream() this.applicationContext.getBeansOfType(Protocol.class).entrySet().stream()
.sorted((a, z) -> a.getValue().signal().compareTo(z.getValue().signal())) .sorted((a, z) -> a.getValue().signal().compareTo(z.getValue().signal()))
.forEach(e -> { .forEach(e -> {
final String key = e.getKey(); final String key = e.getKey();
final Protocol protocol = e.getValue(); final Protocol protocol = e.getValue();
final String name = protocol.name(); final String name = protocol.name();
final String signal = protocol.signal(); final String signal = protocol.signal();
final Class<?> clazz; final Class<?> clazz;
final Description description; if(
if(AopUtils.isAopProxy(e) || AopUtils.isCglibProxy(protocol) || AopUtils.isJdkDynamicProxy(protocol)) { AopUtils.isAopProxy(e) ||
AopUtils.isCglibProxy(protocol) ||
AopUtils.isJdkDynamicProxy(protocol)
) {
// 代理获取 // 代理获取
clazz = AopUtils.getTargetClass(protocol); clazz = AopUtils.getTargetClass(protocol);
description = AnnotationUtils.findAnnotation(clazz, Description.class);
} else { } else {
// 直接获取 // 直接获取
clazz = protocol.getClass(); clazz = protocol.getClass();
description = AnnotationUtils.findAnnotation(clazz, Description.class);
} }
final Description description = AnnotationUtils.findAnnotation(clazz, Description.class);
if(description == null) { if(description == null) {
log.info("信令没有注解:{} - {}", key, name); log.info("信令没有注解:{} - {}", key, name);
return; return;
} }
// 信令名称 // 信令名称
builder.append("### ").append(name) builder
.append("").append(signal).append("") .append("### ").append(name)
.append(newLine).append(newLine); .append("").append(signal).append("")
.append(newLine).append(newLine);
// 描述信息 // 描述信息
final String memo = description.memo().strip(); final String memo = description.memo().strip();
if(StringUtils.isNotEmpty(memo)) { if(StringUtils.isNotEmpty(memo)) {
builder.append(memo).append(newLine).append(newLine); builder
.append(memo)
.append(newLine).append(newLine);
} }
// 消息主体 // 消息主体
builder builder
.append("```").append(newLine) .append("```")
.append("# 消息主体").append(newLine); .append(newLine)
.append("# 消息主体")
.append(newLine);
Stream.of(description.body()).forEach(line -> builder.append(line.strip()).append(newLine)); Stream.of(description.body()).forEach(line -> builder.append(line.strip()).append(newLine));
// 数据流向 // 数据流向
builder.append("# 数据流向").append(newLine); builder
.append("# 数据流向")
.append(newLine);
Stream.of(description.flow()).forEach(line -> builder.append(line.strip()).append(newLine)); Stream.of(description.flow()).forEach(line -> builder.append(line.strip()).append(newLine));
builder.append("```").append(newLine).append(newLine); builder
.append("```")
.append(newLine).append(newLine);
}); });
return builder.toString(); return builder.toString();
} }

View File

@@ -33,35 +33,35 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public class RoomController { public class RoomController {
private final RoomManager roomManager; private final RoomManager roomManager;
@Operation(summary = "房间信息", description = "房间信息") @Operation(summary = "房间信息", description = "房间信息")
@GetMapping("/log") @GetMapping("/log")
public Message log() { public Message log() {
this.roomManager.log(); this.roomManager.log();
return Message.success(); return Message.success();
} }
@Operation(summary = "房间列表", description = "房间列表") @Operation(summary = "房间列表", description = "房间列表")
@GetMapping("/list") @GetMapping("/list")
@ApiResponse(content = @Content(schema = @Schema(implementation = RoomStatus.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = RoomStatus.class)))
public Message list() { public Message list() {
return Message.success(this.roomManager.status()); return Message.success(this.roomManager.status());
} }
@Operation(summary = "房间状态", description = "房间状态") @Operation(summary = "房间状态", description = "房间状态")
@GetMapping("/status/{roomId}") @GetMapping("/status/{roomId}")
@ApiResponse(content = @Content(schema = @Schema(implementation = RoomStatus.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = RoomStatus.class)))
public Message status(@PathVariable String roomId) { public Message status(@PathVariable String roomId) {
return Message.success(this.roomManager.status(roomId)); return Message.success(this.roomManager.status(roomId));
} }
@Operation(summary = "房间终端列表", description = "房间终端列表") @Operation(summary = "房间终端列表", description = "房间终端列表")
@GetMapping("/list/client/{roomId}") @GetMapping("/list/client/{roomId}")
@ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class))) @ApiResponse(content = @Content(schema = @Schema(implementation = ClientStatus.class)))
public Message listClient(@PathVariable String roomId) { public Message listClient(@PathVariable String roomId) {
final Room room = this.roomManager.room(roomId); final Room room = this.roomManager.room(roomId);
return Message.success(room == null ? List.of() : room.clientStatus()); return Message.success(room == null ? List.of() : room.clientStatus());
} }
} }

View File

@@ -20,17 +20,17 @@ public class ApplicationEventAdapter extends ApplicationEvent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 消息 * 信令消息
*/ */
private final Message message; private final Message message;
/** /**
* 主体 * 信令主体
*/ */
private final Map<String, Object> body; private final Map<String, Object> body;
protected ApplicationEventAdapter(Object source, Message message, Map<String, Object> body) { protected ApplicationEventAdapter(Object source, Message message, Map<String, Object> body) {
super(source); super(source);
this.body = body; this.body = body;
this.message = message; this.message = message;
} }
@@ -55,6 +55,13 @@ public class ApplicationEventAdapter extends ApplicationEvent {
return MapUtils.getLong(this.body, key); return MapUtils.getLong(this.body, key);
} }
/**
* @see MapUtils#getDouble(Map, String)
*/
public Double getDouble(String key) {
return MapUtils.getDouble(this.body, key);
}
/** /**
* @see MapUtils#getInteger(Map, String) * @see MapUtils#getInteger(Map, String)
*/ */