mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-24 10:27:38 +00:00
Add support for proxying HTTP requests (#1461)
This commit is contained in:
@@ -45,6 +45,9 @@ class AddressRuleConfig {
|
||||
|
||||
config.setComment("max_websocket_message", "The maximum size (in bytes) that a computer can send or receive in one websocket packet.");
|
||||
config.set("max_websocket_message", AddressRule.WEBSOCKET_MESSAGE);
|
||||
|
||||
config.setComment("use_proxy", "Enable use of the HTTP/SOCKS proxy if it is configured.");
|
||||
config.set("use_proxy", false);
|
||||
}
|
||||
|
||||
return config;
|
||||
@@ -58,6 +61,7 @@ class AddressRuleConfig {
|
||||
&& check(builder, "max_upload", Number.class)
|
||||
&& check(builder, "max_download", Number.class)
|
||||
&& check(builder, "websocket_message", Number.class)
|
||||
&& check(builder, "use_proxy", Boolean.class)
|
||||
&& AddressRule.parse(hostObj, port, PartialOptions.DEFAULT) != null;
|
||||
}
|
||||
|
||||
@@ -71,12 +75,14 @@ class AddressRuleConfig {
|
||||
var maxUpload = unboxOptLong(get(builder, "max_upload", Number.class).map(Number::longValue));
|
||||
var maxDownload = unboxOptLong(get(builder, "max_download", Number.class).map(Number::longValue));
|
||||
var websocketMessage = unboxOptInt(get(builder, "websocket_message", Number.class).map(Number::intValue));
|
||||
var useProxy = get(builder, "use_proxy", Boolean.class);
|
||||
|
||||
var options = new PartialOptions(
|
||||
action,
|
||||
maxUpload,
|
||||
maxDownload,
|
||||
websocketMessage
|
||||
websocketMessage,
|
||||
useProxy
|
||||
);
|
||||
|
||||
return AddressRule.parse(hostObj, port, options);
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.google.common.base.Splitter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.OverridingMethodsMustInvokeSuper;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
@@ -141,6 +142,18 @@ public interface ConfigFile {
|
||||
* @param onChange The function to run on change.
|
||||
* @return The built config file.
|
||||
*/
|
||||
public abstract ConfigFile build(Runnable onChange);
|
||||
public abstract ConfigFile build(ConfigListener onChange);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ConfigListener {
|
||||
/**
|
||||
* The function called then a config file is changed.
|
||||
*
|
||||
* @param path The path to the config file. This will be {@code null} when the config file does not exist on
|
||||
* disk, such as when synced from a server to the client.
|
||||
* @see Builder#build(ConfigListener)
|
||||
*/
|
||||
void onConfigChanged(@Nullable Path path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
package dan200.computercraft.shared.config;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.core.CoreConfig;
|
||||
import dan200.computercraft.core.Logging;
|
||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||
import dan200.computercraft.core.apis.http.options.Action;
|
||||
import dan200.computercraft.core.apis.http.options.ProxyType;
|
||||
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
@@ -16,6 +18,8 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.filter.MarkerFilter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -49,6 +53,10 @@ public final class ConfigSpec {
|
||||
public static final ConfigFile.Value<Integer> httpDownloadBandwidth;
|
||||
public static final ConfigFile.Value<Integer> httpUploadBandwidth;
|
||||
|
||||
public static final ConfigFile.Value<ProxyType> httpProxyType;
|
||||
public static final ConfigFile.Value<String> httpProxyHost;
|
||||
public static final ConfigFile.Value<Integer> httpProxyPort;
|
||||
|
||||
public static final ConfigFile.Value<Boolean> commandBlockEnabled;
|
||||
public static final ConfigFile.Value<Integer> modemRange;
|
||||
public static final ConfigFile.Value<Integer> modemHighAltitudeRange;
|
||||
@@ -222,6 +230,30 @@ public final class ConfigSpec {
|
||||
|
||||
builder.pop();
|
||||
|
||||
builder
|
||||
.comment("""
|
||||
Tunnels HTTP and websocket requests through a proxy server. Only affects HTTP
|
||||
rules with "use_proxy" set to true (off by default).
|
||||
If authentication is required for the proxy, create a "computercraft-proxy.pw"
|
||||
file in the same directory as "computercraft-server.toml", containing the
|
||||
username and password separated by a colon, e.g. "myuser:mypassword". For
|
||||
SOCKS4 proxies only the username is required.""")
|
||||
.push("proxy");
|
||||
|
||||
httpProxyType = builder
|
||||
.comment("The type of proxy to use.")
|
||||
.defineEnum("type", CoreConfig.httpProxyType);
|
||||
|
||||
httpProxyHost = builder
|
||||
.comment("The hostname or IP address of the proxy server.")
|
||||
.define("host", CoreConfig.httpProxyHost);
|
||||
|
||||
httpProxyPort = builder
|
||||
.comment("The port of the proxy server.")
|
||||
.defineInRange("port", CoreConfig.httpProxyPort, 1, 65536);
|
||||
|
||||
builder.pop();
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
@@ -339,7 +371,7 @@ public final class ConfigSpec {
|
||||
clientSpec = clientBuilder.build(ConfigSpec::syncClient);
|
||||
}
|
||||
|
||||
public static void syncServer() {
|
||||
public static void syncServer(@Nullable Path path) {
|
||||
// General
|
||||
Config.computerSpaceLimit = computerSpaceLimit.get();
|
||||
Config.floppySpaceLimit = floppySpaceLimit.get();
|
||||
@@ -370,6 +402,13 @@ public final class ConfigSpec {
|
||||
CoreConfig.httpMaxWebsockets = httpMaxWebsockets.get();
|
||||
CoreConfig.httpDownloadBandwidth = httpDownloadBandwidth.get();
|
||||
CoreConfig.httpUploadBandwidth = httpUploadBandwidth.get();
|
||||
|
||||
CoreConfig.httpProxyType = httpProxyType.get();
|
||||
CoreConfig.httpProxyHost = httpProxyHost.get();
|
||||
CoreConfig.httpProxyPort = httpProxyPort.get();
|
||||
|
||||
if (path != null) ProxyPasswordConfig.init(path.resolveSibling(ComputerCraftAPI.MOD_ID + "-proxy.pw"));
|
||||
|
||||
NetworkUtils.reloadConfig();
|
||||
|
||||
// Peripheral
|
||||
@@ -396,7 +435,7 @@ public final class ConfigSpec {
|
||||
Config.monitorHeight = monitorHeight.get();
|
||||
}
|
||||
|
||||
public static void syncClient() {
|
||||
public static void syncClient(@Nullable Path path) {
|
||||
Config.monitorRenderer = monitorRenderer.get();
|
||||
Config.monitorDistance = monitorDistance.get();
|
||||
Config.uploadNagDelay = uploadNagDelay.get();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.config;
|
||||
|
||||
import dan200.computercraft.core.CoreConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
record ProxyPasswordConfig(String username, String password) {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ProxyPasswordConfig.class);
|
||||
|
||||
@Nullable
|
||||
private static ProxyPasswordConfig loadFromFile(@Nullable Path path) {
|
||||
if (path == null || !path.toFile().exists()) return null;
|
||||
|
||||
try (var br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
|
||||
var line = br.readLine();
|
||||
if (line == null) return null;
|
||||
|
||||
var parts = line.trim().split(":", 2);
|
||||
if (parts.length == 0) return null;
|
||||
|
||||
return new ProxyPasswordConfig(parts[0], parts.length == 2 ? parts[1] : "");
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to load proxy password from {}.", path, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static void init(@Nullable Path path) {
|
||||
var config = loadFromFile(path);
|
||||
if (config == null) {
|
||||
CoreConfig.httpProxyUsername = "";
|
||||
CoreConfig.httpProxyPassword = "";
|
||||
} else {
|
||||
CoreConfig.httpProxyUsername = config.username;
|
||||
CoreConfig.httpProxyPassword = config.password;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user