From 78c8ee1c2cf33cf30b182144adb20f102de8d806 Mon Sep 17 00:00:00 2001 From: HttpMarco Date: Tue, 26 Nov 2024 19:31:31 +0100 Subject: [PATCH] Generate abstract server class for server and node --- .../netline/channel/NetClientChannel.java | 1 - .../httpmarco/netline/node/NetNodeConfig.java | 10 +++ .../httpmarco/netline/node/NetNodeState.java | 19 +++++ .../netline/server/AbstractNetServer.java | 69 +++++++++++++++ .../httpmarco/netline/server/NetServer.java | 85 ++++++------------- .../httpmarco/netline/NetLineTestSuite.java | 2 +- .../dev/httpmarco/netline/tests/NodeTest.java | 28 ++++++ 7 files changed, 154 insertions(+), 60 deletions(-) create mode 100644 src/main/java/dev/httpmarco/netline/node/NetNodeConfig.java create mode 100644 src/main/java/dev/httpmarco/netline/node/NetNodeState.java create mode 100644 src/main/java/dev/httpmarco/netline/server/AbstractNetServer.java create mode 100644 src/test/java/dev/httpmarco/netline/tests/NodeTest.java diff --git a/src/main/java/dev/httpmarco/netline/channel/NetClientChannel.java b/src/main/java/dev/httpmarco/netline/channel/NetClientChannel.java index c186453..15e89ac 100644 --- a/src/main/java/dev/httpmarco/netline/channel/NetClientChannel.java +++ b/src/main/java/dev/httpmarco/netline/channel/NetClientChannel.java @@ -1,7 +1,6 @@ package dev.httpmarco.netline.channel; import dev.httpmarco.netline.NetChannel; -import dev.httpmarco.netline.NetComp; import dev.httpmarco.netline.packet.Packet; import dev.httpmarco.netline.request.Request; import dev.httpmarco.netline.server.NetServer; diff --git a/src/main/java/dev/httpmarco/netline/node/NetNodeConfig.java b/src/main/java/dev/httpmarco/netline/node/NetNodeConfig.java new file mode 100644 index 0000000..6dbce34 --- /dev/null +++ b/src/main/java/dev/httpmarco/netline/node/NetNodeConfig.java @@ -0,0 +1,10 @@ +package dev.httpmarco.netline.node; + +import dev.httpmarco.netline.config.CompConfig; + +public final class NetNodeConfig extends CompConfig { + + public NetNodeConfig() { + super("0.0.0.0", 9091, true, 5); + } +} diff --git a/src/main/java/dev/httpmarco/netline/node/NetNodeState.java b/src/main/java/dev/httpmarco/netline/node/NetNodeState.java new file mode 100644 index 0000000..54a5fce --- /dev/null +++ b/src/main/java/dev/httpmarco/netline/node/NetNodeState.java @@ -0,0 +1,19 @@ +package dev.httpmarco.netline.node; + +public enum NetNodeState { + + // if node is present, but not started booting + INITIALIZING, + // if node is booting and failed to bind to cluster + FAILED, + // if node is booting and binding to cluster (ip pool) + BIND_CLUSTER, + // if node is booting and syncing with cluster + SYNC_CLUSTER, + // if node is booting and ready to accept connections + READY, + // if node is shutting down + CLOSED + + +} diff --git a/src/main/java/dev/httpmarco/netline/server/AbstractNetServer.java b/src/main/java/dev/httpmarco/netline/server/AbstractNetServer.java new file mode 100644 index 0000000..e9d12ff --- /dev/null +++ b/src/main/java/dev/httpmarco/netline/server/AbstractNetServer.java @@ -0,0 +1,69 @@ +package dev.httpmarco.netline.server; + +import dev.httpmarco.netline.NetChannel; +import dev.httpmarco.netline.NetCompHandler; +import dev.httpmarco.netline.channel.NetChannelInitializer; +import dev.httpmarco.netline.config.CompConfig; +import dev.httpmarco.netline.impl.AbstractNetCompImpl; +import dev.httpmarco.netline.utils.NetworkUtils; +import io.netty5.bootstrap.ServerBootstrap; +import io.netty5.channel.ChannelOption; +import io.netty5.channel.EventLoopGroup; +import io.netty5.channel.epoll.Epoll; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +public abstract class AbstractNetServer extends AbstractNetCompImpl { + + private final EventLoopGroup workerGroup = NetworkUtils.createEventLoopGroup(0); + + public AbstractNetServer(C config) { + super(1, config); + } + + + @Override + public CompletableFuture boot() { + var future = new CompletableFuture(); + + var bootstrap = new ServerBootstrap() + .group(bossGroup(), workerGroup) + .childHandler(new NetChannelInitializer(handler())) + .channelFactory(NetworkUtils.generateChannelFactory()) + .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.IP_TOS, 24) + .childOption(ChannelOption.SO_KEEPALIVE, true); + + if (config().tryTcpFastOpen() && Epoll.isTcpFastOpenServerSideAvailable()) { + bootstrap.childOption(ChannelOption.TCP_FASTOPEN_CONNECT, true); + } + + bootstrap.bind(config().hostname(), config().port()).addListener(it -> { + if(it.isSuccess()) { + this.onBindSuccess(); + future.complete(null); + return; + } + this.onBindFail(it.cause()); + future.completeExceptionally(it.cause()); + }); + + return future; + } + + @Override + public @NotNull CompletableFuture close() { + var future = new CompletableFuture(); + this.bossGroup().shutdownGracefully().addListener(it -> onClose().whenComplete((unused, throwable) -> future.complete(null))); + return future; + } + + public abstract CompletableFuture onClose(); + + public abstract void onBindFail(Throwable throwable); + + public abstract void onBindSuccess(); + + public abstract NetCompHandler handler(); +} diff --git a/src/main/java/dev/httpmarco/netline/server/NetServer.java b/src/main/java/dev/httpmarco/netline/server/NetServer.java index 3b62551..43aae5c 100644 --- a/src/main/java/dev/httpmarco/netline/server/NetServer.java +++ b/src/main/java/dev/httpmarco/netline/server/NetServer.java @@ -1,20 +1,14 @@ package dev.httpmarco.netline.server; import dev.httpmarco.netline.NetChannel; -import dev.httpmarco.netline.channel.NetChannelInitializer; +import dev.httpmarco.netline.NetCompHandler; import dev.httpmarco.netline.channel.NetClientChannel; -import dev.httpmarco.netline.impl.AbstractNetCompImpl; import dev.httpmarco.netline.packet.Packet; import dev.httpmarco.netline.packet.common.ChannelIdentifyPacket; import dev.httpmarco.netline.request.ResponderRegisterPacket; import dev.httpmarco.netline.security.SecurityHandler; import dev.httpmarco.netline.tracking.server.ClientConnectedTracking; -import dev.httpmarco.netline.utils.NetworkUtils; -import io.netty5.bootstrap.ServerBootstrap; import io.netty5.channel.Channel; -import io.netty5.channel.ChannelOption; -import io.netty5.channel.EventLoopGroup; -import io.netty5.channel.epoll.Epoll; import lombok.Getter; import lombok.experimental.Accessors; import org.jetbrains.annotations.Contract; @@ -26,51 +20,18 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; +@Getter @Accessors(fluent = true) -public final class NetServer extends AbstractNetCompImpl { - - private final EventLoopGroup workerGroup = NetworkUtils.createEventLoopGroup(0); - @Getter - @NotNull - private final List clients = new CopyOnWriteArrayList<>(); - @Getter +public final class NetServer extends AbstractNetServer { @NotNull private NetServerState state = NetServerState.INITIALIZE; - @Getter + @NotNull + private final List clients = new CopyOnWriteArrayList<>(); @Nullable private SecurityHandler securityHandler; public NetServer() { - super(1, new NetServerConfig()); - } - - @Override - public CompletableFuture boot() { - this.state = NetServerState.BOOTING; - var future = new CompletableFuture(); - - var bootstrap = new ServerBootstrap() - .group(bossGroup(), workerGroup) - .childHandler(new NetChannelInitializer(new NetServerHandler(this))) - .channelFactory(NetworkUtils.generateChannelFactory()) - .childOption(ChannelOption.TCP_NODELAY, true) - .childOption(ChannelOption.IP_TOS, 24) - .childOption(ChannelOption.SO_KEEPALIVE, true); - - - if (config().tryTcpFastOpen() && Epoll.isTcpFastOpenServerSideAvailable()) { - bootstrap.childOption(ChannelOption.TCP_FASTOPEN_CONNECT, true); - } - - bootstrap.bind(config().hostname(), config().port()).addListener(it -> { - if(it.isSuccess()) { - this.state = NetServerState.BOOTED; - future.complete(null); - return; - } - this.state = NetServerState.FAILED; - future.completeExceptionally(it.cause()); - }); + super(new NetServerConfig()); responderOf("channel_identification", (channel, properties) -> { this.clients.add((NetClientChannel) channel); @@ -79,19 +40,6 @@ public CompletableFuture boot() { }); track(ResponderRegisterPacket.class, (channel, packet) -> responders().put(packet.id(), (channel1, stringStringMap) -> channel.request(packet.id(), Packet.class).sync())); - return future; - } - - @Override - public @NotNull CompletableFuture close() { - var future = new CompletableFuture(); - - this.bossGroup().shutdownGracefully().addListener(it -> CompletableFuture.allOf(this.clients.stream().map(NetChannel::close).toArray(CompletableFuture[]::new)).whenComplete((unused, throwable) -> { - this.clients.clear(); - this.state = NetServerState.CLOSED; - future.complete(null); - })); - return future; } @Override @@ -112,6 +60,27 @@ public void send(String id, Packet packet) { public void send(Predicate predicate, Packet packet) { this.clients.stream().filter(predicate).forEach(channel -> channel.send(packet)); } + @Override + public CompletableFuture onClose() { + var future = CompletableFuture.allOf(this.clients.stream().map(NetClientChannel::close).toArray(CompletableFuture[]::new)); + this.state = NetServerState.CLOSED; + return future; + } + + @Override + public void onBindFail(Throwable throwable) { + this.state = NetServerState.FAILED; + } + + @Override + public void onBindSuccess() { + this.state = NetServerState.BOOTED; + } + + @Override + public NetCompHandler handler() { + return new NetServerHandler(this); + } public void withSecurityPolicy(SecurityHandler securityHandler) { this.securityHandler = securityHandler; diff --git a/src/test/java/dev/httpmarco/netline/NetLineTestSuite.java b/src/test/java/dev/httpmarco/netline/NetLineTestSuite.java index 318e83a..bd4ce35 100644 --- a/src/test/java/dev/httpmarco/netline/NetLineTestSuite.java +++ b/src/test/java/dev/httpmarco/netline/NetLineTestSuite.java @@ -7,7 +7,7 @@ @Suite @SelectClasses({ - CompBindingTest.class, PacketTransmitTest.class, SecurityListTest.class, PacketRequestTest.class, BroadcastTest.class + CompBindingTest.class, PacketTransmitTest.class, SecurityListTest.class, PacketRequestTest.class, BroadcastTest.class, NodeTest.class }) @SuiteDisplayName("NetLine Test Suite") public class NetLineTestSuite { diff --git a/src/test/java/dev/httpmarco/netline/tests/NodeTest.java b/src/test/java/dev/httpmarco/netline/tests/NodeTest.java new file mode 100644 index 0000000..43d96bc --- /dev/null +++ b/src/test/java/dev/httpmarco/netline/tests/NodeTest.java @@ -0,0 +1,28 @@ +package dev.httpmarco.netline.tests; + +import dev.httpmarco.netline.node.NetNodeState; +import org.junit.jupiter.api.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@DisplayName("5 - Node cluster test") +public class NodeTest { + + /* + private static NetNode node; + + @BeforeAll + public static void beforeHandling() { + node = new NetNode(); + } + + @Test + @Order(1) + @DisplayName("5.1 Start first node") + public void testState() { + assert node.state() == NetNodeState.INITIALIZING; + node.bootSync(); + assert node.state() == NetNodeState.READY; + } + + */ +}