fix(config): sync Swing settings after Web updates
Add revisioned configuration events and detached commits so Web changes refresh clean Swing forms without overwriting unsaved local edits. Preserve configuration formatting and document the synchronized update workflow.
This commit is contained in:
@@ -46,8 +46,9 @@ pnpm dev
|
|||||||
|
|
||||||
- `KLALBConfigItem` is a polymorphic JSON array keyed by `Type`. Adding a type requires a subclass and cases in both default config serializer and deserializer; unknown types must remain preserved.
|
- `KLALBConfigItem` is a polymorphic JSON array keyed by `Type`. Adding a type requires a subclass and cases in both default config serializer and deserializer; unknown types must remain preserved.
|
||||||
- `/api/config` is field-by-field parsing, not whole-object Gson mapping. Keep legacy key aliases in sync with new fields.
|
- `/api/config` is field-by-field parsing, not whole-object Gson mapping. Keep legacy key aliases in sync with new fields.
|
||||||
- Vendored Gson is `2.1`: responses that are `JsonElement` instances must be serialized with `JsonElement.toString()`, not reflective `gson.toJson(Object)`.
|
- Vendored Gson is `2.1`: HTTP responses that are `JsonElement` instances must be serialized with `JsonElement.toString()`, not reflective `gson.toJson(Object)`; configuration files must use the configured pretty-print Gson path rather than `JsonElement.toString()`.
|
||||||
- UI strings use `UIEnv.getRsb()`; add keys to both `src/klalb_zh_CN.properties` and `src/klalb_en_US.properties`.
|
- UI strings use `UIEnv.getRsb()`; add keys to both `src/klalb_zh_CN.properties` and `src/klalb_en_US.properties`.
|
||||||
|
- Web and Swing configuration writes must use `KLALBProxySystem`'s revisioned detached-candidate commit/event path; do not mutate the canonical config object directly.
|
||||||
- `KLALBController.PublishedNodeInfo` is the thread-safe source for Tiny/Full node-info responses. Publish name, description, external endpoints, and Extra Routes through the controller method so snapshots and Tiny/Full update flags stay consistent.
|
- `KLALBController.PublishedNodeInfo` is the thread-safe source for Tiny/Full node-info responses. Publish name, description, external endpoints, and Extra Routes through the controller method so snapshots and Tiny/Full update flags stay consistent.
|
||||||
- `RouterInfo` no longer carries a device name. Its wire format retains an empty legacy UTF slot and `RouterInfoPacket` has optional Tiny/Full invalidation flags. Treat codec changes as compatibility work: preserve old-reader behavior and review a whole-mesh rollout.
|
- `RouterInfo` no longer carries a device name. Its wire format retains an empty legacy UTF slot and `RouterInfoPacket` has optional Tiny/Full invalidation flags. Treat codec changes as compatibility work: preserve old-reader behavior and review a whole-mesh rollout.
|
||||||
- Full node-info carries `extraRoutes` separately from the endpoint `data` list. Keep absent fields compatible with older peers.
|
- Full node-info carries `extraRoutes` separately from the endpoint `data` list. Keep absent fields compatible with older peers.
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ reconnectall=Reconnect All
|
|||||||
remotelines=Remote lines
|
remotelines=Remote lines
|
||||||
settings=Settings
|
settings=Settings
|
||||||
saveconfigsuccess=Save config success
|
saveconfigsuccess=Save config success
|
||||||
|
configexternalupdate=The configuration was updated by another source.
|
||||||
|
configreload=Reload
|
||||||
|
configcontinue=Continue editing
|
||||||
|
configsaveconflict=Save failed: the configuration was updated. Reload and try again.
|
||||||
|
configsavefailed=Failed to save configuration.
|
||||||
|
configconflicttitle=Configuration conflict
|
||||||
warning=Warning
|
warning=Warning
|
||||||
invaildipv6addr=IPv6 address:Invaild Input
|
invaildipv6addr=IPv6 address:Invaild Input
|
||||||
invailddnsserver=DNS server:Invaild Input
|
invailddnsserver=DNS server:Invaild Input
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ reconnectall=全部重连
|
|||||||
remotelines=远程链路
|
remotelines=远程链路
|
||||||
settings=设置
|
settings=设置
|
||||||
saveconfigsuccess=保存配置成功
|
saveconfigsuccess=保存配置成功
|
||||||
|
configexternalupdate=配置已被其他来源更新。
|
||||||
|
configreload=重新加载
|
||||||
|
configcontinue=继续编辑
|
||||||
|
configsaveconflict=保存失败:配置已被更新,请重新加载后再试。
|
||||||
|
configsavefailed=保存配置失败。
|
||||||
|
configconflicttitle=配置冲突
|
||||||
warning=警告
|
warning=警告
|
||||||
invaildipv6addr=IPv6地址:非法输入
|
invaildipv6addr=IPv6地址:非法输入
|
||||||
invailddnsserver=DNS服务器:非法输入
|
invailddnsserver=DNS服务器:非法输入
|
||||||
|
|||||||
@@ -580,7 +580,63 @@ public class KLALBController {
|
|||||||
|
|
||||||
private KLALBRoutingProtocolAPIClient apiClient;
|
private KLALBRoutingProtocolAPIClient apiClient;
|
||||||
|
|
||||||
private KLALBControllerConfigItem configItem;
|
private volatile KLALBControllerConfigItem configItem;
|
||||||
|
|
||||||
|
private static <T> List<T> copyConfigList(List<T> values) {
|
||||||
|
return values == null ? null : new ArrayList<T>(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KLALBControllerConfigItem copyConfigItem(KLALBControllerConfigItem source) {
|
||||||
|
KLALBControllerConfigItem copy = new KLALBControllerConfigItem();
|
||||||
|
copy.setLanguage(source.getLanguage());
|
||||||
|
copy.setNogui(source.isNogui());
|
||||||
|
copy.setVirtualAddress(source.getVirtualAddress());
|
||||||
|
copy.setVirtualASN(source.getVirtualASN());
|
||||||
|
copy.setDNS(copyConfigList(source.getDNS()));
|
||||||
|
copy.setTCPListen(source.getTCPListen());
|
||||||
|
copy.setUDPListen(source.getUDPListen());
|
||||||
|
copy.setVirtualSocketName(source.getVirtualSocketName());
|
||||||
|
copy.setExternalEndpoints(copyConfigList(source.getExternalEndpoints()));
|
||||||
|
copy.setAutoConnections(copyConfigList(source.getAutoConnections()));
|
||||||
|
copy.setNtpServers(copyConfigList(source.getNtpServers()));
|
||||||
|
copy.setExtraRoutes(copyConfigList(source.getExtraRoutes()));
|
||||||
|
copy.setDenyExternalEndpointQuery(source.isDenyExternalEndpointQuery());
|
||||||
|
copy.setDenyExternalEndpointBroadcast(source.isDenyExternalEndpointBroadcast());
|
||||||
|
copy.setCongestionAlgorithm(source.getCongestionAlgorithm());
|
||||||
|
copy.setBurstLimit(source.getBurstLimit());
|
||||||
|
copy.setDelayUpperBound(source.getDelayUpperBound());
|
||||||
|
copy.setDelayLowerBound(source.getDelayLowerBound());
|
||||||
|
copy.setNagleDelayTime(source.getNagleDelayTime());
|
||||||
|
copy.setLinkNagleDelayTime(source.getLinkNagleDelayTime());
|
||||||
|
copy.setLinkConnectionsCount(source.getLinkConnectionsCount());
|
||||||
|
copy.setEnableTUN(source.isEnableTUN());
|
||||||
|
copy.setTUNName(source.getTUNName());
|
||||||
|
copy.setPerformanceStrategy(source.getPerformanceStrategy());
|
||||||
|
copy.setDeviceName(source.getDeviceName());
|
||||||
|
copy.setDeviceDescription(source.getDeviceDescription());
|
||||||
|
copy.setNetworkInterfaceExcepts(copyConfigList(source.getNetworkInterfaceExcepts()));
|
||||||
|
copy.setWebUI(source.isWebUI());
|
||||||
|
copy.setWebListen(source.getWebListen());
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyConfigItem(KLALBControllerConfigItem committedConfigItem) {
|
||||||
|
if (committedConfigItem == null) {
|
||||||
|
throw new IllegalArgumentException("Controller configuration is required");
|
||||||
|
}
|
||||||
|
KLALBControllerConfigItem detachedConfigItem = copyConfigItem(committedConfigItem);
|
||||||
|
synchronized (externalEndpoints) {
|
||||||
|
configItem = detachedConfigItem;
|
||||||
|
if (srv6Router != null) {
|
||||||
|
PerformanceStrategy strategy = PerformanceStrategy.fromDescription(detachedConfigItem.getPerformanceStrategy());
|
||||||
|
if (strategy != null) {
|
||||||
|
srv6Router.setPerformanceStrategy(strategy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publishNodeInfoLocked(detachedConfigItem.getDeviceName(), detachedConfigItem.getDeviceDescription(),
|
||||||
|
detachedConfigItem.getExternalEndpoints(), detachedConfigItem.getExtraRoutes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addRemoteLines(List<MultiProtocolSocketAddress> select) {
|
public void addRemoteLines(List<MultiProtocolSocketAddress> select) {
|
||||||
for (MultiProtocolSocketAddress target : select) {
|
for (MultiProtocolSocketAddress target : select) {
|
||||||
|
|||||||
@@ -8,7 +8,17 @@ import java.io.Reader;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.AtomicMoveNotSupportedException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.kne.cloud.network.*;
|
import org.kne.cloud.network.*;
|
||||||
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
|
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
|
||||||
@@ -20,6 +30,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonDeserializationContext;
|
import com.google.gson.JsonDeserializationContext;
|
||||||
import com.google.gson.JsonDeserializer;
|
import com.google.gson.JsonDeserializer;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
@@ -30,12 +41,81 @@ import com.google.gson.JsonSerializer;
|
|||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
public class KLALBProxySystem {
|
public class KLALBProxySystem {
|
||||||
|
public enum ConfigChangeSource {
|
||||||
|
WEB, SWING
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ControllerConfigSnapshot {
|
||||||
|
private final long revision;
|
||||||
|
private final String controllerJson;
|
||||||
|
|
||||||
|
private ControllerConfigSnapshot(long revision, String controllerJson) {
|
||||||
|
this.revision = revision;
|
||||||
|
this.controllerJson = controllerJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getControllerJson() {
|
||||||
|
return controllerJson;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ConfigChangeEvent {
|
||||||
|
private final ControllerConfigSnapshot snapshot;
|
||||||
|
private final ConfigChangeSource source;
|
||||||
|
|
||||||
|
private ConfigChangeEvent(ControllerConfigSnapshot snapshot, ConfigChangeSource source) {
|
||||||
|
this.snapshot = snapshot;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControllerConfigSnapshot getSnapshot() {
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigChangeSource getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CommitResult {
|
||||||
|
private final boolean success;
|
||||||
|
private final long revision;
|
||||||
|
private final ControllerConfigSnapshot snapshot;
|
||||||
|
|
||||||
|
private CommitResult(boolean success, long revision, ControllerConfigSnapshot snapshot) {
|
||||||
|
this.success = success;
|
||||||
|
this.revision = revision;
|
||||||
|
this.snapshot = snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControllerConfigSnapshot getSnapshot() {
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Set<Proxy> proxys=new HashSet<>();
|
private Set<Proxy> proxys=new HashSet<>();
|
||||||
private KLALBController klalbController;
|
private KLALBController klalbController;
|
||||||
private KLALBWebServer webServer;
|
private KLALBWebServer webServer;
|
||||||
private KLALBConfig config;
|
private KLALBConfig config;
|
||||||
private Gson gson;
|
private Gson gson;
|
||||||
private File jsonFile;
|
private File jsonFile;
|
||||||
|
private final Object configLock = new Object();
|
||||||
|
private long configRevision;
|
||||||
|
private volatile ControllerConfigSnapshot controllerConfigSnapshot = new ControllerConfigSnapshot(0L, null);
|
||||||
|
private final CopyOnWriteArraySet<Consumer<ConfigChangeEvent>> configChangeListeners = new CopyOnWriteArraySet<>();
|
||||||
|
private JsonArray rawConfigJson;
|
||||||
{
|
{
|
||||||
GsonBuilder gb=new GsonBuilder().setPrettyPrinting();
|
GsonBuilder gb=new GsonBuilder().setPrettyPrinting();
|
||||||
MultiProtocolSocketAddress.registerToGsonBuilder(gb);
|
MultiProtocolSocketAddress.registerToGsonBuilder(gb);
|
||||||
@@ -142,11 +222,25 @@ public class KLALBProxySystem {
|
|||||||
loadConfigJson(new JsonParser().parse(json));
|
loadConfigJson(new JsonParser().parse(json));
|
||||||
}
|
}
|
||||||
public void loadConfigJson(JsonElement json) {
|
public void loadConfigJson(JsonElement json) {
|
||||||
|
JsonElement rawJson = new JsonParser().parse(json.toString());
|
||||||
KLALBConfig config= gson.fromJson(json, KLALBConfig.class);
|
KLALBConfig config= gson.fromJson(json, KLALBConfig.class);
|
||||||
loadConfig(config);
|
JsonArray rawArray = rawJson instanceof JsonArray ? (JsonArray) rawJson : null;
|
||||||
|
synchronized (configLock) {
|
||||||
|
installConfigLocked(config, rawArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void loadConfig(KLALBConfig config) {
|
public void loadConfig(KLALBConfig config) {
|
||||||
|
JsonElement rawJson = gson.toJsonTree(config);
|
||||||
|
JsonArray rawArray = rawJson instanceof JsonArray ? (JsonArray) rawJson : null;
|
||||||
|
synchronized (configLock) {
|
||||||
|
installConfigLocked(config, rawArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installConfigLocked(KLALBConfig config, JsonArray rawArray) {
|
||||||
this.config=config;
|
this.config=config;
|
||||||
|
this.configRevision=0L;
|
||||||
|
rawConfigJson=rawArray;
|
||||||
for(KLALBConfigItem item:config) {
|
for(KLALBConfigItem item:config) {
|
||||||
if(item instanceof KLALBControllerConfigItem) {
|
if(item instanceof KLALBControllerConfigItem) {
|
||||||
KLALBControllerConfigItem kcci=(KLALBControllerConfigItem) item;
|
KLALBControllerConfigItem kcci=(KLALBControllerConfigItem) item;
|
||||||
@@ -229,28 +323,171 @@ public class KLALBProxySystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
controllerConfigSnapshot = createControllerConfigSnapshotLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void saveConfigToFile() {
|
public void saveConfigToFile() {
|
||||||
if (jsonFile != null && config != null) {
|
synchronized (configLock) {
|
||||||
String json = gson.toJson(config);
|
if (jsonFile != null && config != null) {
|
||||||
try (FileWriter fw = new FileWriter(jsonFile)) {
|
try {
|
||||||
fw.write(json);
|
KLALBControllerConfigItem item = findControllerConfigItemLocked();
|
||||||
} catch (IOException e) {
|
if (item == null) {
|
||||||
|
persistConfigJsonLocked(gson.toJson(config));
|
||||||
|
} else {
|
||||||
|
String controllerJson = gson.toJson(item);
|
||||||
|
JsonArray completeConfig = createCompleteConfigJsonLocked(controllerJson);
|
||||||
|
persistConfigJsonLocked(gson.toJson(completeConfig));
|
||||||
|
rawConfigJson = completeConfig;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KLALBControllerConfigItem findControllerConfigItemLocked() {
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (KLALBConfigItem item : config) {
|
||||||
|
if (item instanceof KLALBControllerConfigItem) {
|
||||||
|
return (KLALBControllerConfigItem) item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findControllerConfigIndexLocked() {
|
||||||
|
if (config == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < config.size(); i++) {
|
||||||
|
if (config.get(i) instanceof KLALBControllerConfigItem) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ControllerConfigSnapshot createControllerConfigSnapshotLocked() {
|
||||||
|
KLALBControllerConfigItem item = findControllerConfigItemLocked();
|
||||||
|
return new ControllerConfigSnapshot(configRevision, item == null ? null : gson.toJson(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControllerConfigSnapshot getControllerConfigSnapshot() {
|
||||||
|
synchronized (configLock) {
|
||||||
|
controllerConfigSnapshot = createControllerConfigSnapshotLocked();
|
||||||
|
return controllerConfigSnapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public KLALBControllerConfigItem parseControllerConfigCandidate(ControllerConfigSnapshot snapshot) {
|
||||||
|
if (snapshot == null || snapshot.getControllerJson() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return gson.fromJson(snapshot.getControllerJson(), KLALBControllerConfigItem.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistConfigJsonLocked(String json) throws IOException {
|
||||||
|
if (jsonFile == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Path target = jsonFile.toPath().toAbsolutePath();
|
||||||
|
Path parent = target.getParent();
|
||||||
|
Path temporary = Files.createTempFile(parent, target.getFileName().toString(), ".tmp");
|
||||||
|
try {
|
||||||
|
Files.write(temporary, json.getBytes(StandardCharsets.UTF_8), StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
StandardOpenOption.WRITE);
|
||||||
|
try {
|
||||||
|
Files.move(temporary, target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (AtomicMoveNotSupportedException e) {
|
||||||
|
Files.move(temporary, target, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(temporary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonArray createCompleteConfigJsonLocked(String controllerJson) throws IOException {
|
||||||
|
JsonElement source = rawConfigJson == null ? gson.toJsonTree(config) : rawConfigJson;
|
||||||
|
if (!(source instanceof JsonArray)) {
|
||||||
|
throw new IOException("Configuration is not an array");
|
||||||
|
}
|
||||||
|
JsonArray sourceArray = (JsonArray) source;
|
||||||
|
int index = findControllerConfigIndexLocked();
|
||||||
|
if (index < 0 || index >= sourceArray.size() || sourceArray.size() != config.size()) {
|
||||||
|
throw new IOException("Configuration item layout changed");
|
||||||
|
}
|
||||||
|
JsonArray mergedConfig = new JsonArray();
|
||||||
|
JsonElement controllerElement = new JsonParser().parse(controllerJson);
|
||||||
|
for (int i = 0; i < sourceArray.size(); i++) {
|
||||||
|
mergedConfig.add(i == index ? controllerElement : sourceArray.get(i));
|
||||||
|
}
|
||||||
|
return mergedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConfigChangeListener(Consumer<ConfigChangeEvent> listener) {
|
||||||
|
configChangeListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeConfigChangeListener(Consumer<ConfigChangeEvent> listener) {
|
||||||
|
configChangeListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommitResult commitControllerConfig(long expectedRevision, KLALBControllerConfigItem candidate,
|
||||||
|
ConfigChangeSource source) throws IOException {
|
||||||
|
if (candidate == null || source == null) {
|
||||||
|
throw new IllegalArgumentException("Candidate and source are required");
|
||||||
|
}
|
||||||
|
ConfigChangeEvent event;
|
||||||
|
CommitResult result;
|
||||||
|
synchronized (configLock) {
|
||||||
|
if (expectedRevision != configRevision) {
|
||||||
|
ControllerConfigSnapshot currentSnapshot = createControllerConfigSnapshotLocked();
|
||||||
|
controllerConfigSnapshot = currentSnapshot;
|
||||||
|
return new CommitResult(false, configRevision, currentSnapshot);
|
||||||
|
}
|
||||||
|
int index = findControllerConfigIndexLocked();
|
||||||
|
if (index < 0) {
|
||||||
|
throw new IOException("Controller configuration is missing");
|
||||||
|
}
|
||||||
|
String candidateJson = gson.toJson(candidate);
|
||||||
|
KLALBControllerConfigItem committedCandidate = gson.fromJson(candidateJson,
|
||||||
|
KLALBControllerConfigItem.class);
|
||||||
|
if (PerformanceStrategy.fromDescription(committedCandidate.getPerformanceStrategy()) == null) {
|
||||||
|
throw new IllegalArgumentException("Unknown performanceStrategy: "
|
||||||
|
+ committedCandidate.getPerformanceStrategy());
|
||||||
|
}
|
||||||
|
com.google.gson.JsonArray mergedConfig = createCompleteConfigJsonLocked(candidateJson);
|
||||||
|
persistConfigJsonLocked(gson.toJson(mergedConfig));
|
||||||
|
rawConfigJson = mergedConfig;
|
||||||
|
|
||||||
|
config.set(index, committedCandidate);
|
||||||
|
if (klalbController != null) {
|
||||||
|
klalbController.applyConfigItem(committedCandidate);
|
||||||
|
}
|
||||||
|
configRevision++;
|
||||||
|
controllerConfigSnapshot = createControllerConfigSnapshotLocked();
|
||||||
|
event = new ConfigChangeEvent(controllerConfigSnapshot, source);
|
||||||
|
result = new CommitResult(true, configRevision, controllerConfigSnapshot);
|
||||||
|
}
|
||||||
|
for (Consumer<ConfigChangeEvent> listener : configChangeListeners) {
|
||||||
|
try {
|
||||||
|
listener.accept(event);
|
||||||
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private KLALBStateGUI3 kgui;
|
private KLALBStateGUI3 kgui;
|
||||||
public KLALBStateGUI3 getKLALBGUI() {
|
public KLALBStateGUI3 getKLALBGUI() {
|
||||||
if(kgui==null) {
|
if(kgui==null) {
|
||||||
kgui=new KLALBStateGUI3(klalbController);
|
kgui=new KLALBStateGUI3(klalbController);
|
||||||
kgui.loadConfig(config);
|
kgui.bindConfigSystem(this);
|
||||||
kgui.setSaveComsumer((cfg)->{
|
|
||||||
saveConfigToFile();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return kgui;
|
return kgui;
|
||||||
}
|
}
|
||||||
@@ -258,10 +495,6 @@ public class KLALBProxySystem {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
public KLALBControllerConfigItem getControllerConfig() {
|
public KLALBControllerConfigItem getControllerConfig() {
|
||||||
for(KLALBConfigItem item:config) {
|
return parseControllerConfigCandidate(getControllerConfigSnapshot());
|
||||||
if(item instanceof KLALBControllerConfigItem)
|
|
||||||
return (KLALBControllerConfigItem) item;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,80 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
// ==================== 配置和回调 ====================
|
// ==================== 配置和回调 ====================
|
||||||
private KLALBConfig config; // 配置文件
|
private KLALBConfig config; // 配置文件
|
||||||
private Consumer<KLALBConfig> saveComsumer; // 保存配置的回调函数
|
private Consumer<KLALBConfig> saveComsumer; // 保存配置的回调函数
|
||||||
|
private KLALBProxySystem configSystem;
|
||||||
|
private KLALBProxySystem.ControllerConfigSnapshot loadedSnapshot;
|
||||||
|
private long loadedRevision;
|
||||||
|
private SettingsFormState loadedFormState;
|
||||||
|
private KLALBProxySystem.ControllerConfigSnapshot pendingExternalSnapshot;
|
||||||
|
private long pendingExternalRevision;
|
||||||
|
private boolean configSystemClosed;
|
||||||
|
private long bindingGeneration;
|
||||||
|
private Consumer<KLALBProxySystem.ConfigChangeEvent> boundConfigChangeListener;
|
||||||
|
|
||||||
|
private static final class SettingsFormState {
|
||||||
|
private final String language, deviceName, deviceDescription, address, dns, extraRoutes;
|
||||||
|
private final String asn, tunName, webListen, tcpListen, udpListen, openLines, connectLines, ntp;
|
||||||
|
private final String performance, congestion;
|
||||||
|
private final boolean enableTun, webApi, nogui, denyQuery, denyBroadcast;
|
||||||
|
private final List<String> interfaces;
|
||||||
|
private final int connections, burst, upper, lower, nagle, linkNagle;
|
||||||
|
|
||||||
|
private SettingsFormState(KLALBStateGUI3 gui) {
|
||||||
|
Language languageItem = (Language) gui.comboLang.getSelectedItem();
|
||||||
|
language = languageItem == null ? null : languageItem.name();
|
||||||
|
deviceName = gui.deviceNameSet.getText();
|
||||||
|
deviceDescription = gui.deviceDescriptionSet.getText();
|
||||||
|
address = gui.addressFieldSet.getText();
|
||||||
|
dns = gui.dnsAreaSet.getText();
|
||||||
|
extraRoutes = gui.extraRoutesSet.getText();
|
||||||
|
asn = gui.asnFieldSet.getText();
|
||||||
|
tunName = gui.tunDeviceName.getText();
|
||||||
|
webListen = gui.webListenSet.getText();
|
||||||
|
tcpListen = gui.tcpListeningSet.getText();
|
||||||
|
udpListen = gui.udpListeningSet.getText();
|
||||||
|
openLines = gui.openLineTabelSet.getText();
|
||||||
|
connectLines = gui.connectLineTabelSet.getText();
|
||||||
|
ntp = gui.ntpServerSet.getText();
|
||||||
|
PerformanceStrategyItem performanceItem = (PerformanceStrategyItem) gui.comboPerformance.getSelectedItem();
|
||||||
|
performance = performanceItem == null ? null : performanceItem.getStrategy().toString();
|
||||||
|
congestion = String.valueOf(gui.congestions.getComboBox().getSelectedItem());
|
||||||
|
enableTun = gui.enableTUN.isSelected();
|
||||||
|
webApi = gui.webApiEnabled.isSelected();
|
||||||
|
nogui = gui.nogui.isSelected();
|
||||||
|
denyQuery = gui.denyQuery.isSelected();
|
||||||
|
denyBroadcast = gui.denyBroadcast.isSelected();
|
||||||
|
interfaces = new ArrayList<>();
|
||||||
|
for (int i = 0; i < gui.nilsimdl.getSize(); i++) interfaces.add(gui.nilsimdl.getElementAt(i).getName());
|
||||||
|
connections = gui.linkConnectionsCount.getSlider().getValue();
|
||||||
|
burst = gui.burstLimit.getSlider().getValue();
|
||||||
|
upper = gui.delayHbound.getSlider().getValue();
|
||||||
|
lower = gui.delayLbound.getSlider().getValue();
|
||||||
|
nagle = gui.nagleDelayTime.getSlider().getValue();
|
||||||
|
linkNagle = gui.linkNagleDelayTime.getSlider().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof SettingsFormState)) return false;
|
||||||
|
SettingsFormState o = (SettingsFormState) obj;
|
||||||
|
return enableTun == o.enableTun && webApi == o.webApi && nogui == o.nogui
|
||||||
|
&& denyQuery == o.denyQuery && denyBroadcast == o.denyBroadcast
|
||||||
|
&& connections == o.connections && burst == o.burst && upper == o.upper
|
||||||
|
&& lower == o.lower && nagle == o.nagle && linkNagle == o.linkNagle
|
||||||
|
&& Objects.equals(language, o.language) && Objects.equals(deviceName, o.deviceName)
|
||||||
|
&& Objects.equals(deviceDescription, o.deviceDescription) && Objects.equals(address, o.address)
|
||||||
|
&& Objects.equals(dns, o.dns) && Objects.equals(extraRoutes, o.extraRoutes)
|
||||||
|
&& Objects.equals(asn, o.asn) && Objects.equals(tunName, o.tunName)
|
||||||
|
&& Objects.equals(webListen, o.webListen) && Objects.equals(tcpListen, o.tcpListen)
|
||||||
|
&& Objects.equals(udpListen, o.udpListen) && Objects.equals(openLines, o.openLines)
|
||||||
|
&& Objects.equals(connectLines, o.connectLines) && Objects.equals(ntp, o.ntp)
|
||||||
|
&& Objects.equals(performance, o.performance) && Objects.equals(congestion, o.congestion)
|
||||||
|
&& Objects.equals(interfaces, o.interfaces);
|
||||||
|
}
|
||||||
|
@Override public int hashCode() { return Objects.hash(language, deviceName, deviceDescription, address, dns,
|
||||||
|
extraRoutes, asn, tunName, webListen, tcpListen, udpListen, openLines, connectLines, ntp,
|
||||||
|
performance, congestion, enableTun, webApi, nogui, denyQuery, denyBroadcast, interfaces,
|
||||||
|
connections, burst, upper, lower, nagle, linkNagle); }
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 尺寸常量 ====================
|
// ==================== 尺寸常量 ====================
|
||||||
private Dimension dashSize = new Dimension((int) (145 * 0.7), (int) (165 * 0.7)); // 仪表盘尺寸
|
private Dimension dashSize = new Dimension((int) (145 * 0.7), (int) (165 * 0.7)); // 仪表盘尺寸
|
||||||
@@ -1056,14 +1130,9 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
* 保存配置到文件
|
* 保存配置到文件
|
||||||
*/
|
*/
|
||||||
private void saveConfig() {
|
private void saveConfig() {
|
||||||
if (config == null) {
|
if (configSystem == null || loadedSnapshot == null) return;
|
||||||
config = new KLALBConfig();
|
KLALBControllerConfigItem kck = configSystem.parseControllerConfigCandidate(loadedSnapshot);
|
||||||
config.add(new KLALBControllerConfigItem());
|
if (kck == null) return;
|
||||||
}
|
|
||||||
|
|
||||||
for (KLALBConfigItem item : config) {
|
|
||||||
if (item instanceof KLALBControllerConfigItem) {
|
|
||||||
KLALBControllerConfigItem kck = (KLALBControllerConfigItem) item;
|
|
||||||
String oldDeviceName = kck.getDeviceName();
|
String oldDeviceName = kck.getDeviceName();
|
||||||
String oldDeviceDescription = kck.getDeviceDescription();
|
String oldDeviceDescription = kck.getDeviceDescription();
|
||||||
List<MultiProtocolSocketAddress> oldExternalEndpoints = kck.getExternalEndpoints() == null
|
List<MultiProtocolSocketAddress> oldExternalEndpoints = kck.getExternalEndpoints() == null
|
||||||
@@ -1314,28 +1383,30 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
|
|
||||||
kck.setLinkNagleDelayTime(linkNagleDelayTime.getSlider().getValue()*100000L);
|
kck.setLinkNagleDelayTime(linkNagleDelayTime.getSlider().getValue()*100000L);
|
||||||
|
|
||||||
boolean deviceNameChanged = !Objects.equals(oldDeviceName, newDeviceName);
|
kck.setDeviceName(newDeviceName);
|
||||||
boolean deviceDescriptionChanged = !Objects.equals(oldDeviceDescription, newDeviceDescription);
|
kck.setDeviceDescription(newDeviceDescription);
|
||||||
boolean externalEndpointsChanged = !Objects.equals(oldExternalEndpoints, newExternalEndpoints);
|
kck.setExternalEndpoints(newExternalEndpoints);
|
||||||
boolean extraRoutesChanged = !Objects.equals(oldExtraRoutes, newExtraRoutes);
|
kck.setExtraRoutes(newExtraRoutes);
|
||||||
if (deviceNameChanged || deviceDescriptionChanged || externalEndpointsChanged || extraRoutesChanged) {
|
try {
|
||||||
if (kcontroller != null) {
|
KLALBProxySystem.CommitResult result = configSystem.commitControllerConfig(loadedRevision, kck,
|
||||||
kcontroller.publishNodeInfo(newDeviceName, newDeviceDescription, newExternalEndpoints,
|
KLALBProxySystem.ConfigChangeSource.SWING);
|
||||||
newExtraRoutes);
|
if (!result.isSuccess()) {
|
||||||
} else {
|
resolveConfigConflict(result.getSnapshot(), "configsaveconflict");
|
||||||
kck.setDeviceName(newDeviceName);
|
return;
|
||||||
kck.setDeviceDescription(newDeviceDescription);
|
|
||||||
kck.setExternalEndpoints(newExternalEndpoints);
|
|
||||||
kck.setExtraRoutes(newExtraRoutes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
loadedSnapshot = result.getSnapshot();
|
||||||
|
loadedRevision = result.getRevision();
|
||||||
// 调用保存回调
|
loadedFormState = new SettingsFormState(this);
|
||||||
if (saveComsumer != null) {
|
pendingExternalSnapshot = null;
|
||||||
saveComsumer.accept(config);
|
|
||||||
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("saveconfigsuccess"));
|
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("saveconfigsuccess"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("configsavefailed"),
|
||||||
|
UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("configsavefailed"),
|
||||||
|
UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1565,11 +1636,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
/**
|
/**
|
||||||
* 加载配置文件
|
* 加载配置文件
|
||||||
*/
|
*/
|
||||||
public void loadConfig(KLALBConfig config) {
|
private void loadConfigCandidate(KLALBControllerConfigItem kck) {
|
||||||
this.config = config;
|
|
||||||
for (KLALBConfigItem item : config) {
|
|
||||||
if (item instanceof KLALBControllerConfigItem) {
|
|
||||||
KLALBControllerConfigItem kck = (KLALBControllerConfigItem) item;
|
|
||||||
|
|
||||||
// 加载语言设置
|
// 加载语言设置
|
||||||
String lg = kck.getLanguage();
|
String lg = kck.getLanguage();
|
||||||
@@ -1695,10 +1762,93 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
|
|
||||||
long delr=kck.getLinkNagleDelayTime();
|
long delr=kck.getLinkNagleDelayTime();
|
||||||
linkNagleDelayTime.getSlider().setValue((int)(delr/100000L));
|
linkNagleDelayTime.getSlider().setValue((int)(delr/100000L));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadConfig(KLALBConfig config) {
|
||||||
|
if (configSystem != null) return;
|
||||||
|
this.config = config;
|
||||||
|
if (config == null) return;
|
||||||
|
for (KLALBConfigItem item : config) {
|
||||||
|
if (item instanceof KLALBControllerConfigItem) {
|
||||||
|
loadConfigCandidate((KLALBControllerConfigItem) item);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void bindConfigSystem(KLALBProxySystem system) {
|
||||||
|
if (configSystemClosed || system == null) return;
|
||||||
|
final long generation = ++bindingGeneration;
|
||||||
|
Runnable bind = () -> {
|
||||||
|
if (configSystemClosed || generation != bindingGeneration) return;
|
||||||
|
if (configSystem != null && boundConfigChangeListener != null)
|
||||||
|
configSystem.removeConfigChangeListener(boundConfigChangeListener);
|
||||||
|
configSystem = system;
|
||||||
|
final Consumer<KLALBProxySystem.ConfigChangeEvent> listener = event ->
|
||||||
|
SwingUtilities.invokeLater(() -> handleConfigChange(system, generation, event));
|
||||||
|
boundConfigChangeListener = listener;
|
||||||
|
pendingExternalSnapshot = null;
|
||||||
|
pendingExternalRevision = 0L;
|
||||||
|
loadedSnapshot = null;
|
||||||
|
loadedRevision = 0L;
|
||||||
|
loadedFormState = null;
|
||||||
|
system.addConfigChangeListener(listener);
|
||||||
|
loadedSnapshot = system.getControllerConfigSnapshot();
|
||||||
|
KLALBControllerConfigItem candidate = system.parseControllerConfigCandidate(loadedSnapshot);
|
||||||
|
if (candidate != null) {
|
||||||
|
loadConfigCandidate(candidate);
|
||||||
|
loadedRevision = loadedSnapshot.getRevision();
|
||||||
|
loadedFormState = new SettingsFormState(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (SwingUtilities.isEventDispatchThread()) bind.run();
|
||||||
|
else SwingUtilities.invokeLater(bind);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleConfigChange(KLALBProxySystem sourceSystem, long generation,
|
||||||
|
KLALBProxySystem.ConfigChangeEvent event) {
|
||||||
|
if (configSystemClosed || generation != bindingGeneration || sourceSystem != configSystem
|
||||||
|
|| event.getSource() == KLALBProxySystem.ConfigChangeSource.SWING) return;
|
||||||
|
KLALBProxySystem.ControllerConfigSnapshot snapshot = event.getSnapshot();
|
||||||
|
if (snapshot == null || snapshot.getRevision() <= Math.max(loadedRevision, pendingExternalRevision)) return;
|
||||||
|
if (loadedFormState != null && loadedFormState.equals(new SettingsFormState(this))) {
|
||||||
|
applyExternalSnapshot(snapshot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pendingExternalSnapshot == null || snapshot.getRevision() > pendingExternalRevision) {
|
||||||
|
boolean hadPending = pendingExternalSnapshot != null;
|
||||||
|
pendingExternalSnapshot = snapshot;
|
||||||
|
pendingExternalRevision = snapshot.getRevision();
|
||||||
|
if (!hadPending) resolveConfigConflict(snapshot, "configexternalupdate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolveConfigConflict(KLALBProxySystem.ControllerConfigSnapshot snapshot, String messageKey) {
|
||||||
|
if (snapshot != null && snapshot.getRevision() > Math.max(loadedRevision, pendingExternalRevision)) {
|
||||||
|
pendingExternalSnapshot = snapshot;
|
||||||
|
pendingExternalRevision = snapshot.getRevision();
|
||||||
|
}
|
||||||
|
Object[] options = { UIEnv.getRsb().getString("configreload"), UIEnv.getRsb().getString("configcontinue") };
|
||||||
|
int choice = JOptionPane.showOptionDialog(this, UIEnv.getRsb().getString(messageKey),
|
||||||
|
UIEnv.getRsb().getString("configconflicttitle"), JOptionPane.DEFAULT_OPTION,
|
||||||
|
JOptionPane.WARNING_MESSAGE, null, options, options[0]);
|
||||||
|
if (choice == 0 && pendingExternalSnapshot != null
|
||||||
|
&& pendingExternalSnapshot.getRevision() >= loadedRevision) {
|
||||||
|
applyExternalSnapshot(pendingExternalSnapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyExternalSnapshot(KLALBProxySystem.ControllerConfigSnapshot snapshot) {
|
||||||
|
KLALBControllerConfigItem candidate = configSystem.parseControllerConfigCandidate(snapshot);
|
||||||
|
if (candidate == null) return;
|
||||||
|
loadConfigCandidate(candidate);
|
||||||
|
loadedSnapshot = snapshot;
|
||||||
|
loadedRevision = snapshot.getRevision();
|
||||||
|
loadedFormState = new SettingsFormState(this);
|
||||||
|
pendingExternalSnapshot = null;
|
||||||
|
pendingExternalRevision = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 辅助方法 ====================
|
// ==================== 辅助方法 ====================
|
||||||
/**
|
/**
|
||||||
* 创建图标
|
* 创建图标
|
||||||
@@ -1773,6 +1923,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
* 设置保存配置的回调函数
|
* 设置保存配置的回调函数
|
||||||
*/
|
*/
|
||||||
public void setSaveComsumer(Consumer<KLALBConfig> saveComsumer) {
|
public void setSaveComsumer(Consumer<KLALBConfig> saveComsumer) {
|
||||||
|
if (configSystem != null) return;
|
||||||
this.saveComsumer = saveComsumer;
|
this.saveComsumer = saveComsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1788,6 +1939,11 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
* 关闭窗口并清理资源
|
* 关闭窗口并清理资源
|
||||||
*/
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
|
bindingGeneration++;
|
||||||
|
configSystemClosed = true;
|
||||||
|
if (configSystem != null && boundConfigChangeListener != null)
|
||||||
|
configSystem.removeConfigChangeListener(boundConfigChangeListener);
|
||||||
|
boundConfigChangeListener = null;
|
||||||
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
|
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
|
||||||
Component component = tabbedPane.getComponentAt(i);
|
Component component = tabbedPane.getComponentAt(i);
|
||||||
if (component instanceof NodeInformationPanel) {
|
if (component instanceof NodeInformationPanel) {
|
||||||
|
|||||||
@@ -869,17 +869,11 @@ public class KLALBWebServer {
|
|||||||
String body = readRequestBody(exchange);
|
String body = readRequestBody(exchange);
|
||||||
try {
|
try {
|
||||||
JsonObject json = new JsonParser().parse(body).getAsJsonObject();
|
JsonObject json = new JsonParser().parse(body).getAsJsonObject();
|
||||||
KLALBControllerConfigItem current = proxySystem.getControllerConfig();
|
KLALBProxySystem.ControllerConfigSnapshot baseSnapshot = proxySystem.getControllerConfigSnapshot();
|
||||||
|
KLALBControllerConfigItem current = proxySystem.parseControllerConfigCandidate(baseSnapshot);
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
String oldDeviceName = current.getDeviceName();
|
String newDeviceName = current.getDeviceName();
|
||||||
String oldDeviceDescription = current.getDeviceDescription();
|
String newDeviceDescription = current.getDeviceDescription();
|
||||||
List<MultiProtocolSocketAddress> oldExternalEndpoints = current.getExternalEndpoints() == null
|
|
||||||
? null
|
|
||||||
: new ArrayList<MultiProtocolSocketAddress>(current.getExternalEndpoints());
|
|
||||||
List<String> oldExtraRoutes = current.getExtraRoutes() == null
|
|
||||||
? null : new ArrayList<String>(current.getExtraRoutes());
|
|
||||||
String newDeviceName = oldDeviceName;
|
|
||||||
String newDeviceDescription = oldDeviceDescription;
|
|
||||||
List<MultiProtocolSocketAddress> newExternalEndpoints = current.getExternalEndpoints();
|
List<MultiProtocolSocketAddress> newExternalEndpoints = current.getExternalEndpoints();
|
||||||
List<String> newExtraRoutes = current.getExtraRoutes();
|
List<String> newExtraRoutes = current.getExtraRoutes();
|
||||||
if (json.has("deviceName") && !json.get("deviceName").isJsonNull()) {
|
if (json.has("deviceName") && !json.get("deviceName").isJsonNull()) {
|
||||||
@@ -1078,37 +1072,32 @@ public class KLALBWebServer {
|
|||||||
current.setDenyExternalEndpointBroadcast(json.get("denyLineTableBroadcast").getAsBoolean());
|
current.setDenyExternalEndpointBroadcast(json.get("denyLineTableBroadcast").getAsBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean deviceNameChanged = !Objects.equals(oldDeviceName, newDeviceName);
|
current.setDeviceName(newDeviceName);
|
||||||
boolean deviceDescriptionChanged = !Objects.equals(oldDeviceDescription, newDeviceDescription);
|
current.setDeviceDescription(newDeviceDescription);
|
||||||
boolean externalEndpointsChanged = !Objects.equals(oldExternalEndpoints, newExternalEndpoints);
|
current.setExternalEndpoints(newExternalEndpoints);
|
||||||
boolean extraRoutesChanged = !Objects.equals(oldExtraRoutes, newExtraRoutes);
|
current.setExtraRoutes(newExtraRoutes);
|
||||||
if (deviceNameChanged || deviceDescriptionChanged || externalEndpointsChanged || extraRoutesChanged) {
|
KLALBProxySystem.CommitResult commitResult = proxySystem.commitControllerConfig(
|
||||||
KLALBController kc = proxySystem.getKlalbController();
|
baseSnapshot.getRevision(), current,
|
||||||
if (kc != null) {
|
KLALBProxySystem.ConfigChangeSource.WEB);
|
||||||
kc.publishNodeInfo(newDeviceName, newDeviceDescription, newExternalEndpoints,
|
if (!commitResult.isSuccess()) {
|
||||||
newExtraRoutes);
|
JsonObject conflict = new JsonObject();
|
||||||
} else {
|
conflict.addProperty("success", false);
|
||||||
current.setDeviceName(newDeviceName);
|
conflict.addProperty("revision", commitResult.getRevision());
|
||||||
current.setDeviceDescription(newDeviceDescription);
|
conflict.addProperty("error", "Configuration revision conflict");
|
||||||
current.setExternalEndpoints(newExternalEndpoints);
|
sendJsonResponse(exchange, 409, conflict);
|
||||||
current.setExtraRoutes(newExtraRoutes);
|
return;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger GUI save consumer or save directly
|
|
||||||
if (proxySystem.getKLALBGUI() != null && proxySystem.getKLALBGUI().getSaveComsumer() != null) {
|
|
||||||
proxySystem.getKLALBGUI().getSaveComsumer().accept(proxySystem.getConfig());
|
|
||||||
} else {
|
|
||||||
proxySystem.saveConfigToFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject resp = new JsonObject();
|
JsonObject resp = new JsonObject();
|
||||||
resp.addProperty("success", true);
|
resp.addProperty("success", true);
|
||||||
|
resp.addProperty("revision", commitResult.getRevision());
|
||||||
resp.addProperty("message", "Configuration updated successfully");
|
resp.addProperty("message", "Configuration updated successfully");
|
||||||
sendJsonResponse(exchange, 200, resp);
|
sendJsonResponse(exchange, 200, resp);
|
||||||
} else {
|
} else {
|
||||||
sendError(exchange, 500, "Current configuration is null");
|
sendError(exchange, 500, "Current configuration is null");
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
sendError(exchange, 500, "Failed to persist configuration: " + e.getMessage());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
sendError(exchange, 400, "Failed to update configuration: " + e.getMessage());
|
sendError(exchange, 400, "Failed to update configuration: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user