24 changed files with 674 additions and 32 deletions
@ -0,0 +1,52 @@
|
||||
package net.sopod.soim.client.net; |
||||
|
||||
import io.netty.bootstrap.Bootstrap; |
||||
import io.netty.channel.Channel; |
||||
import io.netty.channel.ChannelInitializer; |
||||
import io.netty.channel.nio.NioEventLoopGroup; |
||||
import io.netty.channel.socket.SocketChannel; |
||||
import io.netty.channel.socket.nio.NioSocketChannel; |
||||
import net.sopod.soim.common.util.Jackson; |
||||
import net.sopod.soim.core.net.ImEntryCodec; |
||||
import net.sopod.soim.data.constant.SerializeType; |
||||
import net.sopod.soim.data.serialize.ImMessage; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* ClientInitial |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-27 22:36 |
||||
*/ |
||||
public class ImNetClient { |
||||
|
||||
public void connect(String host, int port) throws InterruptedException { |
||||
NioEventLoopGroup work = new NioEventLoopGroup(2); |
||||
Bootstrap b = new Bootstrap() |
||||
.group(work) |
||||
.channel(NioSocketChannel.class) |
||||
.handler(new ChannelInitializer<SocketChannel>() { |
||||
@Override |
||||
protected void initChannel(SocketChannel ch) throws Exception { |
||||
ch.pipeline() |
||||
.addLast(new ImEntryCodec()); |
||||
} |
||||
}); |
||||
Channel channel = b.connect(host, port).await().channel(); |
||||
Map<String, Object> body = new HashMap<>(); |
||||
body.put("name", "二狗子"); |
||||
body.put("age", 16); |
||||
ImMessage imMessage = new ImMessage() |
||||
.setServiceNo(1) |
||||
.setSerializeType(SerializeType.json.ordinal()) |
||||
.setBody(Jackson.json().serialize(body).getBytes(StandardCharsets.UTF_8)); |
||||
channel.writeAndFlush(imMessage); |
||||
channel.close(); |
||||
work.shutdownGracefully(); |
||||
} |
||||
|
||||
|
||||
} |
||||
@ -1,13 +0,0 @@
|
||||
package net.sopod.soim.client.server; |
||||
|
||||
/** |
||||
* ClientInitial |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-27 22:36 |
||||
*/ |
||||
public class ClientInitial { |
||||
|
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,11 @@
|
||||
package net.sopod.soim.common.constant; |
||||
|
||||
public class Consts { |
||||
|
||||
public static int KB = 1024; |
||||
|
||||
public static int MB = KB * KB; |
||||
|
||||
public static int GB = KB * MB; |
||||
|
||||
} |
||||
@ -0,0 +1,192 @@
|
||||
package net.sopod.soim.common.util; |
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory; |
||||
import com.fasterxml.jackson.core.JsonParser; |
||||
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
import com.fasterxml.jackson.core.json.JsonReadFeature; |
||||
import com.fasterxml.jackson.core.json.PackageVersion; |
||||
import com.fasterxml.jackson.databind.DeserializationFeature; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fasterxml.jackson.databind.SerializationFeature; |
||||
import com.fasterxml.jackson.databind.module.SimpleModule; |
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; |
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; |
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; |
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; |
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; |
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.text.SimpleDateFormat; |
||||
import java.time.LocalDate; |
||||
import java.time.LocalDateTime; |
||||
import java.time.LocalTime; |
||||
import java.time.ZoneId; |
||||
import java.time.format.DateTimeFormatter; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.TimeZone; |
||||
import java.util.function.Consumer; |
||||
import java.util.function.Supplier; |
||||
|
||||
/** |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-04 16:37 |
||||
*/ |
||||
public class Jackson { |
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Jackson.class); |
||||
|
||||
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; |
||||
private static final String DATE_FORMAT = "yyyy-MM-dd"; |
||||
private static final String TIME_FORMAT = "HH:mm:ss"; |
||||
|
||||
private static volatile Jackson JSON_INSTANCE; |
||||
private static volatile Jackson YAML_INSTANCE; |
||||
private static volatile Jackson XML_INSTANCE; |
||||
|
||||
private final ObjectMapper objectMapper; |
||||
|
||||
private Jackson(ObjectMapper objectMapper) { |
||||
this.objectMapper = objectMapper; |
||||
|
||||
} |
||||
|
||||
private static void getFactoryInstance(String clazz, Supplier<Boolean> predicate, Consumer<Jackson> setter) { |
||||
getFactoryInstance(clazz, predicate, mapper->{}, setter); |
||||
} |
||||
|
||||
private static void getFactoryInstance(String clazz, Supplier<Boolean> predicate, Consumer<ObjectMapper> setting, Consumer<Jackson> setter) { |
||||
if (predicate.get()) { |
||||
synchronized (Jackson.class) { |
||||
if (predicate.get()) { |
||||
try { |
||||
Class<?> factoryClazz = Class.forName(clazz); |
||||
Object factoryInstance = factoryClazz.getDeclaredConstructor().newInstance(); |
||||
ObjectMapper mapper; |
||||
if (factoryInstance instanceof ObjectMapper) { |
||||
mapper = new JacksonObjectMapper((ObjectMapper) factoryInstance); |
||||
} else { |
||||
mapper = new JacksonObjectMapper((JsonFactory) factoryInstance); |
||||
} |
||||
setter.accept(new Jackson(mapper)); |
||||
} catch (ReflectiveOperationException e) { |
||||
throw new RuntimeException(clazz, e); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static class JacksonObjectMapper extends ObjectMapper { |
||||
|
||||
private static final long serialVersionUID = -1848248131995072046L; |
||||
|
||||
public JacksonObjectMapper(ObjectMapper src) { |
||||
super(src); |
||||
init(); |
||||
} |
||||
|
||||
public JacksonObjectMapper(JsonFactory factory) { |
||||
super(factory); |
||||
init(); |
||||
} |
||||
|
||||
@Override |
||||
public ObjectMapper copy() { |
||||
return new JacksonObjectMapper(this); |
||||
} |
||||
|
||||
|
||||
private void init() { |
||||
super.setLocale(Locale.CHINA); |
||||
super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); |
||||
super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault())); |
||||
super.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT, Locale.CHINA)); |
||||
super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); |
||||
super.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true); |
||||
super.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true); |
||||
|
||||
super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); |
||||
super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
||||
super.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true); |
||||
super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); |
||||
|
||||
super.findAndRegisterModules(); |
||||
// 放到jackson-datatype-jsr310后注册,不然被覆盖
|
||||
super.registerModule(new MyJavaTimeModule()); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* jsr310 默认 LocalDateTime 正反序列化格式 DateTimeFormatter.ISO_LOCAL_DATE_TIME |
||||
*/ |
||||
private static class MyJavaTimeModule extends SimpleModule { |
||||
public MyJavaTimeModule() { |
||||
super(PackageVersion.VERSION); |
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); |
||||
DateTimeFormatter DateFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT); |
||||
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT); |
||||
this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter)); |
||||
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateFormatter)); |
||||
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter)); |
||||
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter)); |
||||
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateFormatter)); |
||||
this.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter)); |
||||
} |
||||
} |
||||
|
||||
public static Jackson json() { |
||||
getFactoryInstance("com.fasterxml.jackson.core.JsonFactory", |
||||
() -> JSON_INSTANCE == null, |
||||
jackson -> JSON_INSTANCE = jackson); |
||||
return JSON_INSTANCE; |
||||
} |
||||
|
||||
/** |
||||
* 依赖 jackson-dataformat-yaml |
||||
*/ |
||||
public static Jackson yaml() { |
||||
getFactoryInstance("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", |
||||
() -> YAML_INSTANCE == null, |
||||
jackson -> YAML_INSTANCE = jackson); |
||||
return YAML_INSTANCE; |
||||
} |
||||
|
||||
/** |
||||
* 依赖 jackson-dataformat-xml |
||||
*/ |
||||
public static Jackson xml() { |
||||
getFactoryInstance("com.fasterxml.jackson.dataformat.xml.XmlMapper", |
||||
() -> XML_INSTANCE == null, |
||||
jackson -> XML_INSTANCE = jackson); |
||||
return XML_INSTANCE; |
||||
} |
||||
|
||||
public <T> T deserialize(String content, Class<T> valueType) { |
||||
try { |
||||
return objectMapper.readValue(content, valueType); |
||||
} catch (JsonProcessingException e) { |
||||
log.error(e.getMessage(), e); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public <T> String serialize(T value) { |
||||
try { |
||||
return objectMapper.writeValueAsString(value); |
||||
} catch (JsonProcessingException e) { |
||||
e.printStackTrace(); |
||||
log.error(e.getMessage(), e); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public <T> T toPojo(Map<String, Object> fromValue, Class<T> toValueType) { |
||||
return objectMapper.convertValue(fromValue, toValueType); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>so-im</artifactId> |
||||
<groupId>net.sopod</groupId> |
||||
<version>1.0.0</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>im-core</artifactId> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>net.sopod</groupId> |
||||
<artifactId>im-common</artifactId> |
||||
<version>${soim.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>net.sopod</groupId> |
||||
<artifactId>im-data</artifactId> |
||||
<version>${soim.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>io.netty</groupId> |
||||
<artifactId>netty-all</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
</project> |
||||
@ -0,0 +1,44 @@
|
||||
package net.sopod.soim.core.net; |
||||
|
||||
import io.netty.buffer.ByteBuf; |
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.CombinedChannelDuplexHandler; |
||||
import io.netty.handler.codec.ByteToMessageDecoder; |
||||
import io.netty.handler.codec.MessageToByteEncoder; |
||||
import net.sopod.soim.data.serialize.ImMessage; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* ImEntryCodec |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 11:29 |
||||
*/ |
||||
public class ImEntryCodec extends CombinedChannelDuplexHandler<ImEntryCodec.ImDecoder, ImEntryCodec.ImEncoder> { |
||||
|
||||
public ImEntryCodec() { |
||||
super(new ImDecoder(), new ImEncoder()); |
||||
} |
||||
|
||||
public static class ImDecoder extends ByteToMessageDecoder { |
||||
@Override |
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception { |
||||
ImMessage message = ImMessage.read(byteBuf); |
||||
if (message == ImMessage.MAGIC_ERROR |
||||
|| message == ImMessage.PROTOCOL_ERROR) { |
||||
ctx.channel().close(); |
||||
return; |
||||
} |
||||
list.add(message); |
||||
} |
||||
} |
||||
|
||||
public static class ImEncoder extends MessageToByteEncoder<ImMessage> { |
||||
@Override |
||||
protected void encode(ChannelHandlerContext ctx, ImMessage imMessage, ByteBuf byteBuf) throws Exception { |
||||
imMessage.write(byteBuf); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,26 @@
|
||||
package net.sopod.soim.core.net; |
||||
|
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.SimpleChannelInboundHandler; |
||||
import net.sopod.soim.data.constant.SerializeType; |
||||
import net.sopod.soim.data.serialize.ImMessage; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* ImMessageHandler |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 13:27 |
||||
*/ |
||||
public class ImMessageHandler extends SimpleChannelInboundHandler<ImMessage> { |
||||
|
||||
@Override |
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ImMessage imMessage) throws Exception { |
||||
byte[] body = imMessage.getBody(); |
||||
SerializeType serialize = SerializeType.getSerializeByOrdinal(imMessage.getSerializeType()); |
||||
Map data = serialize.getSerializer().deserialize(body, Map.class); |
||||
System.out.println(data); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,41 @@
|
||||
package net.sopod.soim.core.registry; |
||||
|
||||
import net.sopod.soim.core.service.ReqHandler; |
||||
|
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
||||
/** |
||||
* ServiceRegistry |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 14:30 |
||||
*/ |
||||
public class ServiceRegistry { |
||||
|
||||
private static final ConcurrentHashMap<Integer, Class<?>> serviceIdParamTypeMap; |
||||
|
||||
private static final ConcurrentHashMap<Class<?>, Integer> paramTypeServiceIdMap; |
||||
|
||||
private static final ConcurrentHashMap<Integer, ReqHandler<?>> serviceIdHandlers; |
||||
|
||||
static { |
||||
serviceIdParamTypeMap = new ConcurrentHashMap<>(); |
||||
paramTypeServiceIdMap = new ConcurrentHashMap<>(); |
||||
serviceIdHandlers = new ConcurrentHashMap<>(); |
||||
} |
||||
|
||||
private static final AtomicInteger serviceIdGen = new AtomicInteger(10000); |
||||
|
||||
private static <T> void registry(Class<T> paramType, ReqHandler<T> handler) { |
||||
int serviceId = serviceIdGen.getAndIncrement(); |
||||
serviceIdParamTypeMap.put(serviceId, paramType); |
||||
paramTypeServiceIdMap.put(paramType, serviceId); |
||||
serviceIdHandlers.put(serviceId, handler); |
||||
} |
||||
|
||||
public void aaa() { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
package net.sopod.soim.core.service; |
||||
|
||||
/** |
||||
* ReqHandler |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 14:33 |
||||
*/ |
||||
public interface ReqHandler<T> { |
||||
|
||||
Object handle(T param); |
||||
|
||||
} |
||||
@ -0,0 +1,15 @@
|
||||
package net.sopod.soim.data.serialize; |
||||
|
||||
/** |
||||
* ByteSerializer |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 11:03 |
||||
*/ |
||||
public interface ByteSerializer { |
||||
|
||||
<T> T deserialize(byte[] data, Class<T> clazz) throws Exception; |
||||
|
||||
byte[] serialize(Object pojo) throws Exception; |
||||
|
||||
} |
||||
@ -0,0 +1,40 @@
|
||||
package net.sopod.soim.data.serialize; |
||||
|
||||
import net.sopod.soim.common.util.Jackson; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* JsonByteSerializer |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 11:05 |
||||
*/ |
||||
public class JacksonByteSerializer implements ByteSerializer{ |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JacksonByteSerializer.class); |
||||
|
||||
@Override |
||||
public <T> T deserialize(byte[] data, Class<T> clazz) throws Exception { |
||||
String json = new String(data, StandardCharsets.UTF_8); |
||||
T obj = Jackson.json().deserialize(json, clazz); |
||||
if (obj == null) { |
||||
logger.error("json数据解析失败:{}", json); |
||||
throw new IllegalStateException("json数据解析失败"); |
||||
} |
||||
return obj; |
||||
} |
||||
|
||||
@Override |
||||
public byte[] serialize(Object pojo) throws Exception { |
||||
String json = Jackson.json().serialize(pojo); |
||||
return json.getBytes(StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,18 @@
|
||||
package net.sopod.soim.data.transer; |
||||
|
||||
import lombok.Data; |
||||
|
||||
/** |
||||
* LoginReq |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 14:24 |
||||
*/ |
||||
@Data |
||||
public class LoginReq { |
||||
|
||||
private String name; |
||||
|
||||
private String password; |
||||
|
||||
} |
||||
@ -0,0 +1,88 @@
|
||||
package net.sopod.soim.entry.server; |
||||
|
||||
import io.netty.bootstrap.ServerBootstrap; |
||||
import io.netty.buffer.PooledByteBufAllocator; |
||||
import io.netty.channel.ChannelFutureListener; |
||||
import io.netty.channel.ChannelOption; |
||||
import io.netty.channel.WriteBufferWaterMark; |
||||
import io.netty.channel.nio.NioEventLoopGroup; |
||||
import io.netty.channel.socket.nio.NioServerSocketChannel; |
||||
import io.netty.util.concurrent.DefaultThreadFactory; |
||||
import net.sopod.soim.common.constant.Consts; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.util.function.Consumer; |
||||
|
||||
/** |
||||
* EntryServer |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 11:19 |
||||
*/ |
||||
public class EntryServer { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(EntryServer.class); |
||||
|
||||
private NioEventLoopGroup boss; |
||||
private NioEventLoopGroup worker; |
||||
private ServerBootstrap serverBootstrap; |
||||
|
||||
private String name; |
||||
private int port; |
||||
|
||||
public static final int LOW_WATER_MARK = 32 * Consts.KB; |
||||
public static final int HIGH_WATER_MARK = 64 * Consts.KB; |
||||
|
||||
public EntryServer(String name, int port) { |
||||
this.name = name; |
||||
this.port = port; |
||||
this.boss = |
||||
new NioEventLoopGroup(1, new DefaultThreadFactory("entry-boss", Thread.MAX_PRIORITY)); |
||||
this.worker = |
||||
new NioEventLoopGroup(new DefaultThreadFactory("entry-worker", Thread.MAX_PRIORITY)); |
||||
this.bootstrap(); |
||||
} |
||||
|
||||
private void bootstrap() { |
||||
this.serverBootstrap = new ServerBootstrap() |
||||
.group(boss, worker) |
||||
.channel(NioServerSocketChannel.class) |
||||
.childHandler(new ImEntryInitializer()) |
||||
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) |
||||
.option(ChannelOption.SO_RCVBUF, 32 * Consts.KB) |
||||
.option(ChannelOption.SO_REUSEADDR, true) |
||||
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, |
||||
new WriteBufferWaterMark(LOW_WATER_MARK, HIGH_WATER_MARK)) |
||||
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) |
||||
.childOption(ChannelOption.TCP_NODELAY, true) |
||||
.childOption(ChannelOption.SO_RCVBUF, 32 * Consts.KB) |
||||
.childOption(ChannelOption.SO_SNDBUF, 64 * Consts.KB) |
||||
.childOption(ChannelOption.SO_REUSEADDR, true) |
||||
.childOption( |
||||
ChannelOption.WRITE_BUFFER_WATER_MARK, |
||||
new WriteBufferWaterMark(LOW_WATER_MARK, HIGH_WATER_MARK)); |
||||
} |
||||
|
||||
public void startServer(Consumer<Throwable> onFail) { |
||||
this.serverBootstrap |
||||
.bind(port) |
||||
.addListener((ChannelFutureListener) future -> { |
||||
if (!future.isSuccess()) { |
||||
if (onFail != null) { |
||||
onFail.accept(future.cause()); |
||||
} |
||||
return; |
||||
} |
||||
System.out.println(String.format("%s %s listen...", name, port)); |
||||
}); |
||||
} |
||||
|
||||
public void shutdown() { |
||||
logger.info("netty reactor group shutting down..."); |
||||
boss.shutdownGracefully(); |
||||
worker.shutdownGracefully(); |
||||
logger.info("netty reactor group already shutdown!"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,32 @@
|
||||
package net.sopod.soim.entry.server; |
||||
|
||||
import io.netty.channel.ChannelInitializer; |
||||
import io.netty.channel.ChannelPipeline; |
||||
import io.netty.channel.socket.SocketChannel; |
||||
import io.netty.handler.logging.LogLevel; |
||||
import io.netty.handler.logging.LoggingHandler; |
||||
import net.sopod.soim.core.net.ImEntryCodec; |
||||
import net.sopod.soim.core.net.ImMessageHandler; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* ImEntryInitializer |
||||
* |
||||
* @author tmy |
||||
* @date 2022-03-28 11:25 |
||||
*/ |
||||
public class ImEntryInitializer extends ChannelInitializer<SocketChannel> { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ImEntryInitializer.class); |
||||
|
||||
@Override |
||||
protected void initChannel(SocketChannel socketChannel) throws Exception { |
||||
LogLevel logLevel = logger.isDebugEnabled() ? LogLevel.DEBUG : LogLevel.INFO; |
||||
ChannelPipeline pipeline = socketChannel.pipeline(); |
||||
pipeline.addLast(new LoggingHandler(logLevel)) |
||||
.addLast(new ImEntryCodec()) |
||||
.addLast(new ImMessageHandler()); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue