Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id "java"
}

dependencies {

}

java {
// leave it on java 17 to be compatible with older versions and we dont really need 21 there anyway
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
withSourcesJar()
}
7 changes: 7 additions & 0 deletions api/src/main/java/de/rafael/modflared/api/ModflaredApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package de.rafael.modflared.api;

import de.rafael.modflared.api.tunnel.IModflaredApiTunnel;

public class ModflaredApi {
public static IModflaredApiTunnel IAPITUNNEL = null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.rafael.modflared.api.tunnel;

@SuppressWarnings("unused")
public interface IModflaredApiTunnel {
/**
* Returns true if this is a modflared tunnel.
* */
default boolean isModflaredTunnel(String host, int port) {
return false;
}

/**
* Add a tunnel dependency.
* */
void addTunnelDependency(String host, int port, String id);

/**
* Remove a tunnel dependency.
* */
void removeTunnelDependency(String host, int port, String id);
}
5 changes: 0 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ allprojects {
// for more information about repositories.
}

tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
options.release = 21
}

java {
withSourcesJar()
}
Expand Down
1 change: 1 addition & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
compileOnly(project(":api"))
}

publishing {
Expand Down
4 changes: 3 additions & 1 deletion common/src/main/java/de/rafael/modflared/Modflared.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import de.rafael.modflared.api.ModflaredApi;
import de.rafael.modflared.platform.LoaderPlatform;
import de.rafael.modflared.tunnel.manager.TunnelManager;
import org.slf4j.Logger;
Expand All @@ -24,9 +25,10 @@ public class Modflared {
public static void init() {
TUNNEL_MANAGER.prepareBinary();
TUNNEL_MANAGER.loadForcedTunnels();
ModflaredApi.IAPITUNNEL = TUNNEL_MANAGER;

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
TUNNEL_MANAGER.closeTunnels();
TUNNEL_MANAGER.forceCloseTunnels();
EXECUTOR.shutdownNow();
}));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private static ChannelFuture connect(@NotNull InetSocketAddress address, boolean
public void disconnect(Text disconnectReason, CallbackInfo callbackInfo) {
synchronized(this) {
if(this.modflared$runningTunnel != null) {
Modflared.TUNNEL_MANAGER.closeTunnel(this.modflared$runningTunnel);
Modflared.TUNNEL_MANAGER.closeTunnel(this.modflared$runningTunnel, "modflared", false);
this.modflared$runningTunnel = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.io.*;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.zip.CRC32;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.gson.JsonParser;
import de.rafael.modflared.Modflared;
import de.rafael.modflared.ModflaredPlatform;
import de.rafael.modflared.api.tunnel.IModflaredApiTunnel;
import de.rafael.modflared.binary.Cloudflared;
import de.rafael.modflared.interfaces.mixin.IClientConnection;
import de.rafael.modflared.tunnel.RunningTunnel;
Expand All @@ -27,12 +28,10 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

public class TunnelManager {
public class TunnelManager implements IModflaredApiTunnel {

public static final File BASE_FOLDER = ModflaredPlatform.getGameDir().resolve("modflared/").toFile();
public static final File DATA_FOLDER = new File(BASE_FOLDER, "bin/");
Expand All @@ -43,29 +42,40 @@ public class TunnelManager {
private final AtomicReference<Cloudflared> cloudflared = new AtomicReference<>();
private final List<ServerAddress> forcedTunnels = new ArrayList<>();

private final List<RunningTunnel> runningTunnels = new ArrayList<>();
private final Map<RunningTunnel, List<String>> runningTunnels = new HashMap<>();

public RunningTunnel createTunnel(String host) {
var binary = this.cloudflared.get();
if (binary != null) {
Modflared.LOGGER.info("Starting tunnel to {}", host);
var process = binary.createTunnel(RunningTunnel.Access.localWithRandomPort(host));
if (process == null) return null;
this.runningTunnels.add(process);
this.runningTunnels.put(process, new ArrayList<>(Collections.singleton("modflared")));
return process;
} else {
return null;
}
}

public void closeTunnel(@NotNull RunningTunnel runningTunnel) {
Modflared.LOGGER.info("Stopping tunnel to {}", runningTunnel.access().tunnelAddress());
public void closeTunnel(@NotNull RunningTunnel runningTunnel, String dependencyId, boolean force) {
if (force) {
Modflared.LOGGER.info("Stopping tunnel to {}", runningTunnel.access().tunnelAddress());
} else {
List<String> dependencies = runningTunnels.get(runningTunnel);
dependencies.remove(dependencyId);
if (dependencies.isEmpty()) {
Modflared.LOGGER.info("Closing tunnel to {} as no more dependencies are using it", runningTunnel.access().tunnelAddress());
} else {
runningTunnels.put(runningTunnel, dependencies);
return;
}
}
this.runningTunnels.remove(runningTunnel);
runningTunnel.closeTunnel();
}

public void closeTunnels() {
for (RunningTunnel runningTunnel : this.runningTunnels) {
public void forceCloseTunnels() {
for (RunningTunnel runningTunnel : this.runningTunnels.keySet()) {
runningTunnel.closeTunnel();
}
}
Expand Down Expand Up @@ -230,4 +240,37 @@ public static void displayErrorToast() {
MinecraftClient.getInstance().getToastManager().add(new SystemToast(SystemToast.Type.PERIODIC_NOTIFICATION, Text.translatable("gui.toast.title.error"), Text.translatable("gui.toast.body.error")));
}

@Override
public boolean isModflaredTunnel(String host, int port) {
return getRunningTunnel(host, port) != null;
}

@Override
public void addTunnelDependency(String host, int port, String id) {
RunningTunnel tunnel = getRunningTunnel(host, port);
if (tunnel != null) {
this.runningTunnels.computeIfAbsent(tunnel, k -> new ArrayList<>()).add(id);
} else {
Modflared.LOGGER.warn("No running tunnel found for {}:{}", host, port);
}
}

@Override
public void removeTunnelDependency(String host, int port, String id) {
RunningTunnel tunnel = getRunningTunnel(host, port);
if (tunnel != null) {
closeTunnel(tunnel, id, false);
} else {
Modflared.LOGGER.warn("No running tunnel found for {}:{}", host, port);
}
}

@Nullable
private RunningTunnel getRunningTunnel(String host, int port) {
return this.runningTunnels.keySet().stream()
.filter(tunnel -> tunnel.access().tunnelAddress().getHostString().equalsIgnoreCase(host) &&
tunnel.access().tunnelAddress().getPort() == port)
.findFirst()
.orElse(null);
}
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pluginManagement {
}
}

include("api")
include("common")
include("fabric")
include("neoforge")
Expand Down