Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #7

Merged
merged 49 commits into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
bafe6a7
Add default netty client things
HttpMarco Mar 24, 2024
05f7934
Work on client
HttpMarco Mar 24, 2024
ec32a01
Add reconnect queue
HttpMarco Mar 25, 2024
9e1859c
Add netty server
HttpMarco Mar 25, 2024
b163075
Update version
HttpMarco Mar 25, 2024
8cee021
Move files
HttpMarco Mar 25, 2024
4408303
Change small things
HttpMarco Mar 25, 2024
53f21b3
Add isAlive and is connected method
HttpMarco Mar 25, 2024
85be552
Add packet codec
HttpMarco Mar 25, 2024
5fe0750
Add packet buffer
HttpMarco Mar 26, 2024
3ccd9c6
Add abstract packet buffer formatter
HttpMarco Mar 26, 2024
eccec74
Add read and write String method
HttpMarco Mar 26, 2024
36f32b7
Add write and read classname
HttpMarco Mar 26, 2024
846406d
Remove PacketBuffer.java and AbstractByteToPacketBufferCodec.java and…
HttpMarco Mar 27, 2024
9f21467
Remove single client handler
HttpMarco Mar 27, 2024
7a53048
Add component communication handler
HttpMarco Mar 27, 2024
1a278c2
Improve CommunicationComponent
HttpMarco Mar 27, 2024
8b74a77
Improve netty communication handler
HttpMarco Mar 27, 2024
f02c0bc
Move files
HttpMarco Mar 27, 2024
a2d4f73
Delete connector
HttpMarco Mar 27, 2024
a0cace6
Remove client tests
HttpMarco Mar 27, 2024
8a4071c
Delete old codec
HttpMarco Mar 27, 2024
58b5725
Move class
HttpMarco Mar 27, 2024
f1cad46
Add reflections
HttpMarco Mar 27, 2024
5667fa5
Add own consumer logic
HttpMarco Mar 27, 2024
f930e41
Better tests
HttpMarco Mar 27, 2024
90ba199
Add codec classes
HttpMarco Mar 27, 2024
137259c
Improve code and implement event packet logic
HttpMarco Mar 27, 2024
a6548a3
Add simple parameter codec
HttpMarco Mar 27, 2024
e4c2b3b
Add secondary models
HttpMarco Mar 27, 2024
6406048
Add array read
HttpMarco Mar 27, 2024
1bea67d
Complete array sending
HttpMarco Mar 27, 2024
d8d7169
Complete collections
HttpMarco Mar 27, 2024
84f1402
Fix collections and implement packet listener
HttpMarco Mar 27, 2024
518daa9
Add client id
HttpMarco Mar 27, 2024
22bec71
Complete channel ids
HttpMarco Mar 27, 2024
2a59288
Fix channel listeners
HttpMarco Mar 27, 2024
5f13c47
Add responder system
HttpMarco Mar 27, 2024
737fefa
added request/response + fixes
Thiies Mar 28, 2024
b295e14
write fieldname to buffer to prevent wrong data encoding
Thiies Mar 28, 2024
c74b372
WIP: netty dynamic buffer allocation
Thiies Mar 28, 2024
9d78b3b
WIP: fix netty
Thiies Apr 1, 2024
3b84f7a
Netty fix
Thiies Apr 1, 2024
1b686c0
using lengthdecoder in netty - 1.1.0-SNAPSHOT
Thiies Apr 2, 2024
1d6e76b
correctly unregistering responders
Thiies Apr 2, 2024
2762537
registering channels correctly
Thiies Apr 2, 2024
68c3f8a
Merge pull request #5 from Thiies/dev-netty
HttpMarco Apr 6, 2024
6d52889
Fix reconnect queue and small code improvements
HttpMarco Apr 7, 2024
38e69c3
small method change + bump version
Thiies Apr 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ allprojects {
apply(plugin = "java-library")
apply(plugin = "maven-publish")


group = "dev.httpmarco"
version = "1.0.26-SNAPSHOT"
version = "1.1.4-SNAPSHOT"

repositories {
mavenCentral()
Expand Down Expand Up @@ -67,11 +66,11 @@ allprojects {
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
nexusUrl.set(uri("https://nexus.bytemc.de/repository/maven-public/"))
snapshotRepositoryUrl.set(uri("https://nexus.bytemc.de/repository/maven-public/"))

username.set(System.getenv("ossrhUsername")?.toString() ?: "")
password.set(System.getenv("ossrhPassword")?.toString() ?: "")
username.set(System.getenv("BYTEMC_REPO_USER")?.toString() ?: "")
password.set(System.getenv("BYTEMC_REPO_PASSWORD")?.toString() ?: "")
}
}
useStaging.set(!project.rootProject.version.toString().endsWith("-SNAPSHOT"))
Expand Down
6 changes: 6 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ lombok = "1.18.32"

gson = "2.10.1"

#networking
netty5 = "5.0.0.Alpha5"

[libraries]
lombok = { group = "org.projectlombok", name="lombok", version.ref = "lombok" }
annotations = { group = "org.jetbrains", name="annotations", version.ref = "annotations" }
gson = { group = "com.google.code.gson", name="gson", version.ref = "gson" }

#networking
netty5 = { group = "io.netty", name = "netty5-all", version.ref = "netty5" }

[plugins]
nexusPublish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexusPublish" }
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public JsonObjectSerializer(String gsonObject) {
this.jsonObject = JsonUtils.getGson().fromJson(gsonObject, JsonObject.class);
}

public boolean has(String key) {
return jsonObject.has(key);
}

public JsonObjectSerializer append(String key, String value) {
jsonObject.addProperty(key, value);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
public class JsonUtils {

private static final Gson JSON = new GsonBuilder()
.disableHtmlEscaping()
.setExclusionStrategies(new JsonByteExclusionStrategy())
.create();
private static final Gson PRETTY_JSON = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setExclusionStrategies(new JsonByteExclusionStrategy())
.create();

Expand Down
18 changes: 18 additions & 0 deletions osgan-netty/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
dependencies {
implementation(libs.netty5)
compileOnly(libs.gson)
api(project(":osgan-utils"))
api(project(":osgan-files"))
api(project(":osgan-reflections"))

testImplementation(platform("org.junit:junit-bom:5.10.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.test {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.httpmarco.osgan.networking;

import lombok.Getter;
import lombok.experimental.Accessors;

@Getter
@Accessors(fluent = true)
public abstract class AbstractCommunicationComponentBuilder<R extends CommunicationComponent<?>, B extends AbstractCommunicationComponentBuilder<R, ?>> {

private String hostname = "0.0.0.0";
private int port = 9090;

public B withPort(int port) {
this.port = port;
return (B) this;
}

public B withHostname(String hostname) {
this.hostname = hostname;
return (B) this;
}

public abstract R build();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package dev.httpmarco.osgan.networking;

@FunctionalInterface
public interface ChannelConsumer {

void listen(ChannelTransmit channel);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.httpmarco.osgan.networking;

import dev.httpmarco.osgan.networking.codec.PacketDecoder;
import dev.httpmarco.osgan.networking.codec.PacketEncoder;
import io.netty5.channel.Channel;
import io.netty5.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty5.handler.codec.LengthFieldPrepender;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull;

@Setter
@Accessors(fluent = true)
@AllArgsConstructor
public final class ChannelInitializer extends io.netty5.channel.ChannelInitializer<Channel> {

private final CommunicationComponentHandler communicationComponentHandler;

@Override
protected void initChannel(@NotNull Channel channel) {
channel.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, Integer.BYTES, 0, Integer.BYTES))
.addLast(new PacketDecoder())
.addLast(new LengthFieldPrepender(Integer.BYTES))
.addLast(new PacketEncoder())
.addLast(communicationComponentHandler);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.httpmarco.osgan.networking;

import dev.httpmarco.osgan.networking.packet.ForwardPacket;
import io.netty5.buffer.Buffer;
import io.netty5.channel.Channel;
import io.netty5.util.concurrent.Future;
import lombok.*;
import lombok.experimental.Accessors;

import java.util.concurrent.CompletableFuture;

@Getter
@Accessors(fluent = true)
@RequiredArgsConstructor
@EqualsAndHashCode(exclude = "id")
public final class ChannelTransmit {

@Setter
private String id = "unknown";
private final Channel channel;

public <P extends Packet> void sendPacket(P object) {
this.sendPacket(this.channel, object);
}

public void sendPacket(Channel channel, Packet object) {
this.writeAndFlush(channel, object);
}

public void redirectPacket(String id, Packet object) {
this.sendPacket(new ForwardPacket(id, object));
}

@SneakyThrows
private void writeAndFlush(Channel channel, Packet packet) {
packet.getBuffer().getOrigin().readerOffset(0);

channel.writeAndFlush(packet);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package dev.httpmarco.osgan.networking;

import dev.httpmarco.osgan.files.json.JsonObjectSerializer;
import dev.httpmarco.osgan.networking.listening.ChannelPacketListener;
import dev.httpmarco.osgan.networking.request.PacketResponder;
import dev.httpmarco.osgan.networking.request.RequestHandler;
import dev.httpmarco.osgan.utils.executers.FutureResult;
import io.netty5.channel.Channel;
import io.netty5.channel.EventLoopGroup;
import io.netty5.util.concurrent.FutureListener;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

@Getter
@Accessors(fluent = true)
public abstract class CommunicationComponent<M extends Metadata> {

@Setter
private FutureResult<Void> connectionFuture = new FutureResult<>();

private final M metadata;
private final EventLoopGroup bossGroup;
private final Map<Class<? extends Packet>, List<ChannelPacketListener<? extends Packet>>> packetListeners = new HashMap<>();
private final RequestHandler requestHandler;

public CommunicationComponent(M metadata, int workerThreads) {
this.bossGroup = NetworkUtils.createEventLoopGroup(workerThreads);
this.metadata = metadata;
this.requestHandler = new RequestHandler(this);
}

public abstract <P extends Packet> void sendPacket(P packet);

public abstract <P extends Packet> void sendPacket(Channel channel, P packet);

public abstract <P extends Packet> void redirectPacket(String id, P packet);

public FutureListener<? super Channel> handleConnectionRelease() {
return it -> {
if (it.isSuccess()) {
connectionFuture.complete(null);
it.getNow().closeFuture();
} else {
connectionFuture.completeExceptionally(it.cause());
}
};
}

public boolean isConnected() {
return connectionFuture.isDone();
}

public boolean isAlive() {
return !bossGroup.isShutdown() && !bossGroup.isTerminated() && !bossGroup.isShuttingDown();
}

public void close() {
bossGroup.shutdownGracefully();
}

public void callPacketReceived(ChannelTransmit transmit, Packet packet) {
if (this.packetListeners.containsKey(packet.getClass())) {
this.packetListeners.get(packet.getClass()).forEach(it -> it.listenWithMapping(transmit, packet));
}
}

public <P extends Packet> void listen(Class<P> packetClass, ChannelPacketListener<P> listener) {
this.packetListeners.computeIfAbsent(packetClass, it -> new ArrayList<>()).add(listener);
}

public <T extends Packet> void request(String id, Class<T> responsePacket, Consumer<T> consumer) {
this.requestHandler.request(id, responsePacket, consumer);
}

public <T extends Packet> void request(String id, JsonObjectSerializer properties, Class<T> responsePacket, Consumer<T> consumer) {
this.requestHandler.request(id, properties, responsePacket, consumer);
}

public <T extends Packet> void registerResponder(String id, PacketResponder<T> responder) {
this.requestHandler.registerResponder(id, responder);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.httpmarco.osgan.networking;

import dev.httpmarco.osgan.networking.listening.ChannelPacketListener;
import io.netty5.channel.Channel;
import io.netty5.channel.ChannelHandlerContext;
import io.netty5.channel.SimpleChannelInboundHandler;
import lombok.Builder;
import org.jetbrains.annotations.NotNull;

@Builder
public final class CommunicationComponentHandler extends SimpleChannelInboundHandler<Packet> {

private ChannelConsumer onActive, onInactive;
private ChannelPacketListener<? extends Packet> onPacketReceived;

@Override
protected void messageReceived(ChannelHandlerContext ctx, Packet packet) {
this.onPacketReceived.listenWithMapping(new ChannelTransmit(ctx.channel()), packet);
System.out.println("Received packet " + packet.getClass().getSimpleName() + " from " + ctx.channel().remoteAddress());
}

@Override
public void channelActive(@NotNull ChannelHandlerContext ctx) {
this.supplyChannelTransmit(ctx.channel(), this.onActive);
System.out.println("Channel active: " + ctx.channel().remoteAddress());
}

@Override
public void channelInactive(@NotNull ChannelHandlerContext ctx) {
this.supplyChannelTransmit(ctx.channel(), this.onInactive);
System.out.println("Connection closed with " + ctx.channel().remoteAddress());
}

@Override
public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if(!cause.getMessage().equals("Connection reset")) cause.printStackTrace();
}

private void supplyChannelTransmit(Channel channel, ChannelConsumer consumer) {
if (consumer != null) {
consumer.listen(new ChannelTransmit(channel));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.httpmarco.osgan.networking;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;

@Getter
@Accessors(fluent = true)
@AllArgsConstructor
public abstract class Metadata {

// connection host address
private String hostname;
// connection port
private int port;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dev.httpmarco.osgan.networking;

import io.netty5.channel.EventLoop;
import io.netty5.channel.MultithreadEventLoopGroup;
import io.netty5.channel.ServerChannel;
import io.netty5.channel.ServerChannelFactory;
import io.netty5.channel.epoll.Epoll;
import io.netty5.channel.epoll.EpollHandler;
import io.netty5.channel.epoll.EpollServerSocketChannel;
import io.netty5.channel.epoll.EpollSocketChannel;
import io.netty5.channel.nio.NioHandler;
import io.netty5.channel.socket.SocketChannel;
import io.netty5.channel.socket.nio.NioServerSocketChannel;
import io.netty5.channel.socket.nio.NioSocketChannel;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

@UtilityClass
public class NetworkUtils {

@Contract("_ -> new")
public static @NotNull MultithreadEventLoopGroup createEventLoopGroup(int threads) {
return new MultithreadEventLoopGroup(threads, Epoll.isAvailable() ? EpollHandler.newFactory() : NioHandler.newFactory());
}

public static @NotNull SocketChannel createChannelFactory(EventLoop loop) {
return Epoll.isAvailable() ? new EpollSocketChannel(loop) : new NioSocketChannel(loop);
}

public static ServerChannelFactory<? extends ServerChannel> generateChannelFactory() {
return Epoll.isAvailable() ? EpollServerSocketChannel::new : NioServerSocketChannel::new;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.httpmarco.osgan.networking;

import dev.httpmarco.osgan.files.annotations.ConfigExclude;
import dev.httpmarco.osgan.networking.codec.CodecBuffer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public abstract class Packet {
@ConfigExclude
private final CodecBuffer buffer;

public Packet() {
this.buffer = CodecBuffer.allocate();
}
}
Loading