This commit is contained in:
crschnick 2024-06-23 22:40:50 +00:00
parent d1b506415c
commit eeeef57b8f
74 changed files with 314 additions and 187 deletions

View file

@ -1,6 +1,7 @@
package io.xpipe.app.beacon; package io.xpipe.app.beacon;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import lombok.Value; import lombok.Value;
import java.util.HashSet; import java.util.HashSet;
@ -13,7 +14,10 @@ public class AppBeaconCache {
Set<BeaconShellSession> shellSessions = new HashSet<>(); Set<BeaconShellSession> shellSessions = new HashSet<>();
public BeaconShellSession getShellSession(UUID uuid) throws BeaconClientException { public BeaconShellSession getShellSession(UUID uuid) throws BeaconClientException {
var found = shellSessions.stream().filter(beaconShellSession -> beaconShellSession.getEntry().getUuid().equals(uuid)).findFirst(); var found = shellSessions.stream()
.filter(beaconShellSession ->
beaconShellSession.getEntry().getUuid().equals(uuid))
.findFirst();
if (found.isEmpty()) { if (found.isEmpty()) {
throw new BeaconClientException("No active shell session known for id " + uuid); throw new BeaconClientException("No active shell session known for id " + uuid);
} }

View file

@ -1,7 +1,5 @@
package io.xpipe.app.beacon; package io.xpipe.app.beacon;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import io.xpipe.app.core.AppResources; import io.xpipe.app.core.AppResources;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
@ -9,6 +7,9 @@ import io.xpipe.app.util.MarkdownHelper;
import io.xpipe.beacon.BeaconConfig; import io.xpipe.beacon.BeaconConfig;
import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.util.XPipeInstallation; import io.xpipe.core.util.XPipeInstallation;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import lombok.Getter; import lombok.Getter;
import java.io.IOException; import java.io.IOException;

View file

@ -1,7 +1,5 @@
package io.xpipe.app.beacon; package io.xpipe.app.beacon;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
@ -9,6 +7,9 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.beacon.*; import io.xpipe.beacon.*;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.io.IOException; import java.io.IOException;
@ -67,16 +68,22 @@ public class BeaconRequestHandler<T> implements HttpHandler {
} else { } else {
try (InputStream is = exchange.getRequestBody()) { try (InputStream is = exchange.getRequestBody()) {
var read = is.readAllBytes(); var read = is.readAllBytes();
var rawDataRequestClass = beaconInterface.getRequestClass().getDeclaredFields().length == 1 && var rawDataRequestClass = beaconInterface.getRequestClass().getDeclaredFields().length == 1
beaconInterface.getRequestClass().getDeclaredFields()[0].getType().equals(byte[].class); && beaconInterface
.getRequestClass()
.getDeclaredFields()[0]
.getType()
.equals(byte[].class);
if (!new String(read, StandardCharsets.US_ASCII).trim().startsWith("{") && rawDataRequestClass) { if (!new String(read, StandardCharsets.US_ASCII).trim().startsWith("{") && rawDataRequestClass) {
object = createRawDataRequest(beaconInterface, read); object = createRawDataRequest(beaconInterface, read);
} else { } else {
var tree = JacksonMapper.getDefault().readTree(read); var tree = JacksonMapper.getDefault().readTree(read);
TrackEvent.trace("Parsed raw request:\n" + tree.toPrettyString()); TrackEvent.trace("Parsed raw request:\n" + tree.toPrettyString());
var emptyRequestClass = tree.isEmpty() && beaconInterface.getRequestClass().getDeclaredFields().length == 0; var emptyRequestClass = tree.isEmpty()
object = emptyRequestClass ? createDefaultRequest(beaconInterface) : JacksonMapper.getDefault().treeToValue(tree, && beaconInterface.getRequestClass().getDeclaredFields().length == 0;
beaconInterface.getRequestClass()); object = emptyRequestClass
? createDefaultRequest(beaconInterface)
: JacksonMapper.getDefault().treeToValue(tree, beaconInterface.getRequestClass());
TrackEvent.trace("Parsed request object:\n" + object); TrackEvent.trace("Parsed request object:\n" + object);
} }
} }
@ -163,8 +170,11 @@ public class BeaconRequestHandler<T> implements HttpHandler {
c.setAccessible(true); c.setAccessible(true);
var b = c.invoke(null); var b = c.invoke(null);
var setMethod = Arrays.stream(b.getClass().getDeclaredMethods()).filter(method -> method.getParameterCount() == 1 && var setMethod = Arrays.stream(b.getClass().getDeclaredMethods())
method.getParameters()[0].getType().equals(byte[].class)).findFirst().orElseThrow(); .filter(method -> method.getParameterCount() == 1
&& method.getParameters()[0].getType().equals(byte[].class))
.findFirst()
.orElseThrow();
setMethod.invoke(b, (Object) s); setMethod.invoke(b, (Object) s);
var m = b.getClass().getDeclaredMethod("build"); var m = b.getClass().getDeclaredMethod("build");

View file

@ -1,6 +1,7 @@
package io.xpipe.app.beacon; package io.xpipe.app.beacon;
import io.xpipe.beacon.BeaconClientInformation; import io.xpipe.beacon.BeaconClientInformation;
import lombok.Value; import lombok.Value;
@Value @Value

View file

@ -3,6 +3,7 @@ package io.xpipe.app.beacon;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.ShellTemp; import io.xpipe.app.util.ShellTemp;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -60,7 +61,7 @@ public class BlobManager {
try (var fileOut = Files.newOutputStream(file)) { try (var fileOut = Files.newOutputStream(file)) {
blob.transferTo(fileOut); blob.transferTo(fileOut);
} }
fileBlobs.put(uuid,file); fileBlobs.put(uuid, file);
} }
public InputStream getBlob(UUID uuid) throws Exception { public InputStream getBlob(UUID uuid) throws Exception {

View file

@ -1,12 +1,13 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.util.AskpassAlert; import io.xpipe.app.util.AskpassAlert;
import io.xpipe.app.util.SecretManager; import io.xpipe.app.util.SecretManager;
import io.xpipe.app.util.SecretQueryState; import io.xpipe.app.util.SecretQueryState;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.api.AskpassExchange; import io.xpipe.beacon.api.AskpassExchange;
import com.sun.net.httpserver.HttpExchange;
public class AskpassExchangeImpl extends AskpassExchange { public class AskpassExchangeImpl extends AskpassExchange {
@Override @Override
@ -33,8 +34,6 @@ public class AskpassExchangeImpl extends AskpassExchange {
if (p.getState() != SecretQueryState.NORMAL) { if (p.getState() != SecretQueryState.NORMAL) {
throw new BeaconClientException(SecretQueryState.toErrorMessage(p.getState())); throw new BeaconClientException(SecretQueryState.toErrorMessage(p.getState()));
} }
return Response.builder() return Response.builder().value(secret.inPlace()).build();
.value(secret.inPlace())
.build();
} }
} }

View file

@ -1,11 +1,12 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.beacon.api.ConnectionQueryExchange; import io.xpipe.beacon.api.ConnectionQueryExchange;
import io.xpipe.core.store.StorePath; import io.xpipe.core.store.StorePath;
import com.sun.net.httpserver.HttpExchange;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -41,7 +42,9 @@ public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange {
continue; continue;
} }
if (!typeMatcher.matcher(storeEntry.getProvider().getId().toLowerCase()).matches()) { if (!typeMatcher
.matcher(storeEntry.getProvider().getId().toLowerCase())
.matches()) {
continue; continue;
} }

View file

@ -1,9 +1,10 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.beacon.api.DaemonFocusExchange; import io.xpipe.beacon.api.DaemonFocusExchange;
import com.sun.net.httpserver.HttpExchange;
public class DaemonFocusExchangeImpl extends DaemonFocusExchange { public class DaemonFocusExchangeImpl extends DaemonFocusExchange {
@Override @Override

View file

@ -1,14 +1,14 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.api.DaemonModeExchange; import io.xpipe.beacon.api.DaemonModeExchange;
import com.sun.net.httpserver.HttpExchange;
public class DaemonModeExchangeImpl extends DaemonModeExchange { public class DaemonModeExchangeImpl extends DaemonModeExchange {
@Override @Override
public Object handle(HttpExchange exchange, Request msg) public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException {
throws BeaconClientException {
var mode = OperationMode.map(msg.getMode()); var mode = OperationMode.map(msg.getMode());
if (!mode.isSupported()) { if (!mode.isSupported()) {
throw new BeaconClientException("Unsupported mode: " + msg.getMode().getDisplayName() + ". Supported: " throw new BeaconClientException("Unsupported mode: " + msg.getMode().getDisplayName() + ". Supported: "

View file

@ -1,17 +1,17 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.launcher.LauncherInput; import io.xpipe.app.launcher.LauncherInput;
import io.xpipe.app.util.PlatformState; import io.xpipe.app.util.PlatformState;
import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.BeaconServerException;
import io.xpipe.beacon.api.DaemonOpenExchange; import io.xpipe.beacon.api.DaemonOpenExchange;
import com.sun.net.httpserver.HttpExchange;
public class DaemonOpenExchangeImpl extends DaemonOpenExchange { public class DaemonOpenExchangeImpl extends DaemonOpenExchange {
@Override @Override
public Object handle(HttpExchange exchange, Request msg) public Object handle(HttpExchange exchange, Request msg) throws BeaconServerException {
throws BeaconServerException {
if (msg.getArguments().isEmpty()) { if (msg.getArguments().isEmpty()) {
if (!OperationMode.switchToSyncIfPossible(OperationMode.GUI)) { if (!OperationMode.switchToSyncIfPossible(OperationMode.GUI)) {
throw new BeaconServerException(PlatformState.getLastError()); throw new BeaconServerException(PlatformState.getLastError());

View file

@ -1,9 +1,10 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.beacon.api.DaemonStatusExchange; import io.xpipe.beacon.api.DaemonStatusExchange;
import com.sun.net.httpserver.HttpExchange;
public class DaemonStatusExchangeImpl extends DaemonStatusExchange { public class DaemonStatusExchangeImpl extends DaemonStatusExchange {
@Override @Override

View file

@ -1,10 +1,11 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.beacon.api.DaemonStopExchange; import io.xpipe.beacon.api.DaemonStopExchange;
import com.sun.net.httpserver.HttpExchange;
public class DaemonStopExchangeImpl extends DaemonStopExchange { public class DaemonStopExchangeImpl extends DaemonStopExchange {
@Override @Override

View file

@ -1,9 +1,10 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppProperties;
import io.xpipe.beacon.api.DaemonVersionExchange; import io.xpipe.beacon.api.DaemonVersionExchange;
import com.sun.net.httpserver.HttpExchange;
public class DaemonVersionExchangeImpl extends DaemonVersionExchange { public class DaemonVersionExchangeImpl extends DaemonVersionExchange {
@Override @Override

View file

@ -1,8 +1,9 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.BlobManager; import io.xpipe.app.beacon.BlobManager;
import io.xpipe.beacon.api.FsBlobExchange; import io.xpipe.beacon.api.FsBlobExchange;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.util.UUID; import java.util.UUID;
@ -16,9 +17,9 @@ public class FsBlobExchangeImpl extends FsBlobExchange {
var size = exchange.getRequestBody().available(); var size = exchange.getRequestBody().available();
if (size > 100_000_000) { if (size > 100_000_000) {
BlobManager.get().store(id,exchange.getRequestBody()); BlobManager.get().store(id, exchange.getRequestBody());
} else { } else {
BlobManager.get().store(id,exchange.getRequestBody().readAllBytes()); BlobManager.get().store(id, exchange.getRequestBody().readAllBytes());
} }
return Response.builder().blob(id).build(); return Response.builder().blob(id).build();
} }

View file

@ -1,12 +1,13 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.beacon.BlobManager; import io.xpipe.app.beacon.BlobManager;
import io.xpipe.app.util.FixedSizeInputStream; import io.xpipe.app.util.FixedSizeInputStream;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.api.FsReadExchange; import io.xpipe.beacon.api.FsReadExchange;
import io.xpipe.core.store.ConnectionFileSystem; import io.xpipe.core.store.ConnectionFileSystem;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
@ -29,15 +30,17 @@ public class FsReadExchangeImpl extends FsReadExchange {
if (size > 100_000_000) { if (size > 100_000_000) {
var file = BlobManager.get().newBlobFile(); var file = BlobManager.get().newBlobFile();
try (var in = fs.openInput(msg.getPath().toString())) { try (var in = fs.openInput(msg.getPath().toString())) {
try (var fileOut = Files.newOutputStream(file.resolve(msg.getPath().getFileName())); try (var fileOut =
var fixedIn = new FixedSizeInputStream(new BufferedInputStream(in), size)) { Files.newOutputStream(file.resolve(msg.getPath().getFileName()));
var fixedIn = new FixedSizeInputStream(new BufferedInputStream(in), size)) {
fixedIn.transferTo(fileOut); fixedIn.transferTo(fileOut);
} }
in.transferTo(OutputStream.nullOutputStream()); in.transferTo(OutputStream.nullOutputStream());
} }
exchange.sendResponseHeaders(200, size); exchange.sendResponseHeaders(200, size);
try (var fileIn = Files.newInputStream(file); var out = exchange.getResponseBody()) { try (var fileIn = Files.newInputStream(file);
var out = exchange.getResponseBody()) {
fileIn.transferTo(out); fileIn.transferTo(out);
} }
return Response.builder().build(); return Response.builder().build();

View file

@ -1,10 +1,11 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.beacon.BlobManager; import io.xpipe.app.beacon.BlobManager;
import io.xpipe.app.util.ScriptHelper; import io.xpipe.app.util.ScriptHelper;
import io.xpipe.beacon.api.FsScriptExchange; import io.xpipe.beacon.api.FsScriptExchange;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -20,7 +21,10 @@ public class FsScriptExchangeImpl extends FsScriptExchange {
data = new String(in.readAllBytes(), StandardCharsets.UTF_8); data = new String(in.readAllBytes(), StandardCharsets.UTF_8);
} }
var file = ScriptHelper.getExecScriptFile(shell.getControl()); var file = ScriptHelper.getExecScriptFile(shell.getControl());
shell.getControl().getShellDialect().createScriptTextFileWriteCommand(shell.getControl(), data, file.toString()).execute(); shell.getControl()
.getShellDialect()
.createScriptTextFileWriteCommand(shell.getControl(), data, file.toString())
.execute();
return Response.builder().path(file).build(); return Response.builder().path(file).build();
} }
} }

View file

@ -1,10 +1,11 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.beacon.BlobManager; import io.xpipe.app.beacon.BlobManager;
import io.xpipe.beacon.api.FsWriteExchange; import io.xpipe.beacon.api.FsWriteExchange;
import io.xpipe.core.store.ConnectionFileSystem; import io.xpipe.core.store.ConnectionFileSystem;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
public class FsWriteExchangeImpl extends FsWriteExchange { public class FsWriteExchangeImpl extends FsWriteExchange {
@ -15,7 +16,7 @@ public class FsWriteExchangeImpl extends FsWriteExchange {
var shell = AppBeaconServer.get().getCache().getShellSession(msg.getConnection()); var shell = AppBeaconServer.get().getCache().getShellSession(msg.getConnection());
var fs = new ConnectionFileSystem(shell.getControl()); var fs = new ConnectionFileSystem(shell.getControl());
try (var in = BlobManager.get().getBlob(msg.getBlob()); try (var in = BlobManager.get().getBlob(msg.getBlob());
var os = fs.openOutput(msg.getPath().toString(), in.available())) { var os = fs.openOutput(msg.getPath().toString(), in.available())) {
in.transferTo(os); in.transferTo(os);
} }
return Response.builder().build(); return Response.builder().build();

View file

@ -1,6 +1,5 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.beacon.BeaconSession; import io.xpipe.app.beacon.BeaconSession;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
@ -8,6 +7,8 @@ import io.xpipe.beacon.BeaconAuthMethod;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.api.HandshakeExchange; import io.xpipe.beacon.api.HandshakeExchange;
import com.sun.net.httpserver.HttpExchange;
import java.util.UUID; import java.util.UUID;
public class HandshakeExchangeImpl extends HandshakeExchange { public class HandshakeExchangeImpl extends HandshakeExchange {
@ -18,8 +19,7 @@ public class HandshakeExchangeImpl extends HandshakeExchange {
} }
@Override @Override
public Object handle(HttpExchange exchange, Request body) public Object handle(HttpExchange exchange, Request body) throws BeaconClientException {
throws BeaconClientException {
if (!checkAuth(body.getAuth())) { if (!checkAuth(body.getAuth())) {
throw new BeaconClientException("Authentication failed"); throw new BeaconClientException("Authentication failed");
} }

View file

@ -1,8 +1,9 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.beacon.api.ShellExecExchange; import io.xpipe.beacon.api.ShellExecExchange;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;

View file

@ -1,12 +1,13 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.beacon.BeaconShellSession; import io.xpipe.app.beacon.BeaconShellSession;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.api.ShellStartExchange; import io.xpipe.beacon.api.ShellStartExchange;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
public class ShellStartExchangeImpl extends ShellStartExchange { public class ShellStartExchangeImpl extends ShellStartExchange {
@ -30,6 +31,11 @@ public class ShellStartExchangeImpl extends ShellStartExchange {
if (existing.isEmpty()) { if (existing.isEmpty()) {
AppBeaconServer.get().getCache().getShellSessions().add(new BeaconShellSession(e, control)); AppBeaconServer.get().getCache().getShellSessions().add(new BeaconShellSession(e, control));
} }
return Response.builder().shellDialect(control.getShellDialect()).osType(control.getOsType()).osName(control.getOsName()).temp(control.getSystemTemporaryDirectory()).build(); return Response.builder()
.shellDialect(control.getShellDialect())
.osType(control.getOsType())
.osName(control.getOsName())
.temp(control.getSystemTemporaryDirectory())
.build();
} }
} }

View file

@ -1,8 +1,9 @@
package io.xpipe.app.beacon.impl; package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.beacon.api.ShellStopExchange; import io.xpipe.beacon.api.ShellStopExchange;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
public class ShellStopExchangeImpl extends ShellStopExchange { public class ShellStopExchangeImpl extends ShellStopExchange {

View file

@ -2,17 +2,13 @@ package io.xpipe.app.beacon.impl;
import io.xpipe.app.util.TerminalLauncherManager; import io.xpipe.app.util.TerminalLauncherManager;
import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.BeaconServerException;
import io.xpipe.beacon.api.TerminalLaunchExchange; import io.xpipe.beacon.api.TerminalLaunchExchange;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
public class TerminalLaunchExchangeImpl extends TerminalLaunchExchange { public class TerminalLaunchExchangeImpl extends TerminalLaunchExchange {
@Override @Override
public Object handle(HttpExchange exchange, Request msg) public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException {
throws BeaconClientException {
var r = TerminalLauncherManager.performLaunch(msg.getRequest()); var r = TerminalLauncherManager.performLaunch(msg.getRequest());
return Response.builder().targetFile(r).build(); return Response.builder().targetFile(r).build();
} }

View file

@ -7,12 +7,9 @@ import io.xpipe.beacon.api.TerminalWaitExchange;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
public class TerminalWaitExchangeImpl extends TerminalWaitExchange { public class TerminalWaitExchangeImpl extends TerminalWaitExchange {
@Override @Override
public Object handle(HttpExchange exchange, Request msg) public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException, BeaconServerException {
throws BeaconClientException, BeaconServerException {
TerminalLauncherManager.waitForCompletion(msg.getRequest()); TerminalLauncherManager.waitForCompletion(msg.getRequest());
return Response.builder().build(); return Response.builder().build();
} }

View file

@ -6,6 +6,7 @@ import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
@ -23,13 +24,14 @@ public final class BrowserBookmarkComp extends SimpleComp {
private final Predicate<StoreEntryWrapper> applicable; private final Predicate<StoreEntryWrapper> applicable;
private final BiConsumer<StoreEntryWrapper, BooleanProperty> action; private final BiConsumer<StoreEntryWrapper, BooleanProperty> action;
private final Property<StoreCategoryWrapper> category; private final Property<StoreCategoryWrapper> category;
private final Property<String> filter ; private final Property<String> filter;
public BrowserBookmarkComp( public BrowserBookmarkComp(
ObservableValue<DataStoreEntry> selected, ObservableValue<DataStoreEntry> selected,
Predicate<StoreEntryWrapper> applicable, Predicate<StoreEntryWrapper> applicable,
BiConsumer<StoreEntryWrapper, BooleanProperty> action, Property<StoreCategoryWrapper> category, Property<String> filter BiConsumer<StoreEntryWrapper, BooleanProperty> action,
) { Property<StoreCategoryWrapper> category,
Property<String> filter) {
this.selected = selected; this.selected = selected;
this.applicable = applicable; this.applicable = applicable;
this.action = action; this.action = action;
@ -62,7 +64,11 @@ public final class BrowserBookmarkComp extends SimpleComp {
var section = new StoreSectionMiniComp( var section = new StoreSectionMiniComp(
StoreSection.createTopLevel( StoreSection.createTopLevel(
StoreViewState.get().getAllEntries(), this::filter, filter, category, StoreViewState.get().getEntriesListUpdateObservable()), StoreViewState.get().getAllEntries(),
this::filter,
filter,
category,
StoreViewState.get().getEntriesListUpdateObservable()),
augment, augment,
entryWrapper -> action.accept(entryWrapper, busy), entryWrapper -> action.accept(entryWrapper, busy),
true); true);

View file

@ -1,6 +1,5 @@
package io.xpipe.app.browser; package io.xpipe.app.browser;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.store.StoreCategoryWrapper; import io.xpipe.app.comp.store.StoreCategoryWrapper;
import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;
@ -8,10 +7,13 @@ import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.FilterComp; import io.xpipe.app.fxcomps.impl.FilterComp;
import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.HorizontalComp;
import io.xpipe.app.util.DataStoreCategoryChoiceComp; import io.xpipe.app.util.DataStoreCategoryChoiceComp;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import lombok.Getter; import lombok.Getter;
import java.util.List; import java.util.List;
@ -19,7 +21,8 @@ import java.util.List;
@Getter @Getter
public final class BrowserBookmarkHeaderComp extends SimpleComp { public final class BrowserBookmarkHeaderComp extends SimpleComp {
private final Property<StoreCategoryWrapper> category = new SimpleObjectProperty<>(StoreViewState.get().getActiveCategory().getValue()); private final Property<StoreCategoryWrapper> category =
new SimpleObjectProperty<>(StoreViewState.get().getActiveCategory().getValue());
private final Property<String> filter = new SimpleStringProperty(); private final Property<String> filter = new SimpleStringProperty();
@Override @Override
@ -30,13 +33,17 @@ public final class BrowserBookmarkHeaderComp extends SimpleComp {
this.category) this.category)
.styleClass(Styles.LEFT_PILL) .styleClass(Styles.LEFT_PILL)
.apply(struc -> AppFont.medium(struc.get())); .apply(struc -> AppFont.medium(struc.get()));
var filter = new FilterComp(this.filter).styleClass(Styles.RIGHT_PILL).apply(struc -> AppFont.medium(struc.get())).hgrow(); var filter = new FilterComp(this.filter)
.styleClass(Styles.RIGHT_PILL)
.apply(struc -> AppFont.medium(struc.get()))
.hgrow();
var top = new HorizontalComp(List.of(category, filter)) var top = new HorizontalComp(List.of(category, filter))
.apply(struc -> struc.get().setFillHeight(true)) .apply(struc -> struc.get().setFillHeight(true))
.apply(struc -> { .apply(struc -> {
((Region) struc.get().getChildren().get(0)).prefHeightProperty().bind( ((Region) struc.get().getChildren().get(0))
((Region) struc.get().getChildren().get(1)).heightProperty()); .prefHeightProperty()
.bind(((Region) struc.get().getChildren().get(1)).heightProperty());
}) })
.styleClass("bookmarks-header") .styleClass("bookmarks-header")
.createRegion(); .createRegion();

View file

@ -28,9 +28,9 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import atlantafx.base.theme.Styles; import atlantafx.base.theme.Styles;
import javafx.scene.shape.Rectangle;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
public class BrowserNavBar extends Comp<BrowserNavBar.Structure> { public class BrowserNavBar extends Comp<BrowserNavBar.Structure> {

View file

@ -10,6 +10,7 @@ import io.xpipe.app.fxcomps.augment.DragOverPseudoClassAugment;
import io.xpipe.app.fxcomps.impl.*; import io.xpipe.app.fxcomps.impl.*;
import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.fxcomps.util.DerivedObservableList;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@ -18,6 +19,7 @@ import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode; import javafx.scene.input.TransferMode;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
import java.io.File; import java.io.File;
@ -100,7 +102,8 @@ public class BrowserTransferComp extends SimpleComp {
return p; return p;
}); });
var listBox = new VerticalComp(List.of(list, dragNotice)).padding(new Insets(10, 10, 5, 10)) var listBox = new VerticalComp(List.of(list, dragNotice))
.padding(new Insets(10, 10, 5, 10))
.apply(struc -> struc.get().setMinHeight(200)) .apply(struc -> struc.get().setMinHeight(200))
.apply(struc -> struc.get().setMaxHeight(200)); .apply(struc -> struc.get().setMaxHeight(200));
var stack = LoadingOverlayComp.noProgress( var stack = LoadingOverlayComp.noProgress(

View file

@ -163,13 +163,15 @@ public class OpenFileSystemComp extends SimpleComp {
var statusBar = new BrowserStatusBarComp(model); var statusBar = new BrowserStatusBarComp(model);
fileListElements.add(statusBar); fileListElements.add(statusBar);
} }
var fileList = new VerticalComp(fileListElements).styleClass("browser-content").apply(struc -> { var fileList = new VerticalComp(fileListElements)
struc.get().focusedProperty().addListener((observable, oldValue, newValue) -> { .styleClass("browser-content")
if (newValue) { .apply(struc -> {
struc.get().getChildren().getFirst().requestFocus(); struc.get().focusedProperty().addListener((observable, oldValue, newValue) -> {
} if (newValue) {
}); struc.get().getChildren().getFirst().requestFocus();
}); }
});
});
var home = new BrowserOverviewComp(model).styleClass("browser-content"); var home = new BrowserOverviewComp(model).styleClass("browser-content");
var stack = new MultiContentComp(Map.of( var stack = new MultiContentComp(Map.of(

View file

@ -98,8 +98,7 @@ public class BrowserChooserComp extends SimpleComp {
var bookmarkTopBar = new BrowserBookmarkHeaderComp(); var bookmarkTopBar = new BrowserBookmarkHeaderComp();
var bookmarksList = new BrowserBookmarkComp( var bookmarksList = new BrowserBookmarkComp(
BindingsHelper.map( BindingsHelper.map(model.getSelectedEntry(), v -> v.getEntry().get()),
model.getSelectedEntry(), v -> v.getEntry().get()),
applicable, applicable,
action, action,
bookmarkTopBar.getCategory(), bookmarkTopBar.getCategory(),

View file

@ -13,6 +13,7 @@ import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
@ -66,21 +67,22 @@ public class BrowserSessionComp extends SimpleComp {
var bookmarkTopBar = new BrowserBookmarkHeaderComp(); var bookmarkTopBar = new BrowserBookmarkHeaderComp();
var bookmarksList = new BrowserBookmarkComp( var bookmarksList = new BrowserBookmarkComp(
BindingsHelper.map( BindingsHelper.map(model.getSelectedEntry(), v -> v.getEntry().get()),
model.getSelectedEntry(), v -> v.getEntry().get()), applicable,
applicable, action,
action, bookmarkTopBar.getCategory(),
bookmarkTopBar.getCategory(), bookmarkTopBar.getFilter());
bookmarkTopBar.getFilter());
var bookmarksContainer = new StackComp(List.of(bookmarksList)).styleClass("bookmarks-container"); var bookmarksContainer = new StackComp(List.of(bookmarksList)).styleClass("bookmarks-container");
bookmarksContainer.apply(struc -> { bookmarksContainer
var rec = new Rectangle(); .apply(struc -> {
rec.widthProperty().bind(struc.get().widthProperty()); var rec = new Rectangle();
rec.heightProperty().bind(struc.get().heightProperty()); rec.widthProperty().bind(struc.get().widthProperty());
rec.setArcHeight(7); rec.heightProperty().bind(struc.get().heightProperty());
rec.setArcWidth(7); rec.setArcHeight(7);
struc.get().getChildren().getFirst().setClip(rec); rec.setArcWidth(7);
}).vgrow(); struc.get().getChildren().getFirst().setClip(rec);
})
.vgrow();
var localDownloadStage = new BrowserTransferComp(model.getLocalTransfersStage()) var localDownloadStage = new BrowserTransferComp(model.getLocalTransfersStage())
.hide(PlatformThread.sync(Bindings.createBooleanBinding( .hide(PlatformThread.sync(Bindings.createBooleanBinding(
() -> { () -> {
@ -94,10 +96,12 @@ public class BrowserSessionComp extends SimpleComp {
model.getSelectedEntry()))); model.getSelectedEntry())));
localDownloadStage.prefHeight(200); localDownloadStage.prefHeight(200);
localDownloadStage.maxHeight(200); localDownloadStage.maxHeight(200);
var vertical = new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left"); var vertical =
new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left");
var split = new SimpleDoubleProperty(); var split = new SimpleDoubleProperty();
var tabs = new BrowserSessionTabsComp(model, split).apply(struc -> struc.get().setViewOrder(1)) var tabs = new BrowserSessionTabsComp(model, split)
.apply(struc -> struc.get().setViewOrder(1))
.apply(struc -> struc.get().setPickOnBounds(false)); .apply(struc -> struc.get().setPickOnBounds(false));
var splitPane = new SideSplitPaneComp(vertical, tabs) var splitPane = new SideSplitPaneComp(vertical, tabs)
.withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth())

View file

@ -71,28 +71,30 @@ public class BrowserSessionTabsComp extends SimpleComp {
Styles.toggleStyleClass(tabs, TabPane.STYLE_CLASS_FLOATING); Styles.toggleStyleClass(tabs, TabPane.STYLE_CLASS_FLOATING);
toggleStyleClass(tabs, DENSE); toggleStyleClass(tabs, DENSE);
tabs.skinProperty().subscribe(newValue -> { tabs.skinProperty().subscribe(newValue -> {
if (newValue != null) { if (newValue != null) {
Platform.runLater(() -> { Platform.runLater(() -> {
tabs.setClip(null); tabs.setClip(null);
tabs.setPickOnBounds(false); tabs.setPickOnBounds(false);
tabs.lookupAll(".tab-header-area").forEach(node -> { tabs.lookupAll(".tab-header-area").forEach(node -> {
node.setClip(null); node.setClip(null);
node.setPickOnBounds(false); node.setPickOnBounds(false);
}); });
tabs.lookupAll(".headers-region").forEach(node -> { tabs.lookupAll(".headers-region").forEach(node -> {
node.setClip(null); node.setClip(null);
node.setPickOnBounds(false); node.setPickOnBounds(false);
}); });
Region headerArea = (Region) tabs.lookup(".tab-header-area"); Region headerArea = (Region) tabs.lookup(".tab-header-area");
headerArea.paddingProperty().bind(Bindings.createObjectBinding(() -> new Insets(0, 0, 0, -leftPadding.get() + 2), leftPadding)); headerArea
}); .paddingProperty()
} .bind(Bindings.createObjectBinding(
() -> new Insets(0, 0, 0, -leftPadding.get() + 2), leftPadding));
}); });
}
});
var map = new HashMap<BrowserSessionTab<?>, Tab>(); var map = new HashMap<BrowserSessionTab<?>, Tab>();
// Restore state // Restore state
model.getSessionEntries().forEach(v -> { model.getSessionEntries().forEach(v -> {

View file

@ -9,6 +9,7 @@ import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.scene.control.ButtonBase; import javafx.scene.control.ButtonBase;

View file

@ -54,7 +54,9 @@ public class MarkdownComp extends Comp<CompStructure<StackPane>> {
.setUserDataDirectory( .setUserDataDirectory(
AppProperties.get().getDataDir().resolve("webview").toFile()); AppProperties.get().getDataDir().resolve("webview").toFile());
wv.setPageFill(Color.TRANSPARENT); wv.setPageFill(Color.TRANSPARENT);
var theme = AppPrefs.get() != null && AppPrefs.get().theme.getValue() != null && AppPrefs.get().theme.getValue().isDark() var theme = AppPrefs.get() != null
&& AppPrefs.get().theme.getValue() != null
&& AppPrefs.get().theme.getValue().isDark()
? "misc/github-markdown-dark.css" ? "misc/github-markdown-dark.css"
: "misc/github-markdown-light.css"; : "misc/github-markdown-light.css";
var url = AppResources.getResourceURL(AppResources.XPIPE_MODULE, theme).orElseThrow(); var url = AppResources.getResourceURL(AppResources.XPIPE_MODULE, theme).orElseThrow();

View file

@ -13,6 +13,7 @@ import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.update.UpdateAvailableAlert; import io.xpipe.app.update.UpdateAvailableAlert;
import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.Hyperlinks;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.Property; import javafx.beans.property.Property;
@ -159,8 +160,8 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
{ {
var b = new IconButtonComp( var b = new IconButtonComp(
"mdi2c-code-json", "mdi2c-code-json",
() -> Hyperlinks.open("http://localhost:" () -> Hyperlinks.open(
+ AppBeaconServer.get().getPort())) "http://localhost:" + AppBeaconServer.get().getPort()))
.tooltipKey("api") .tooltipKey("api")
.apply(simpleBorders) .apply(simpleBorders)
.accessibleTextKey("api"); .accessibleTextKey("api");

View file

@ -137,8 +137,11 @@ public class StoreCreationComp extends DialogComp {
} }
// Don't use the all connections category // Don't use the all connections category
if (targetCategory.equals(DataStorage.get().getAllConnectionsCategory().getUuid())) { if (targetCategory.equals(
targetCategory = DataStorage.get().getDefaultConnectionsCategory().getUuid(); DataStorage.get().getAllConnectionsCategory().getUuid())) {
targetCategory = DataStorage.get()
.getDefaultConnectionsCategory()
.getUuid();
} }
return DataStoreEntry.createNew( return DataStoreEntry.createNew(

View file

@ -405,7 +405,6 @@ public abstract class StoreEntryComp extends SimpleComp {
} }
order.getItems().add(top); order.getItems().add(top);
var bottom = new MenuItem(AppI18n.get("stickToBottom"), new FontIcon("mdi2o-order-bool-ascending")); var bottom = new MenuItem(AppI18n.get("stickToBottom"), new FontIcon("mdi2o-order-bool-ascending"));
bottom.setOnAction(event -> { bottom.setOnAction(event -> {
wrapper.setOrder(DataStoreEntry.Order.BOTTOM); wrapper.setOrder(DataStoreEntry.Order.BOTTOM);

View file

@ -16,9 +16,9 @@ import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import atlantafx.base.controls.Popover; import atlantafx.base.controls.Popover;
import javafx.scene.paint.Color;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;

View file

@ -6,12 +6,14 @@ import io.xpipe.app.fxcomps.util.DerivedObservableList;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableIntegerValue; import javafx.beans.value.ObservableIntegerValue;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import lombok.Value; import lombok.Value;
import java.util.ArrayList; import java.util.ArrayList;
@ -61,7 +63,8 @@ public class StoreSection {
} }
private static DerivedObservableList<StoreSection> sorted( private static DerivedObservableList<StoreSection> sorted(
DerivedObservableList<StoreSection> list, ObservableValue<StoreCategoryWrapper> category, DerivedObservableList<StoreSection> list,
ObservableValue<StoreCategoryWrapper> category,
ObservableIntegerValue updateObservable) { ObservableIntegerValue updateObservable) {
if (category == null) { if (category == null) {
return list; return list;
@ -112,16 +115,15 @@ public class StoreSection {
Predicate<StoreEntryWrapper> entryFilter, Predicate<StoreEntryWrapper> entryFilter,
ObservableValue<String> filterString, ObservableValue<String> filterString,
ObservableValue<StoreCategoryWrapper> category, ObservableValue<StoreCategoryWrapper> category,
ObservableIntegerValue updateObservable ObservableIntegerValue updateObservable) {
) {
var topLevel = all.filtered( var topLevel = all.filtered(
section -> { section -> {
return DataStorage.get().isRootEntry(section.getEntry()); return DataStorage.get().isRootEntry(section.getEntry());
}, },
category, category,
updateObservable); updateObservable);
var cached = topLevel.mapped( var cached = topLevel.mapped(storeEntryWrapper ->
storeEntryWrapper -> create(List.of(), storeEntryWrapper, 1, all, entryFilter, filterString, category, updateObservable)); create(List.of(), storeEntryWrapper, 1, all, entryFilter, filterString, category, updateObservable));
var ordered = sorted(cached, category, updateObservable); var ordered = sorted(cached, category, updateObservable);
var shown = ordered.filtered( var shown = ordered.filtered(
section -> { section -> {
@ -178,7 +180,8 @@ public class StoreSection {
updateObservable); updateObservable);
var l = new ArrayList<>(parents); var l = new ArrayList<>(parents);
l.add(e); l.add(e);
var cached = allChildren.mapped(c -> create(l, c, depth + 1, all, entryFilter, filterString, category, updateObservable)); var cached = allChildren.mapped(
c -> create(l, c, depth + 1, all, entryFilter, filterString, category, updateObservable));
var ordered = sorted(cached, category, updateObservable); var ordered = sorted(cached, category, updateObservable);
var filtered = ordered.filtered( var filtered = ordered.filtered(
section -> { section -> {

View file

@ -82,8 +82,8 @@ public class StoreViewState {
private void initSections() { private void initSections() {
try { try {
currentTopLevelSection = currentTopLevelSection = StoreSection.createTopLevel(
StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory, entriesListUpdateObservable); allEntries, storeEntryWrapper -> true, filter, activeCategory, entriesListUpdateObservable);
} catch (Exception exception) { } catch (Exception exception) {
currentTopLevelSection = new StoreSection( currentTopLevelSection = new StoreSection(
null, null,

View file

@ -8,9 +8,11 @@ import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.LicenseProvider;
import javafx.application.Application; import javafx.application.Application;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.stage.Stage; import javafx.stage.Stage;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;

View file

@ -6,6 +6,7 @@ import io.xpipe.app.launcher.LauncherInput;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat; import javafx.scene.input.DataFormat;
import lombok.Setter; import lombok.Setter;
import java.util.List; import java.util.List;

View file

@ -10,10 +10,10 @@ import io.xpipe.app.util.LicenseProvider;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination; import javafx.scene.input.KeyCombination;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
@ -74,13 +74,23 @@ public class AppLayoutModel {
new Entry( new Entry(
AppI18n.observable("browser"), AppI18n.observable("browser"),
"mdi2f-file-cabinet", "mdi2f-file-cabinet",
new BrowserSessionComp(BrowserSessionModel.DEFAULT), new KeyCodeCombination(KeyCode.DIGIT1, KeyCombination.CONTROL_DOWN)), new BrowserSessionComp(BrowserSessionModel.DEFAULT),
new Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp(), new KeyCodeCombination(KeyCode.DIGIT2, KeyCombination.CONTROL_DOWN)), new KeyCodeCombination(KeyCode.DIGIT1, KeyCombination.CONTROL_DOWN)),
new Entry(AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new AppPrefsComp(), new KeyCodeCombination(KeyCode.DIGIT3, KeyCombination.CONTROL_DOWN)), new Entry(
AppI18n.observable("connections"),
"mdi2c-connection",
new StoreLayoutComp(),
new KeyCodeCombination(KeyCode.DIGIT2, KeyCombination.CONTROL_DOWN)),
new Entry(
AppI18n.observable("settings"),
"mdsmz-miscellaneous_services",
new AppPrefsComp(),
new KeyCodeCombination(KeyCode.DIGIT3, KeyCombination.CONTROL_DOWN)),
new Entry( new Entry(
AppI18n.observable("explorePlans"), AppI18n.observable("explorePlans"),
"mdi2p-professional-hexagon", "mdi2p-professional-hexagon",
LicenseProvider.get().overviewPage(), null))); LicenseProvider.get().overviewPage(),
null)));
return l; return l;
} }

View file

@ -1,6 +1,5 @@
package io.xpipe.app.core; package io.xpipe.app.core;
import atlantafx.base.theme.*;
import io.xpipe.app.core.window.AppMainWindow; import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.ext.PrefsChoiceValue; import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
@ -8,6 +7,7 @@ import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.animation.Interpolator; import javafx.animation.Interpolator;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.KeyValue; import javafx.animation.KeyValue;
@ -23,6 +23,8 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.util.Duration; import javafx.util.Duration;
import atlantafx.base.theme.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;

View file

@ -4,8 +4,8 @@ import io.xpipe.app.browser.file.LocalFileSystem;
import io.xpipe.app.browser.icon.FileIconManager; import io.xpipe.app.browser.icon.FileIconManager;
import io.xpipe.app.core.App; import io.xpipe.app.core.App;
import io.xpipe.app.core.AppGreetings; import io.xpipe.app.core.AppGreetings;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.core.check.AppPtbCheck; import io.xpipe.app.core.check.AppPtbCheck;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;

View file

@ -11,6 +11,7 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.CloseBehaviourAlert; import io.xpipe.app.prefs.CloseBehaviourAlert;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Rectangle2D; import javafx.geometry.Rectangle2D;
@ -22,17 +23,18 @@ import javafx.scene.paint.Color;
import javafx.stage.Screen; import javafx.stage.Screen;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
import javax.imageio.ImageIO;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import javax.imageio.ImageIO;
public class AppMainWindow { public class AppMainWindow {

View file

@ -2,6 +2,7 @@ package io.xpipe.app.core.window;
import io.xpipe.app.core.App; import io.xpipe.app.core.App;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.geometry.Rectangle2D; import javafx.geometry.Rectangle2D;
import javafx.stage.Screen; import javafx.stage.Screen;
import javafx.stage.Stage; import javafx.stage.Stage;

View file

@ -8,6 +8,7 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.InputHelper; import io.xpipe.app.util.InputHelper;
import io.xpipe.app.util.ThreadHelper; import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass; import javafx.css.PseudoClass;

View file

@ -4,6 +4,7 @@ import javafx.scene.control.Alert;
import javafx.scene.control.Dialog; import javafx.scene.control.Dialog;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.Window; import javafx.stage.Window;
import lombok.SneakyThrows; import lombok.SneakyThrows;
public class ModifiedAlertStage { public class ModifiedAlertStage {
@ -22,9 +23,10 @@ public class ModifiedAlertStage {
var stageField = c.getDeclaredField("stage"); var stageField = c.getDeclaredField("stage");
stageField.setAccessible(true); stageField.setAccessible(true);
var m = new Stage() { var m = new Stage() {
@SneakyThrows @SneakyThrows
@Override public void centerOnScreen() { @Override
public void centerOnScreen() {
Window owner = getOwner(); Window owner = getOwner();
if (owner != null) { if (owner != null) {
positionStageMethod.invoke(dialog); positionStageMethod.invoke(dialog);
@ -36,6 +38,6 @@ public class ModifiedAlertStage {
} }
}; };
stageField.set(alert,m); stageField.set(alert, m);
} }
} }

View file

@ -3,6 +3,7 @@ package io.xpipe.app.core.window;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import javafx.animation.PauseTransition; import javafx.animation.PauseTransition;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
@ -11,6 +12,7 @@ import javafx.css.PseudoClass;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.Window; import javafx.stage.Window;
import javafx.util.Duration; import javafx.util.Duration;
import lombok.SneakyThrows; import lombok.SneakyThrows;
public class ModifiedStage extends Stage { public class ModifiedStage extends Stage {
@ -21,7 +23,7 @@ public class ModifiedStage extends Stage {
var windowsField = Window.class.getDeclaredField("windows"); var windowsField = Window.class.getDeclaredField("windows");
windowsField.setAccessible(true); windowsField.setAccessible(true);
ObservableList<Window> list = (ObservableList<Window>) windowsField.get(null); ObservableList<Window> list = (ObservableList<Window>) windowsField.get(null);
list.addListener((ListChangeListener<Window>) c -> { list.addListener((ListChangeListener<Window>) c -> {
if (c.next() && c.wasAdded()) { if (c.next() && c.wasAdded()) {
var added = c.getAddedSubList().getFirst(); var added = c.getAddedSubList().getFirst();
if (added instanceof Stage stage) { if (added instanceof Stage stage) {
@ -55,7 +57,9 @@ public class ModifiedStage extends Stage {
} }
var ctrl = new NativeWinWindowControl(stage); var ctrl = new NativeWinWindowControl(stage);
ctrl.setWindowAttribute(DmwaWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE.get(), AppPrefs.get().theme.getValue().isDark()); ctrl.setWindowAttribute(
DmwaWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE.get(),
AppPrefs.get().theme.getValue().isDark());
boolean backdrop; boolean backdrop;
if (AppPrefs.get().performanceMode().get()) { if (AppPrefs.get().performanceMode().get()) {
backdrop = false; backdrop = false;

View file

@ -1,12 +1,13 @@
package io.xpipe.app.core.window; package io.xpipe.app.core.window;
import javafx.stage.Window;
import com.sun.jna.Library; import com.sun.jna.Library;
import com.sun.jna.Pointer; import com.sun.jna.Pointer;
import com.sun.jna.PointerType; import com.sun.jna.PointerType;
import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef; import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT; import com.sun.jna.platform.win32.WinNT;
import javafx.stage.Window;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
@ -51,8 +52,7 @@ public class NativeWinWindowControl {
windowHandle, windowHandle,
DmwaWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE.get(), DmwaWindowAttribute.DWMWA_SYSTEMBACKDROP_TYPE.get(),
new WinDef.DWORDByReference(new WinDef.DWORD(backdrop.get())), new WinDef.DWORDByReference(new WinDef.DWORD(backdrop.get())),
WinDef.DWORD.SIZE WinDef.DWORD.SIZE);
);
return r.longValue() == 0; return r.longValue() == 0;
} }

View file

@ -93,8 +93,11 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
}; };
var section = new StoreSectionMiniComp( var section = new StoreSectionMiniComp(
StoreSection.createTopLevel( StoreSection.createTopLevel(
StoreViewState.get().getAllEntries(), applicable, filterText, selectedCategory, StoreViewState.get() StoreViewState.get().getAllEntries(),
.getEntriesListUpdateObservable()), applicable,
filterText,
selectedCategory,
StoreViewState.get().getEntriesListUpdateObservable()),
(s, comp) -> { (s, comp) -> {
if (!applicable.test(s.getWrapper())) { if (!applicable.test(s.getWrapper())) {
comp.disable(new SimpleBooleanProperty(true)); comp.disable(new SimpleBooleanProperty(true));

View file

@ -93,10 +93,11 @@ public class PrettyImageComp extends SimpleComp {
stack.getChildren().add(storeIcon); stack.getChildren().add(storeIcon);
Consumer<String> update = val -> { Consumer<String> update = val -> {
var useDark = AppPrefs.get() != null && AppPrefs.get().theme.get() != null && AppPrefs.get().theme.get().isDark(); var useDark = AppPrefs.get() != null
&& AppPrefs.get().theme.get() != null
&& AppPrefs.get().theme.get().isDark();
var fixed = val != null var fixed = val != null
? FileNames.getBaseName(val) + (useDark ? "-dark" : "") + "." ? FileNames.getBaseName(val) + (useDark ? "-dark" : "") + "." + FileNames.getExtension(val)
+ FileNames.getExtension(val)
: null; : null;
image.set(fixed); image.set(fixed);

View file

@ -88,10 +88,11 @@ public class PrettySvgComp extends SimpleComp {
} }
Consumer<String> update = val -> { Consumer<String> update = val -> {
var useDark = AppPrefs.get() != null && AppPrefs.get().theme.get() != null && AppPrefs.get().theme.get().isDark(); var useDark = AppPrefs.get() != null
&& AppPrefs.get().theme.get() != null
&& AppPrefs.get().theme.get().isDark();
var fixed = val != null var fixed = val != null
? FileNames.getBaseName(val) + (useDark ? "-dark" : "") + "." ? FileNames.getBaseName(val) + (useDark ? "-dark" : "") + "." + FileNames.getExtension(val)
+ FileNames.getExtension(val)
: null; : null;
image.set(fixed); image.set(fixed);
}; };

View file

@ -14,12 +14,14 @@ import io.xpipe.app.terminal.ExternalTerminalType;
import io.xpipe.app.util.PasswordLockSecretValue; import io.xpipe.app.util.PasswordLockSecretValue;
import io.xpipe.core.util.InPlaceSecretValue; import io.xpipe.core.util.InPlaceSecretValue;
import io.xpipe.core.util.ModuleHelper; import io.xpipe.core.util.ModuleHelper;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableDoubleValue; import javafx.beans.value.ObservableDoubleValue;
import javafx.beans.value.ObservableStringValue; import javafx.beans.value.ObservableStringValue;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import lombok.Getter; import lombok.Getter;
import lombok.Value; import lombok.Value;

View file

@ -44,8 +44,7 @@ public class AppearanceCategory extends AppPrefsCategory {
.nameAndDescription("uiScale") .nameAndDescription("uiScale")
.addComp(new IntFieldComp(prefs.uiScale).maxWidth(100), prefs.uiScale) .addComp(new IntFieldComp(prefs.uiScale).maxWidth(100), prefs.uiScale)
.nameAndDescription("useSystemFont") .nameAndDescription("useSystemFont")
.addToggle(prefs.useSystemFont) .addToggle(prefs.useSystemFont))
)
.addTitle("windowOptions") .addTitle("windowOptions")
.sub(new OptionsBuilder() .sub(new OptionsBuilder()
.nameAndDescription("windowOpacity") .nameAndDescription("windowOpacity")

View file

@ -2,8 +2,8 @@ package io.xpipe.app.prefs;
import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.ext.PrefsChoiceValue; import io.xpipe.app.ext.PrefsChoiceValue;
import javafx.beans.property.Property; import javafx.beans.property.Property;

View file

@ -90,8 +90,7 @@ public class DataStoreEntry extends StorageElement {
boolean expanded, boolean expanded,
DataStoreColor color, DataStoreColor color,
String notes, String notes,
Order explicitOrder Order explicitOrder) {
) {
super(directory, uuid, name, lastUsed, lastModified, dirty); super(directory, uuid, name, lastUsed, lastModified, dirty);
this.categoryUuid = categoryUuid; this.categoryUuid = categoryUuid;
this.store = DataStorageParser.storeFromNode(storeNode); this.store = DataStorageParser.storeFromNode(storeNode);
@ -116,8 +115,7 @@ public class DataStoreEntry extends StorageElement {
Instant lastUsed, Instant lastUsed,
Instant lastModified, Instant lastModified,
DataStore store, DataStore store,
Order explicitOrder Order explicitOrder) {
) {
super(directory, uuid, name, lastUsed, lastModified, false); super(directory, uuid, name, lastUsed, lastModified, false);
this.categoryUuid = categoryUuid; this.categoryUuid = categoryUuid;
this.store = store; this.store = store;
@ -604,7 +602,6 @@ public class DataStoreEntry extends StorageElement {
} }
} }
@Getter @Getter
public enum Order { public enum Order {
@JsonProperty("top") @JsonProperty("top")

View file

@ -158,8 +158,8 @@ public class StandardStorage extends DataStorage {
dataStoreCategory.setCategoryUuid(DEFAULT_CATEGORY_UUID); dataStoreCategory.setCategoryUuid(DEFAULT_CATEGORY_UUID);
} }
if (dataStoreCategory.getCategoryUuid() != null && if (dataStoreCategory.getCategoryUuid() != null
dataStoreCategory.getCategoryUuid().equals(ALL_CONNECTIONS_CATEGORY_UUID)) { && dataStoreCategory.getCategoryUuid().equals(ALL_CONNECTIONS_CATEGORY_UUID)) {
dataStoreCategory.setCategoryUuid(DEFAULT_CATEGORY_UUID); dataStoreCategory.setCategoryUuid(DEFAULT_CATEGORY_UUID);
} }
}); });

View file

@ -19,7 +19,10 @@ import java.util.function.UnaryOperator;
public class MarkdownHelper { public class MarkdownHelper {
public static String toHtml( public static String toHtml(
String value, UnaryOperator<String> headTransformation, UnaryOperator<String> bodyTransformation, String bodyStyleClass) { String value,
UnaryOperator<String> headTransformation,
UnaryOperator<String> bodyTransformation,
String bodyStyleClass) {
MutableDataSet options = new MutableDataSet() MutableDataSet options = new MutableDataSet()
.set( .set(
Parser.EXTENSIONS, Parser.EXTENSIONS,
@ -47,7 +50,8 @@ public class MarkdownHelper {
var html = renderer.render(document); var html = renderer.render(document);
var result = bodyTransformation.apply(html); var result = bodyTransformation.apply(html);
var headContent = headTransformation.apply("<meta charset=\"utf-8\"/>"); var headContent = headTransformation.apply("<meta charset=\"utf-8\"/>");
return "<html><head>" + headContent + "</head><body" + (bodyStyleClass != null ? " class=\"" + bodyStyleClass + "\"" : "") + "><article class=\"markdown-body\">" + result return "<html><head>" + headContent + "</head><body"
+ "</article></body></html>"; + (bodyStyleClass != null ? " class=\"" + bodyStyleClass + "\"" : "")
+ "><article class=\"markdown-body\">" + result + "</article></body></html>";
} }
} }

View file

@ -56,14 +56,21 @@ public class SecretManager {
return false; return false;
} }
public static SecretValue retrieve(SecretRetrievalStrategy strategy, String prompt, UUID secretId, int sub, boolean interactive) { public static SecretValue retrieve(
SecretRetrievalStrategy strategy, String prompt, UUID secretId, int sub, boolean interactive) {
if (!strategy.expectsQuery()) { if (!strategy.expectsQuery()) {
return null; return null;
} }
var uuid = UUID.randomUUID(); var uuid = UUID.randomUUID();
var p = expectAskpass( var p = expectAskpass(
uuid, secretId, List.of(strategy.query()), SecretQuery.prompt(false), List.of(), CountDown.of(), interactive); uuid,
secretId,
List.of(strategy.query()),
SecretQuery.prompt(false),
List.of(),
CountDown.of(),
interactive);
p.preAdvance(sub); p.preAdvance(sub);
var r = p.process(prompt); var r = p.process(prompt);
completeRequest(uuid); completeRequest(uuid);

View file

@ -32,8 +32,7 @@ public class SecretQueryProgress {
@NonNull SecretQuery fallback, @NonNull SecretQuery fallback,
@NonNull List<SecretQueryFilter> filters, @NonNull List<SecretQueryFilter> filters,
@NonNull CountDown countDown, @NonNull CountDown countDown,
boolean interactive boolean interactive) {
) {
this.requestId = requestId; this.requestId = requestId;
this.storeId = storeId; this.storeId = storeId;
this.suppliers = new ArrayList<>(suppliers); this.suppliers = new ArrayList<>(suppliers);

View file

@ -60,7 +60,8 @@ public interface SecretRetrievalStrategy {
@Override @Override
public SecretQueryResult query(String prompt) { public SecretQueryResult query(String prompt) {
return new SecretQueryResult( return new SecretQueryResult(
value != null ? value.getInternalSecret() : InPlaceSecretValue.of(""), SecretQueryState.NORMAL); value != null ? value.getInternalSecret() : InPlaceSecretValue.of(""),
SecretQueryState.NORMAL);
} }
@Override @Override
@ -180,7 +181,8 @@ public interface SecretRetrievalStrategy {
@Override @Override
public SecretQueryResult query(String prompt) { public SecretQueryResult query(String prompt) {
try (var cc = new LocalStore().control().command(command).start()) { try (var cc = new LocalStore().control().command(command).start()) {
return new SecretQueryResult(InPlaceSecretValue.of(cc.readStdoutOrThrow()), SecretQueryState.NORMAL); return new SecretQueryResult(
InPlaceSecretValue.of(cc.readStdoutOrThrow()), SecretQueryState.NORMAL);
} catch (Exception ex) { } catch (Exception ex) {
ErrorEvent.fromThrowable("Unable to retrieve password with command " + command, ex) ErrorEvent.fromThrowable("Unable to retrieve password with command " + command, ex)
.handle(); .handle();

View file

@ -139,7 +139,9 @@ open module io.xpipe.app {
DaemonStatusExchangeImpl, DaemonStatusExchangeImpl,
DaemonStopExchangeImpl, DaemonStopExchangeImpl,
HandshakeExchangeImpl, HandshakeExchangeImpl,
DaemonModeExchangeImpl, FsBlobExchangeImpl, FsReadExchangeImpl, DaemonModeExchangeImpl,
FsBlobExchangeImpl,
FsReadExchangeImpl,
FsScriptExchangeImpl, FsScriptExchangeImpl,
FsWriteExchangeImpl, FsWriteExchangeImpl,
AskpassExchangeImpl, AskpassExchangeImpl,

View file

@ -1,7 +1,8 @@
package io.xpipe.beacon; package io.xpipe.beacon;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.core.util.ModuleLayerLoader; import io.xpipe.core.util.ModuleLayerLoader;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.util.List; import java.util.List;
@ -71,8 +72,7 @@ public abstract class BeaconInterface<T> {
public abstract String getPath(); public abstract String getPath();
public Object handle(HttpExchange exchange, T body) public Object handle(HttpExchange exchange, T body) throws BeaconClientException, BeaconServerException {
throws BeaconClientException, BeaconServerException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View file

@ -28,8 +28,11 @@ public class BeaconServer {
} }
private static List<String> toProcessCommand(String toExec) { private static List<String> toProcessCommand(String toExec) {
// Having the trailing space is very important to force cmd to not interpret surrounding spaces and removing them // Having the trailing space is very important to force cmd to not interpret surrounding spaces and removing
return OsType.getLocal().equals(OsType.WINDOWS) ? List.of("cmd", "/c", toExec + " ") : List.of("sh", "-c", toExec); // them
return OsType.getLocal().equals(OsType.WINDOWS)
? List.of("cmd", "/c", toExec + " ")
: List.of("sh", "-c", toExec);
} }
public static Process tryStartCustom() throws Exception { public static Process tryStartCustom() throws Exception {

View file

@ -1,6 +1,7 @@
package io.xpipe.beacon.api; package io.xpipe.beacon.api;
import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconInterface;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;

View file

@ -2,6 +2,7 @@ package io.xpipe.beacon.api;
import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FilePath;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -22,6 +23,7 @@ public class FsReadExchange extends BeaconInterface<FsReadExchange.Request> {
public static class Request { public static class Request {
@NonNull @NonNull
UUID connection; UUID connection;
@NonNull @NonNull
FilePath path; FilePath path;
} }

View file

@ -2,6 +2,7 @@ package io.xpipe.beacon.api;
import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FilePath;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -22,6 +23,7 @@ public class FsScriptExchange extends BeaconInterface<FsScriptExchange.Request>
public static class Request { public static class Request {
@NonNull @NonNull
UUID connection; UUID connection;
@NonNull @NonNull
UUID blob; UUID blob;
} }

View file

@ -2,6 +2,7 @@ package io.xpipe.beacon.api;
import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FilePath;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -22,8 +23,10 @@ public class FsWriteExchange extends BeaconInterface<FsWriteExchange.Request> {
public static class Request { public static class Request {
@NonNull @NonNull
UUID connection; UUID connection;
@NonNull @NonNull
UUID blob; UUID blob;
@NonNull @NonNull
FilePath path; FilePath path;
} }

View file

@ -4,6 +4,7 @@ import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellDialect; import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FilePath;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -32,10 +33,13 @@ public class ShellStartExchange extends BeaconInterface<ShellStartExchange.Reque
public static class Response { public static class Response {
@NonNull @NonNull
ShellDialect shellDialect; ShellDialect shellDialect;
@NonNull @NonNull
OsType osType; OsType osType;
@NonNull @NonNull
String osName; String osName;
@NonNull @NonNull
FilePath temp; FilePath temp;
} }

View file

@ -1,9 +1,10 @@
import com.fasterxml.jackson.databind.Module;
import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconInterface;
import io.xpipe.beacon.BeaconJacksonModule; import io.xpipe.beacon.BeaconJacksonModule;
import io.xpipe.beacon.api.*; import io.xpipe.beacon.api.*;
import io.xpipe.core.util.ModuleLayerLoader; import io.xpipe.core.util.ModuleLayerLoader;
import com.fasterxml.jackson.databind.Module;
open module io.xpipe.beacon { open module io.xpipe.beacon {
exports io.xpipe.beacon; exports io.xpipe.beacon;
exports io.xpipe.beacon.test; exports io.xpipe.beacon.test;

View file

@ -1,14 +1,5 @@
package io.xpipe.core.util; package io.xpipe.core.util;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.ArrayType;
import io.xpipe.core.dialog.BaseQueryElement; import io.xpipe.core.dialog.BaseQueryElement;
import io.xpipe.core.dialog.BusyElement; import io.xpipe.core.dialog.BusyElement;
import io.xpipe.core.dialog.ChoiceElement; import io.xpipe.core.dialog.ChoiceElement;
@ -20,6 +11,16 @@ import io.xpipe.core.store.FilePath;
import io.xpipe.core.store.LocalStore; import io.xpipe.core.store.LocalStore;
import io.xpipe.core.store.StorePath; import io.xpipe.core.store.StorePath;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.ArrayType;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.WildcardType; import java.lang.reflect.WildcardType;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -89,7 +90,8 @@ public class CoreJacksonModule extends SimpleModule {
@Override @Override
public StorePath deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { public StorePath deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JavaType javaType = JacksonMapper.getDefault().getTypeFactory().constructCollectionLikeType(List.class, String.class); JavaType javaType =
JacksonMapper.getDefault().getTypeFactory().constructCollectionLikeType(List.class, String.class);
List<String> list = JacksonMapper.getDefault().readValue(p, javaType); List<String> list = JacksonMapper.getDefault().readValue(p, javaType);
return new StorePath(list); return new StorePath(list);
} }

View file

@ -1,7 +1,8 @@
package io.xpipe.ext.base.service; package io.xpipe.ext.base.service;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.core.store.NetworkTunnelStore; import io.xpipe.core.store.NetworkTunnelStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;

View file

@ -71,7 +71,8 @@ open module io.xpipe.ext.base {
BrowseStoreAction, BrowseStoreAction,
ScanStoreAction; ScanStoreAction;
provides DataStoreProvider with provides DataStoreProvider with
FixedServiceGroupStoreProvider, CustomServiceGroupStoreProvider, FixedServiceGroupStoreProvider,
CustomServiceGroupStoreProvider,
CustomServiceStoreProvider, CustomServiceStoreProvider,
MappedServiceStoreProvider, MappedServiceStoreProvider,
FixedServiceStoreProvider, FixedServiceStoreProvider,