21 changed files with 735 additions and 124 deletions
@ -0,0 +1,18 @@
|
||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠹⢿⣿⣿⣿⣿⣿⡿⠋⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠈⠻⣿⣿⡿⠏⠀⠀⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠙⠋⠀⠀⠀⢀⣿⣿⣿⣿⣿ |
||||
⣿⣿⣷⡈⠉⠉⠉⠉⠉⠀⣀⡤⠴⠶⠶⠶⠤⣄⡀⠸⠿⠿⠛⢛⣿ |
||||
⣿⣿⣿⣿⡄⠀⠀⠀⣰⠚⠁⠀⠀⠀⠀⠀⠀⠀⠳⣄⠀⠀⢠⣾⣿ |
||||
⣿⣿⣿⣿⣷⠀⠀⡜⠁⠀⠀⠀⠀⣀⣀⣀⣀⣀⣀⠘⡆⢠⣿⣿⣿ |
||||
⣿⣿⠿⠛⠉⠀⢰⠇⠀⠰⣾⡯⠭⠭⣭⠭⡭⠭⠭⠭⢿⡀⠙⠿⣿ |
||||
⣿⣤⣀⠀⠀⠀⢸⠀⢠⣧⣤⣤⣤⠤⢼⣾⠥⣤⡤⠤⠬⡇⣠⣴⣾ |
||||
⣿⣿⣿⣿⡦⠀⢸⠀⠈⢧⡀⠁⠀⠀⡠⠛⣄⠈⠀⢀⣠⠇⣿⣿⣿ |
||||
⣿⣿⠿⠋⠀⠀⣸⡄⠀⢤⣉⠓⠚⠋⠁⡀⢸⡩⣯⡭⢿⡀⠙⠿⣿ |
||||
⣿⣷⣤⣄⡀⢼⠋⠀⠀⠀⠉⠉⠁⠀⠀⠳⣼⠇⠀⠀⣼⢹⣾⣿⣿ |
||||
⣿⣿⣿⣿⡟⠈⠳⣤⠀⠀⡀⠀⠀⣀⣀⣀⣀⣀⡀⠀⣿⡻⣿⣿⣿ |
||||
⣿⣿⣿⣿⣾⣿⣿⠞⣆⠸⡇⠚⠉⠁⠀⣿⣿⡟⠉⢁⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⣿⣿⣶⣿⣆⠈⠁⠀⠰⡖⠙⠛⠃⣠⣿⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡦⣄⣀⣀⣠⣴⣾⣿⣿⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⣿⡿⠿⠟⠛⡛⢷⣤⣀⣠⢾⣛⠛⠿⢿⣿⣿⣿⣿⣿ |
||||
⣿⣿⣿⣿⣿⠃⠀⠀⠀⢰⠃⢸⠀⠀⠀⠘⡟⣆⠀⠀⢹⣿⣿⣿⣿ |
||||
@ -0,0 +1,31 @@
|
||||
package net.sopod.soim.router.datasync; |
||||
|
||||
import net.sopod.soim.common.util.Jackson; |
||||
import net.sopod.soim.router.cache.RouterUser; |
||||
import net.sopod.soim.router.cache.RouterUserStorage; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* SyncService |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-08 09:42 |
||||
*/ |
||||
public class SyncService { |
||||
|
||||
public void fullSync() { |
||||
Map<Long, RouterUser> routerUserMap = RouterUserStorage.getInstance().getRouterUserMap(); |
||||
for (Map.Entry<Long, RouterUser> entry : routerUserMap.entrySet()) { |
||||
Long key = entry.getKey(); |
||||
RouterUser value = entry.getValue(); |
||||
Jackson.json().serialize(value); |
||||
|
||||
} |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,50 +0,0 @@
|
||||
package net.sopod.soim.router.datasync.server; |
||||
|
||||
import io.netty.buffer.ByteBuf; |
||||
import io.netty.channel.*; |
||||
import io.netty.handler.codec.ByteToMessageDecoder; |
||||
import io.netty.handler.codec.MessageToByteEncoder; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* SyncDataInboundHandler |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-05 10:20 |
||||
*/ |
||||
public class SyncLogDataCodec |
||||
extends CombinedChannelDuplexHandler<SyncLogDataCodec.SyncDataDecoder, |
||||
SyncLogDataCodec.SyncDataEncoder> { |
||||
|
||||
public SyncLogDataCodec() { |
||||
super(new SyncDataDecoder(), new SyncDataEncoder()); |
||||
} |
||||
|
||||
/** |
||||
* 解码器 |
||||
*/ |
||||
public static class SyncDataDecoder extends ByteToMessageDecoder { |
||||
|
||||
@Override |
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception { |
||||
SyncLog syncLog = SyncLog.read(byteBuf); |
||||
list.add(syncLog); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 编码器 |
||||
*/ |
||||
public static class SyncDataEncoder extends MessageToByteEncoder<SyncLog> { |
||||
|
||||
@Override |
||||
protected void encode(ChannelHandlerContext channelHandlerContext, SyncLog syncLog, ByteBuf byteBuf) throws Exception { |
||||
byte[] bytes = syncLog.toBytes(); |
||||
byteBuf.writeBytes(bytes); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,33 +0,0 @@
|
||||
package net.sopod.soim.router.datasync.server; |
||||
|
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.ChannelInboundHandlerAdapter; |
||||
|
||||
/** |
||||
* SyncLogInboundHandler |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-05 14:57 |
||||
*/ |
||||
public class SyncServerInboundHandler extends ChannelInboundHandlerAdapter { |
||||
|
||||
public SyncServerInboundHandler() { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception { |
||||
super.channelActive(ctx); |
||||
} |
||||
|
||||
@Override |
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
||||
super.channelInactive(ctx); |
||||
} |
||||
|
||||
@Override |
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
||||
super.exceptionCaught(ctx, cause); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
|
||||
package net.sopod.soim.router.datasync.server.codec; |
||||
|
||||
import net.sopod.soim.common.util.Jackson; |
||||
import org.xerial.snappy.Snappy; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* CodecUtil |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-08 16:54 |
||||
*/ |
||||
public class CodecUtil { |
||||
|
||||
public static byte[] encode(Object data) { |
||||
return Jackson.msgpack().serializeBytes(data); |
||||
} |
||||
|
||||
public static byte[] compress(byte[] bytes) { |
||||
try { |
||||
return Snappy.compress(bytes); |
||||
} catch (IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
public static byte[] codecAndCompress(Object data) { |
||||
byte[] bytes = encode(data); |
||||
return compress(bytes); |
||||
} |
||||
|
||||
public static <T> T decode(byte[] bytes, Class<T> type) { |
||||
return Jackson.msgpack().deserializeBytes(bytes, type); |
||||
} |
||||
|
||||
public static byte[] uncompress(byte[] bytes) { |
||||
try { |
||||
return Snappy.uncompress(bytes); |
||||
} catch (IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
public static <T> T uncompressAndDecode(byte[] bytes, Class<T> type) { |
||||
byte[] uncompress = uncompress(bytes); |
||||
return decode(uncompress, type); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,61 @@
|
||||
package net.sopod.soim.router.datasync.server.codec; |
||||
|
||||
import io.netty.buffer.ByteBuf; |
||||
import io.netty.buffer.Unpooled; |
||||
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.router.datasync.server.data.SyncCmd; |
||||
import net.sopod.soim.router.datasync.server.data.SyncLog; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* SyncChannelHandler |
||||
* SyncCmd 编解码器 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-07 21:37 |
||||
*/ |
||||
public class SyncCmdCodec extends CombinedChannelDuplexHandler<SyncCmdCodec.SyncCmdDecoder, |
||||
SyncCmdCodec.SyncCmdEncoder> { |
||||
|
||||
public SyncCmdCodec() { |
||||
super(new SyncCmdDecoder(), new SyncCmdEncoder()); |
||||
} |
||||
|
||||
public static class SyncCmdDecoder extends ByteToMessageDecoder { |
||||
@Override |
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception { |
||||
SyncCmd syncCmd = SyncCmd.read(byteBuf); |
||||
if (!SyncCmd.SYNC_LOG.equals(syncCmd.getCmdType())) { |
||||
list.add(syncCmd); |
||||
return; |
||||
} |
||||
// 数据同步请求命令
|
||||
// 同步数据请求体长度
|
||||
int syncLogBytesLen = byteBuf.readInt(); |
||||
// 读取、解压、解析字节数据
|
||||
byte[] syncLogCompressBytes = new byte[syncLogBytesLen]; |
||||
byteBuf.readBytes(syncLogCompressBytes); |
||||
byte[] syncLogBytes = CodecUtil.uncompress(syncLogCompressBytes); |
||||
ByteBuf syncLogByteBuf = Unpooled.wrappedBuffer(syncLogBytes); |
||||
try { |
||||
SyncLog syncLog = SyncLog.read(syncLogByteBuf); |
||||
list.add(syncLog); |
||||
} finally { |
||||
syncLogByteBuf.release(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static class SyncCmdEncoder extends MessageToByteEncoder<SyncCmd> { |
||||
@Override |
||||
protected void encode(ChannelHandlerContext channelHandlerContext, SyncCmd syncCmd, ByteBuf byteBuf) throws Exception { |
||||
byte[] bytes = syncCmd.toByte(); |
||||
byteBuf.writeBytes(bytes); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,34 @@
|
||||
package net.sopod.soim.router.datasync.server.codec; |
||||
|
||||
import io.netty.buffer.ByteBuf; |
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.handler.codec.MessageToByteEncoder; |
||||
import net.sopod.soim.router.datasync.server.data.SyncCmd; |
||||
import net.sopod.soim.router.datasync.server.data.SyncLog; |
||||
|
||||
/** |
||||
* SyncDataInboundHandler |
||||
* SyncLog 编码器 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-05 10:20 |
||||
*/ |
||||
public class SyncLogEncoder extends MessageToByteEncoder<SyncLog> { |
||||
|
||||
@Override |
||||
protected void encode(ChannelHandlerContext channelHandlerContext, SyncLog syncLog, ByteBuf byteBuf) throws Exception { |
||||
// 同步数据指令
|
||||
SyncCmd syncCmd = new SyncCmd() |
||||
.setCmdType(SyncCmd.SYNC_LOG); |
||||
byte[] syncCmdBytes = syncCmd.toByte(); |
||||
byteBuf.writeBytes(syncCmdBytes); |
||||
|
||||
// 同步数据内容
|
||||
byte[] bytes = syncLog.toBytes(); |
||||
// snappy 压缩一下
|
||||
byte[] compressLogBytes = CodecUtil.compress(bytes); |
||||
byteBuf.writeInt(compressLogBytes.length); |
||||
byteBuf.writeBytes(compressLogBytes); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,113 @@
|
||||
package net.sopod.soim.router.datasync.server.data; |
||||
|
||||
import io.netty.buffer.ByteBuf; |
||||
import lombok.Data; |
||||
import lombok.experimental.Accessors; |
||||
import org.apache.dubbo.common.io.Bytes; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
/** |
||||
* SyncCmd |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-07 21:41 |
||||
*/ |
||||
@Data |
||||
@Accessors(chain = true) |
||||
public class SyncCmd { |
||||
|
||||
private static final short MAGIC = 0x7a21; |
||||
|
||||
public static final int PING = 1; |
||||
|
||||
public static final int PONG = 2; |
||||
|
||||
/** |
||||
* 同步命令 |
||||
*/ |
||||
public static final Integer SYNC = 3; |
||||
|
||||
/** |
||||
* 同步结束命令 |
||||
*/ |
||||
public static final Integer SYNC_END = 4; |
||||
|
||||
/** |
||||
* SyncLog 推送命令 |
||||
*/ |
||||
public static final Integer SYNC_LOG = 10; |
||||
|
||||
private Integer cmdType; |
||||
|
||||
private String param1; |
||||
|
||||
private String param2; |
||||
|
||||
private String param3; |
||||
|
||||
public byte[] toByte() { |
||||
byte[] param1Bytes = param1 == null ? new byte[0] : param1.getBytes(StandardCharsets.UTF_8); |
||||
byte[] param2Bytes = param2 == null ? new byte[0] : param2.getBytes(StandardCharsets.UTF_8); |
||||
byte[] param3Bytes = param3 == null ? new byte[0] : param3.getBytes(StandardCharsets.UTF_8); |
||||
byte[] bytes = new byte[2 + 4 + 4 + param1Bytes.length + 4 + param2Bytes.length + 4 + param3Bytes.length]; |
||||
|
||||
int offset = 0; |
||||
Bytes.short2bytes(MAGIC, bytes, offset); |
||||
offset += 2; |
||||
Bytes.int2bytes(cmdType, bytes, offset); |
||||
offset += 4; |
||||
Bytes.int2bytes(param1Bytes.length, bytes, offset); |
||||
offset += 4; |
||||
System.arraycopy(param1Bytes, 0, bytes, offset, param1Bytes.length); |
||||
offset += param1Bytes.length; |
||||
|
||||
Bytes.int2bytes(param2Bytes.length, bytes, offset); |
||||
offset += 4; |
||||
System.arraycopy(param2Bytes, 0, bytes, offset, param2Bytes.length); |
||||
offset += param2Bytes.length; |
||||
|
||||
Bytes.int2bytes(param3Bytes.length, bytes, offset); |
||||
offset += 4; |
||||
System.arraycopy(param3Bytes, 0, bytes, offset, param3Bytes.length); |
||||
offset += param3Bytes.length; |
||||
return bytes; |
||||
} |
||||
|
||||
public static SyncCmd read(ByteBuf buf) { |
||||
short magic = buf.readShort(); |
||||
if (magic != MAGIC) { |
||||
throw new IllegalStateException("unknown bytes magic error"); |
||||
} |
||||
SyncCmd cmd = new SyncCmd(); |
||||
cmd.cmdType = buf.readInt(); |
||||
int param1Len = buf.readInt(); |
||||
byte[] paramBytes = new byte[param1Len]; |
||||
if (param1Len > 0) { |
||||
buf.readBytes(paramBytes); |
||||
cmd.param1 = new String(paramBytes, StandardCharsets.UTF_8); |
||||
} |
||||
int param2Len = buf.readInt(); |
||||
if (param2Len > 0) { |
||||
paramBytes = paramBytes.length >= param2Len ? paramBytes : new byte[param2Len]; |
||||
buf.readBytes(paramBytes, 0, param2Len); |
||||
cmd.param2 = new String(paramBytes, 0, param2Len, StandardCharsets.UTF_8); |
||||
} |
||||
int param3Len = buf.readInt(); |
||||
if (param3Len > 0) { |
||||
paramBytes = paramBytes.length >= param3Len ? paramBytes : new byte[param3Len]; |
||||
buf.readBytes(paramBytes, 0, param3Len); |
||||
cmd.param3 = new String(paramBytes, 0, param3Len, StandardCharsets.UTF_8); |
||||
} |
||||
return cmd; |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
AtomicBoolean locked = new AtomicBoolean(false); |
||||
System.out.println(locked.compareAndSet(false, false)); |
||||
System.out.println(locked.compareAndExchange(false, true)); |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,41 @@
|
||||
package net.sopod.soim.router.datasync.server.handler; |
||||
|
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.SimpleChannelInboundHandler; |
||||
import net.sopod.soim.router.datasync.server.data.SyncCmd; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* SyncHandler |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-07 21:43 |
||||
*/ |
||||
public class SyncCmdClientHandler extends SimpleChannelInboundHandler<SyncCmd> { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SyncCmdClientHandler.class); |
||||
|
||||
@Override |
||||
protected void channelRead0(ChannelHandlerContext ctx, SyncCmd syncCmd) { |
||||
switch (syncCmd.getCmdType()) { |
||||
case SyncCmd.PING: |
||||
this.handlePing(ctx, syncCmd); |
||||
break; |
||||
case SyncCmd.PONG: |
||||
this.handlePong(ctx, syncCmd); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
private void handlePing(ChannelHandlerContext ctx, SyncCmd syncCmd) { |
||||
logger.info("ping: {}", ctx.channel()); |
||||
SyncCmd pong = new SyncCmd().setCmdType(SyncCmd.PONG); |
||||
ctx.writeAndFlush(pong); |
||||
} |
||||
|
||||
private void handlePong(ChannelHandlerContext ctx, SyncCmd syncCmd) { |
||||
logger.info("pong: {}", ctx.channel()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
|
||||
package net.sopod.soim.router.datasync.server.handler; |
||||
|
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.SimpleChannelInboundHandler; |
||||
import net.sopod.soim.router.datasync.server.data.SyncCmd; |
||||
|
||||
/** |
||||
* SyncCmdServerHandler |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-08 18:48 |
||||
*/ |
||||
public class SyncCmdServerHandler extends SimpleChannelInboundHandler<SyncCmd> { |
||||
|
||||
@Override |
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, SyncCmd syncCmd) throws Exception { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@
|
||||
package net.sopod.soim.router.datasync.server.handler; |
||||
|
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.SimpleChannelInboundHandler; |
||||
import net.sopod.soim.router.datasync.server.data.SyncLog; |
||||
|
||||
/** |
||||
* SyncLogHandler |
||||
* 其他节点会推送同步数据到当前新增的节点,这里接收数据 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-08 17:20 |
||||
*/ |
||||
public class SyncLogClientHandler extends SimpleChannelInboundHandler<SyncLog> { |
||||
|
||||
@Override |
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, SyncLog syncLog) throws Exception { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@
|
||||
package net.sopod.soim.router.datasync.server.handler; |
||||
|
||||
import io.netty.channel.ChannelHandlerContext; |
||||
import io.netty.channel.SimpleChannelInboundHandler; |
||||
import net.sopod.soim.router.datasync.server.data.SyncLog; |
||||
|
||||
/** |
||||
* SyncLogServerHandler |
||||
* 即将删除的节点:会主动推送同步数据,这里进行接收 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-08 18:48 |
||||
*/ |
||||
public class SyncLogServerHandler extends SimpleChannelInboundHandler<SyncLog> { |
||||
|
||||
@Override |
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, SyncLog syncLog) throws Exception { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,56 @@
|
||||
package net.sopod.soim.router.datasync.server.session; |
||||
|
||||
import net.sopod.soim.router.datasync.server.data.SyncCmd; |
||||
import net.sopod.soim.router.datasync.server.SyncServer; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* SyncSession |
||||
* 作为客户端或服务端主动操作连接 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-08 17:34 |
||||
*/ |
||||
public class SyncSession { |
||||
private static final Logger logger = LoggerFactory.getLogger(SyncSession.class); |
||||
|
||||
public static SyncSession client() { |
||||
return null; |
||||
} |
||||
|
||||
public static SyncSession server() { |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public static class SyncSessionServer { |
||||
|
||||
private final SyncServer syncServer; |
||||
|
||||
public SyncSessionServer(int port) { |
||||
this.syncServer = new SyncServer(); |
||||
this.syncServer.start(9999, err -> { |
||||
logger.error("sync server start fail!", err); |
||||
}); |
||||
} |
||||
|
||||
public void writeTo() { |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
public static class SyncSessionClient { |
||||
|
||||
public SyncSessionClient() { |
||||
|
||||
} |
||||
|
||||
public void write(SyncCmd syncCmd) { |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue