diff --git a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java index e3d0a31e1..68fcc7fd6 100644 --- a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java +++ b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java @@ -36,7 +36,7 @@ public class AppBeaconServer { private String localAuthSecret; private String notFoundHtml; - private Map resources = new HashMap<>(); + private final Map resources = new HashMap<>(); static { int port; diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java index a737fffc8..ce713fe73 100644 --- a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java @@ -77,15 +77,16 @@ public class BeaconRequestHandler implements HttpHandler { } try { - if (response != null) { - TrackEvent.trace("Sending response:\n" + object); - var tree = JacksonMapper.getDefault().valueToTree(response); - TrackEvent.trace("Sending raw response:\n" + tree.toPrettyString()); - var bytes = tree.toPrettyString().getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(200, bytes.length); - try (OutputStream os = exchange.getResponseBody()) { - os.write(bytes); - } + var emptyResponseClass = beaconInterface.getResponseClass().getDeclaredFields().length == 0; + if (!emptyResponseClass && response != null) { + TrackEvent.trace("Sending response:\n" + object); + var tree = JacksonMapper.getDefault().valueToTree(response); + TrackEvent.trace("Sending raw response:\n" + tree.toPrettyString()); + var bytes = tree.toPrettyString().getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } } else { exchange.sendResponseHeaders(200, -1); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index b12f80c93..6cd55eba6 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -310,6 +310,11 @@ public abstract class StoreEntryComp extends SimpleComp { browse.setOnAction( event -> DesktopHelper.browsePathLocal(wrapper.getEntry().getDirectory())); contextMenu.getItems().add(browse); + + var copyId = new MenuItem(AppI18n.get("copyId"), new FontIcon("mdi2c-content-copy")); + copyId.setOnAction( + event -> ClipboardHelper.copyText(wrapper.getEntry().getUuid().toString())); + contextMenu.getItems().add(copyId); } if (DataStorage.get().isRootEntry(wrapper.getEntry())) { diff --git a/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java b/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java index 62431effe..f88ef002b 100644 --- a/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java @@ -2,6 +2,7 @@ package io.xpipe.app.prefs; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.core.AppProperties; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.DesktopHelper; @@ -19,8 +20,10 @@ public class SyncCategory extends AppPrefsCategory { var builder = new OptionsBuilder(); builder.addTitle("sync") .sub(new OptionsBuilder() - .nameAndDescription("enableGitStorage") + .name("enableGitStorage") + .description(AppProperties.get().isStaging() ? "enableGitStoragePtbDisabled" : "enableGitStorage") .addToggle(prefs.enableGitStorage) + .disable(AppProperties.get().isStaging()) .nameAndDescription("storageGitRemote") .addString(prefs.storageGitRemote, true) .disable(prefs.enableGitStorage.not()) diff --git a/app/src/main/java/io/xpipe/app/storage/ImpersistentStorage.java b/app/src/main/java/io/xpipe/app/storage/ImpersistentStorage.java index e352def66..8d11a11d0 100644 --- a/app/src/main/java/io/xpipe/app/storage/ImpersistentStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/ImpersistentStorage.java @@ -1,13 +1,8 @@ package io.xpipe.app.storage; import io.xpipe.app.comp.store.StoreSortMode; -import io.xpipe.app.issue.ErrorEvent; -import io.xpipe.app.issue.TrackEvent; import io.xpipe.core.store.LocalStore; -import org.apache.commons.io.FileUtils; - -import java.nio.file.Files; import java.time.Instant; import java.util.UUID; @@ -20,22 +15,17 @@ public class ImpersistentStorage extends DataStorage { @Override public void load() { - var storesDir = getStoresDir(); - var categoriesDir = getCategoriesDir(); - { var cat = DataStoreCategory.createNew(null, ALL_CONNECTIONS_CATEGORY_UUID, "All connections"); - cat.setDirectory(categoriesDir.resolve(ALL_CONNECTIONS_CATEGORY_UUID.toString())); storeCategories.add(cat); } { var cat = DataStoreCategory.createNew(null, ALL_SCRIPTS_CATEGORY_UUID, "All scripts"); - cat.setDirectory(categoriesDir.resolve(ALL_SCRIPTS_CATEGORY_UUID.toString())); storeCategories.add(cat); } { var cat = new DataStoreCategory( - categoriesDir.resolve(DEFAULT_CATEGORY_UUID.toString()), + null, DEFAULT_CATEGORY_UUID, "Default", Instant.now(), @@ -50,7 +40,6 @@ public class ImpersistentStorage extends DataStorage { var e = DataStoreEntry.createNew( LOCAL_ID, DataStorage.DEFAULT_CATEGORY_UUID, "Local Machine", new LocalStore()); - e.setDirectory(getStoresDir().resolve(LOCAL_ID.toString())); e.setConfiguration( StorageElement.Configuration.builder().deletable(false).build()); storeEntries.put(e, e); @@ -58,18 +47,7 @@ public class ImpersistentStorage extends DataStorage { } @Override - public synchronized void save(boolean dispose) { - var storesDir = getStoresDir(); - - TrackEvent.info("Storage persistence is disabled. Deleting storage contents ..."); - try { - if (Files.exists(storesDir)) { - FileUtils.cleanDirectory(storesDir.toFile()); - } - } catch (Exception ex) { - ErrorEvent.fromThrowable(ex).build().handle(); - } - } + public synchronized void save(boolean dispose) {} @Override public boolean supportsSharing() { diff --git a/beacon/README.md b/beacon/README.md index 54ed3fc19..5563a5fbb 100644 --- a/beacon/README.md +++ b/beacon/README.md @@ -4,36 +4,27 @@ ## XPipe Beacon The XPipe beacon component is responsible for handling all communications between the XPipe daemon -and the various programming language APIs and the CLI. It provides an API that supports all kinds +and the APIs and the CLI. It provides an API that supports all kinds of different operations. ### Inner Workings -- The underlying inter-process communication is realized through - TCP sockets on port `21721` on Windows and `21723` on Linux/macOS. +- The underlying communication is realized through an HTTP server on port `21721` - The data structures and exchange protocols are specified in the - [io.xpipe.beacon.exchange package](src/main/java/io/xpipe/beacon/exchange). + [io.xpipe.beacon.api package](src/main/java/io/xpipe/beacon/api). - Every exchange is initiated from the outside by sending a request message to the XPipe daemon. The daemon then always sends a response message. -- The header information of a message is formatted in the json format. +- The body of a message is formatted in the json format. As a result, all data structures exchanged must be serializable/deserializable with jackson. -- Both the requests and responses can optionally include content in a body. - A body is initiated with two new lines (`\n`). - -- The body is split into segments of max length `65536`. - Each segment is preceded by four bytes that specify the length of the next segment. - In case the next segment has a length of less than `65536` bytes, we know that the end of the body has been reached. - This way the socket communication can handle payloads of unknown length. - ## Configuration #### Custom port -The default port can be changed by passing the property `io.xpipe.beacon.port=` to both the daemon and APIs. +The default port can be changed by passing the property `io.xpipe.beacon.port=` to the daemon or changing it in the settings menu. Note that if both sides do not have the same port setting, they won't be able to reach each other. #### Custom launch command diff --git a/build.gradle b/build.gradle index 8baa20c67..2e2690578 100644 --- a/build.gradle +++ b/build.gradle @@ -88,7 +88,7 @@ project.ext { arch = getArchName() privateExtensions = file("$rootDir/private_extensions.txt").exists() ? file("$rootDir/private_extensions.txt").readLines() : [] isFullRelease = System.getenv('RELEASE') != null && Boolean.parseBoolean(System.getenv('RELEASE')) - isStage = System.getenv('STAGE') != null && Boolean.parseBoolean(System.getenv('STAGE')) + isStage = true rawVersion = file('version').text.trim() versionString = rawVersion + (isFullRelease || isStage ? '' : '-SNAPSHOT') versionReleaseNumber = rawVersion.split('-').length == 2 ? Integer.parseInt(rawVersion.split('-')[1]) : 1 diff --git a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java index 72e7f5add..074e85a88 100644 --- a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java +++ b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java @@ -22,7 +22,7 @@ public class XPipeInstallation { .orElse(false); public static int getDefaultBeaconPort() { - var offset = isStaging() ? 1 : 0; + var offset = isStaging() ? 2 : 0; return 21721 + offset; } diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index df834481e..8399271e2 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -478,3 +478,4 @@ httpApi=HTTP API isOnlySupportedLimit=is only supported with a professional license when having more than $COUNT$ connections areOnlySupportedLimit=are only supported with a professional license when having more than $COUNT$ connections enabled=Enabled +enableGitStoragePtbDisabled=Git synchronization is disabled for public test builds to prevent usage with regular release git repositories and to discourage using a PTB build as your daily driver. diff --git a/openapi.yaml b/openapi.yaml index 27249a543..3a380f408 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -26,7 +26,7 @@ externalDocs: description: XPipe - Plans and pricing url: https://xpipe.io/pricing servers: - - url: http://localhost:21721 + - url: http://localhost:21723 description: XPipe Daemon API paths: /handshake: diff --git a/version b/version index 2f52450b3..a3a9b449c 100644 --- a/version +++ b/version @@ -1 +1 @@ -10.0 +10.0-1