rename com.imyeyu.server to com.imyeyu.api
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package com.imyeyu.api.modules.music.bean;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.Data;
|
||||
import com.imyeyu.utils.Time;
|
||||
|
||||
/**
|
||||
* 频道绑定
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2023-02-07 14:43
|
||||
*/
|
||||
@Data
|
||||
public class ChannelBinding {
|
||||
|
||||
/** 与受控端连接频道 */
|
||||
private ChannelHandlerContext playerChannel;
|
||||
|
||||
/** 与控制端连接频道 */
|
||||
private ChannelHandlerContext controllerChannel;
|
||||
|
||||
private long lastActiviedAt = -1;
|
||||
|
||||
/** @return true 为超过 1 分钟未发生通信 */
|
||||
public boolean isTimeout() {
|
||||
return Time.M < Time.now() - lastActiviedAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.imyeyu.api.modules.music.bean.pkg;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 基本数据包
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2023-02-08 11:14
|
||||
*/
|
||||
@Data
|
||||
abstract class BasePackage {
|
||||
|
||||
/**
|
||||
* 播放模式
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2023-02-08 14:12
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/** 单曲循环 */
|
||||
REPEAT,
|
||||
|
||||
/** 队列循环 */
|
||||
REPEAT_PLAY_LIST,
|
||||
|
||||
/** 队后单循 */
|
||||
REPEAT_PLAY_LIST_END,
|
||||
|
||||
/** 列表循环 */
|
||||
REPEAT_FILE_LIST
|
||||
}
|
||||
|
||||
/** 频道 */
|
||||
private String channelID;
|
||||
|
||||
/** 播放模式 */
|
||||
private Type type;
|
||||
|
||||
/** 音量 */
|
||||
private double volume;
|
||||
|
||||
/** 包生成时间 */
|
||||
private Long createdAt;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.imyeyu.api.modules.music.bean.pkg;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 控制端数据包,由控制器发出至受控端
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2023-02-08 11:15
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ControllerPackage extends BasePackage {
|
||||
|
||||
/**
|
||||
* @author 夜雨
|
||||
* @version 2023-02-07 11:37
|
||||
*/
|
||||
public enum Action {
|
||||
|
||||
/** 上一首 */
|
||||
PREVIOUS,
|
||||
|
||||
/** 切换播放状态 */
|
||||
TOGGLE,
|
||||
|
||||
/** 下一首 */
|
||||
NEXT,
|
||||
|
||||
/** 随机列表 */
|
||||
RANDOM,
|
||||
|
||||
/** 音量调整 */
|
||||
VOLUME,
|
||||
|
||||
/** 播放模式调整 */
|
||||
TYPE
|
||||
}
|
||||
|
||||
/** 控制动作 */
|
||||
private Action action;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.imyeyu.api.modules.music.bean.pkg;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 受控端数据包,推送播放器状态到控制器
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2023-02-08 11:15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PlayerPackage extends BasePackage {
|
||||
|
||||
/** 当前播放 */
|
||||
private String nowPlaying;
|
||||
|
||||
/** 下一首播放 */
|
||||
private String nextPlay;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.imyeyu.api.modules.music.core;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.imyeyu.utils.Time;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.api.modules.music.bean.ChannelBinding;
|
||||
import com.imyeyu.api.modules.music.bean.pkg.ControllerPackage;
|
||||
import com.imyeyu.api.modules.music.bean.pkg.PlayerPackage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 中转站
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2021-11-03 22:56
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class Middleware implements SchedulingConfigurer {
|
||||
|
||||
/** 缓存清理间隔 */
|
||||
private static final String CACHE_CLEAR_CORN = "0 0/20 * * * ?";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
/** 缓存频道,Map<频道 ID, 关联频道> */
|
||||
private final Map<String, ChannelBinding> channels = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void configureTasks(ScheduledTaskRegistrar registrar) {
|
||||
// 定时清理过期频道
|
||||
Trigger trigger = tc -> new CronTrigger(CACHE_CLEAR_CORN).nextExecution(tc);
|
||||
registrar.addTriggerTask(() -> channels.keySet().removeIf(channelID -> channels.get(channelID).isTimeout()), trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送受控端数据
|
||||
*
|
||||
* @param ctx 受控端频道(关联控制端)
|
||||
* @param pkg 数据包
|
||||
*/
|
||||
public void pushPlayerData(ChannelHandlerContext ctx, PlayerPackage pkg) {
|
||||
if (TimiJava.isEmpty(pkg.getChannelID())) {
|
||||
return;
|
||||
}
|
||||
ChannelBinding channelBinding = channels.get(pkg.getChannelID());
|
||||
if (channelBinding == null) {
|
||||
channelBinding = new ChannelBinding();
|
||||
channels.put(pkg.getChannelID(), channelBinding);
|
||||
log.info("TimiMusic created channel: " + pkg.getChannelID());
|
||||
}
|
||||
channelBinding.setPlayerChannel(ctx);
|
||||
channelBinding.setLastActiviedAt(Time.now());
|
||||
if (channelBinding.getControllerChannel() != null) {
|
||||
channelBinding.getControllerChannel().writeAndFlush(new TextWebSocketFrame(gson.toJson(pkg)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送控制端数据
|
||||
*
|
||||
* @param ctx 控制端频道(关联受控端)
|
||||
* @param pkg 数据包
|
||||
*/
|
||||
public void pushControllerData(ChannelHandlerContext ctx, ControllerPackage pkg) {
|
||||
if (TimiJava.isEmpty(pkg.getChannelID())) {
|
||||
return;
|
||||
}
|
||||
ChannelBinding channelBinding = channels.get(pkg.getChannelID());
|
||||
if (channelBinding == null) {
|
||||
channelBinding = new ChannelBinding();
|
||||
channels.put(pkg.getChannelID(), channelBinding);
|
||||
log.info("TimiMusic created channel: " + pkg.getChannelID());
|
||||
}
|
||||
channelBinding.setControllerChannel(ctx);
|
||||
channelBinding.setLastActiviedAt(Time.now());
|
||||
if (pkg.getAction() != null && channelBinding.getPlayerChannel() != null) {
|
||||
byte[] bytes = gson.toJson(pkg).getBytes(StandardCharsets.UTF_8);
|
||||
ByteBuf buffer = Unpooled.buffer();
|
||||
buffer.writeInt(bytes.length);
|
||||
buffer.writeBytes(bytes);
|
||||
channelBinding.getPlayerChannel().writeAndFlush(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.imyeyu.api.modules.music.handler;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.imyeyu.api.modules.music.bean.pkg.ControllerPackage;
|
||||
import com.imyeyu.api.modules.music.core.Middleware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 控制端消息处理
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2021-11-03 15:34
|
||||
*/
|
||||
@Slf4j
|
||||
@ChannelHandler.Sharable
|
||||
@Component
|
||||
public class ControllerMessageHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Autowired
|
||||
private Middleware middleware;
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) {
|
||||
if (msg instanceof TextWebSocketFrame textWebSocketFrame) {
|
||||
middleware.pushControllerData(ctx, gson.fromJson(textWebSocketFrame.text(), ControllerPackage.class));
|
||||
} else {
|
||||
ctx.channel().writeAndFlush(WebSocketCloseStatus.INVALID_MESSAGE_TYPE).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
log.info("TimiMusic controller disconnected: " + ctx.channel().remoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
log.info("TimiMusic controller connected: " + ctx.channel().remoteAddress());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.imyeyu.api.modules.music.handler;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.imyeyu.api.modules.music.bean.pkg.PlayerPackage;
|
||||
import com.imyeyu.api.modules.music.core.Middleware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 受控端消息处理
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2021-11-03 17:50
|
||||
*/
|
||||
@Slf4j
|
||||
@ChannelHandler.Sharable
|
||||
@Component
|
||||
public class PlayerMessageHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Autowired
|
||||
private Middleware middleware;
|
||||
|
||||
@Override
|
||||
protected synchronized void channelRead0(ChannelHandlerContext ctx, String result) {
|
||||
middleware.pushPlayerData(ctx, gson.fromJson(result, PlayerPackage.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
log.info("TimiMusic player disconnected: " + ctx.channel().remoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
log.info("TimiMusic player connected: " + ctx.channel().remoteAddress());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.imyeyu.api.modules.music.runner;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.imyeyu.api.config.CORSConfig;
|
||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||
import com.imyeyu.api.modules.common.service.SettingService;
|
||||
import com.imyeyu.api.modules.music.handler.ControllerMessageHandler;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* 控制端 Netty 服务
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2021-11-03 15:29
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ControllerBootstrapRunner implements ApplicationRunner, ApplicationListener<ContextClosedEvent>, ApplicationContextAware {
|
||||
|
||||
private final CORSConfig corsConfig;
|
||||
private final SettingService settingService;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Channel channel;
|
||||
private EventLoopGroup boss, worker;
|
||||
|
||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void run(ApplicationArguments args) {
|
||||
final DefaultFullHttpResponse NFP = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
|
||||
final DefaultFullHttpResponse BRP = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
|
||||
|
||||
boss = new NioEventLoopGroup();
|
||||
worker = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(boss, worker);
|
||||
bootstrap.channel(NioServerSocketChannel.class);
|
||||
bootstrap.localAddress(new InetSocketAddress(settingService.getAsInt(SettingKey.MUSIC_CONTROLLER_PORT)));
|
||||
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel) {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
pipeline.addLast(new HttpServerCodec());
|
||||
pipeline.addLast(new ChunkedWriteHandler());
|
||||
pipeline.addLast(new HttpObjectAggregator(65536));
|
||||
pipeline.addLast(new ChannelInboundHandlerAdapter() {
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
|
||||
if (obj instanceof FullHttpRequest req) {
|
||||
if (!req.uri().equals(settingService.getAsString(SettingKey.MUSIC_CONTROLLER_URI))) {
|
||||
// 访问的路径不是 Web Socket 的端点地址,响应 404
|
||||
ctx.channel().writeAndFlush(NFP).addListener(ChannelFutureListener.CLOSE);
|
||||
return;
|
||||
}
|
||||
// 域名限制
|
||||
String reqOrigin = req.headers().get(HttpHeaderNames.ORIGIN);
|
||||
String[] allowOrigin = corsConfig.getAllowOrigin();
|
||||
for (int i = 0; i < allowOrigin.length; i++) {
|
||||
if (allowOrigin[i].equals(reqOrigin)) {
|
||||
super.channelRead(ctx, obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ctx.channel().writeAndFlush(BRP).addListener(ChannelFutureListener.CLOSE);
|
||||
return;
|
||||
}
|
||||
super.channelRead(ctx, obj);
|
||||
}
|
||||
});
|
||||
pipeline.addLast(new WebSocketServerCompressionHandler());
|
||||
pipeline.addLast(new WebSocketServerProtocolHandler(
|
||||
settingService.getAsString(SettingKey.MUSIC_CONTROLLER_URI),
|
||||
null,
|
||||
true,
|
||||
settingService.getAsInt(SettingKey.MUSIC_MAX_FRAME_LENGTH)
|
||||
)
|
||||
);
|
||||
|
||||
// 从 IOC 获取 Handler
|
||||
pipeline.addLast(applicationContext.getBean(ControllerMessageHandler.class));
|
||||
}
|
||||
});
|
||||
channel = bootstrap.bind().sync().channel();
|
||||
log.info("TimiMusicRC controller service startup with " + settingService.getAsString(SettingKey.MUSIC_CONTROLLER_IP));
|
||||
} catch (Exception e) {
|
||||
log.error("TimiMusicRC controller service startup error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onApplicationEvent(@NonNull ContextClosedEvent event) {
|
||||
if (channel != null) {
|
||||
channel.closeFuture();
|
||||
boss.shutdownGracefully();
|
||||
worker.shutdownGracefully();
|
||||
}
|
||||
log.info("TimiMusicRC controller service shutdown finished");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.imyeyu.api.modules.music.runner;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||
import com.imyeyu.api.modules.common.service.SettingService;
|
||||
import com.imyeyu.api.modules.music.handler.PlayerMessageHandler;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 受控端 Netty 服务
|
||||
*
|
||||
* @author 夜雨
|
||||
* @version 2021-11-03 19:18
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PlayerBootstrapRunner implements ApplicationRunner, ApplicationListener<ContextClosedEvent>, ApplicationContextAware {
|
||||
|
||||
private final SettingService settingService;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Channel channel;
|
||||
private EventLoopGroup boss, worker;
|
||||
|
||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void run(ApplicationArguments args) {
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
boss = new NioEventLoopGroup();
|
||||
worker = new NioEventLoopGroup();
|
||||
try {
|
||||
bootstrap.group(boss, worker);
|
||||
bootstrap.channel(NioServerSocketChannel.class);
|
||||
bootstrap.localAddress(new InetSocketAddress(settingService.getAsInt(SettingKey.MUSIC_PLAYER_PORT)));
|
||||
bootstrap.childHandler(new ChannelInitializer<>() {
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel ch) {
|
||||
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(
|
||||
settingService.getAsInt(SettingKey.MUSIC_MAX_FRAME_LENGTH),
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
4));
|
||||
ch.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
|
||||
ch.pipeline().addLast(applicationContext.getBean(PlayerMessageHandler.class));
|
||||
}
|
||||
});
|
||||
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
|
||||
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
|
||||
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
channel = bootstrap.bind().sync().channel();
|
||||
|
||||
log.info("TimiMusicRC player service startup with " + settingService.getAsString(SettingKey.MUSIC_PLAYER_IP));
|
||||
} catch (Exception e) {
|
||||
log.error("TimiMusicRC player service startup error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onApplicationEvent(@NonNull ContextClosedEvent event) {
|
||||
if (channel != null) {
|
||||
channel.closeFuture();
|
||||
boss.shutdownGracefully();
|
||||
worker.shutdownGracefully();
|
||||
}
|
||||
log.info("TimiMusicRC player service shutdown finished");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user