Api fixes, order fixes [stage]

This commit is contained in:
crschnick 2024-06-18 17:32:10 +00:00
parent adb621dab4
commit 20093becf3
40 changed files with 273 additions and 176 deletions

View file

@ -118,7 +118,10 @@ public class BeaconRequestHandler<T> implements HttpHandler {
exchange.sendResponseHeaders(200, -1);
}
} catch (IOException ioException) {
ErrorEvent.fromThrowable(ioException).omit().expected().handle();
// The exchange implementation might have already sent a response manually
if (!"headers already sent".equals(ioException.getMessage())) {
ErrorEvent.fromThrowable(ioException).omit().expected().handle();
}
} catch (Throwable other) {
ErrorEvent.fromThrowable(other).handle();
writeError(exchange, new BeaconServerErrorResponse(other), 500);

View file

@ -25,7 +25,7 @@ public class AskpassExchangeImpl extends AskpassExchange {
? SecretManager.getProgress(msg.getRequest(), msg.getSecretId())
: SecretManager.getProgress(msg.getRequest());
if (found.isEmpty()) {
throw new BeaconClientException("No password was provided");
throw new BeaconClientException("Unknown askpass request");
}
var p = found.get();

View file

@ -0,0 +1,26 @@
package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.beacon.api.FsReadExchange;
import io.xpipe.core.store.ConnectionFileSystem;
import lombok.SneakyThrows;
public class FsReadExchangeImpl extends FsReadExchange {
@Override
@SneakyThrows
public Object handle(HttpExchange exchange, Request msg) {
var shell = AppBeaconServer.get().getCache().getShellSession(msg.getConnection());
var fs = new ConnectionFileSystem(shell.getControl());
byte[] bytes;
try (var in = fs.openInput(msg.getPath().toString())) {
bytes = in.readAllBytes();
}
exchange.sendResponseHeaders(200, bytes.length);
try (var out = exchange.getResponseBody()) {
out.write(bytes);
}
return Response.builder().build();
}
}

View file

@ -76,7 +76,7 @@ public final class BrowserBookmarkComp extends SimpleComp {
var section = new StoreSectionMiniComp(
StoreSection.createTopLevel(
StoreViewState.get().getAllEntries(), this::filter, filterText, selectedCategory),
StoreViewState.get().getAllEntries(), this::filter, filterText, selectedCategory, StoreViewState.get().getEntriesListUpdateObservable()),
augment,
entryWrapper -> action.accept(entryWrapper, busy),
true);

View file

@ -18,6 +18,7 @@ import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreColor;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.*;
@ -369,57 +370,41 @@ public abstract class StoreEntryComp extends SimpleComp {
});
contextMenu.getItems().add(move);
}
var order = new Menu(AppI18n.get("order"), new FontIcon("mdal-bookmarks"));
var noOrder = new MenuItem(AppI18n.get("none"), new FontIcon("mdi2r-reorder-horizontal"));
noOrder.setOnAction(event -> {
DataStorage.get().orderBefore(wrapper.getEntry(), null);
event.consume();
});
if (wrapper.getEntry().getOrderBefore() == null) {
noOrder.setDisable(true);
}
order.getItems().add(noOrder);
order.getItems().add(new SeparatorMenuItem());
var stick = new MenuItem(AppI18n.get("stickToTop"), new FontIcon("mdi2o-order-bool-descending"));
stick.setOnAction(event -> {
DataStorage.get().orderBefore(wrapper.getEntry(), wrapper.getEntry());
event.consume();
});
if (wrapper.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) {
stick.setDisable(true);
}
order.getItems().add(stick);
order.getItems().add(new SeparatorMenuItem());
var desc = new MenuItem(AppI18n.get("orderAheadOf"), new FontIcon("mdi2o-order-bool-descending-variant"));
desc.setDisable(true);
order.getItems().add(desc);
var section = StoreViewState.get().getParentSectionForWrapper(wrapper);
if (section.isPresent()) {
section.get().getAllChildren().getList().forEach(other -> {
var ow = other.getWrapper();
var op = ow.getEntry().getProvider();
MenuItem m = new MenuItem(
ow.getName().getValue(),
op != null
? PrettyImageHelper.ofFixedSizeSquare(
op.getDisplayIconFileName(
ow.getEntry().getStore()),
16)
.createRegion()
: null);
if (other.getWrapper().equals(wrapper)
|| ow.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) {
m.setDisable(true);
}
m.setOnAction(event -> {
wrapper.orderBefore(ow);
event.consume();
});
order.getItems().add(m);
{
var order = new Menu(AppI18n.get("order"), new FontIcon("mdal-bookmarks"));
var noOrder = new MenuItem(AppI18n.get("none"), new FontIcon("mdi2r-reorder-horizontal"));
noOrder.setOnAction(event -> {
wrapper.setOrder(null);
event.consume();
});
if (wrapper.getEntry().getExplicitOrder() == null) {
noOrder.setDisable(true);
}
order.getItems().add(noOrder);
order.getItems().add(new SeparatorMenuItem());
var top = new MenuItem(AppI18n.get("stickToTop"), new FontIcon("mdi2o-order-bool-descending"));
top.setOnAction(event -> {
wrapper.setOrder(DataStoreEntry.Order.TOP);
event.consume();
});
if (DataStoreEntry.Order.TOP.equals(wrapper.getEntry().getExplicitOrder())) {
top.setDisable(true);
}
order.getItems().add(top);
var bottom = new MenuItem(AppI18n.get("stickToBottom"), new FontIcon("mdi2o-order-bool-ascending"));
bottom.setOnAction(event -> {
wrapper.setOrder(DataStoreEntry.Order.BOTTOM);
event.consume();
});
if (DataStoreEntry.Order.BOTTOM.equals(wrapper.getEntry().getExplicitOrder())) {
bottom.setDisable(true);
}
order.getItems().add(bottom);
contextMenu.getItems().add(order);
}
contextMenu.getItems().add(order);
contextMenu.getItems().add(new SeparatorMenuItem());

View file

@ -68,9 +68,9 @@ public class StoreEntryWrapper {
});
}
public void orderBefore(StoreEntryWrapper other) {
public void setOrder(DataStoreEntry.Order order) {
ThreadHelper.runAsync(() -> {
DataStorage.get().orderBefore(getEntry(), other.getEntry());
DataStorage.get().setOrder(getEntry(), order);
});
}

View file

@ -10,6 +10,7 @@ import io.xpipe.app.storage.DataStoreEntry;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableIntegerValue;
import javafx.beans.value.ObservableStringValue;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
@ -61,7 +62,8 @@ public class StoreSection {
}
private static DerivedObservableList<StoreSection> sorted(
DerivedObservableList<StoreSection> list, ObservableValue<StoreCategoryWrapper> category) {
DerivedObservableList<StoreSection> list, ObservableValue<StoreCategoryWrapper> category,
ObservableIntegerValue updateObservable) {
if (category == null) {
return list;
}
@ -69,36 +71,15 @@ public class StoreSection {
var explicitOrderComp = Comparator.<StoreSection>comparingInt(new ToIntFunction<>() {
@Override
public int applyAsInt(StoreSection value) {
var explicit = value.getWrapper().getEntry().getOrderBefore();
var explicit = value.getWrapper().getEntry().getExplicitOrder();
if (explicit == null) {
return 1;
}
if (explicit.equals(value.getWrapper().getEntry().getUuid())) {
return Integer.MIN_VALUE;
}
return -count(value.getWrapper(), new HashSet<>());
}
private int count(StoreEntryWrapper wrapper, Set<StoreEntryWrapper> seen) {
if (seen.contains(wrapper)) {
// Loop!
return 0;
}
seen.add(wrapper);
var found = list.getList().stream()
.filter(section -> section.getWrapper()
.getEntry()
.getUuid()
.equals(wrapper.getEntry().getOrderBefore()))
.findFirst();
if (found.isPresent()) {
return count(found.get().getWrapper(), seen);
} else {
return seen.size();
}
return switch (explicit) {
case TOP -> -1;
case BOTTOM -> 1;
};
}
});
var usableComp = Comparator.<StoreSection>comparingInt(
@ -118,23 +99,25 @@ public class StoreSection {
}
},
mappedSortMode,
StoreViewState.get().getEntriesOrderChangeObservable());
updateObservable);
}
public static StoreSection createTopLevel(
DerivedObservableList<StoreEntryWrapper> all,
Predicate<StoreEntryWrapper> entryFilter,
ObservableStringValue filterString,
ObservableValue<StoreCategoryWrapper> category) {
ObservableValue<StoreCategoryWrapper> category,
ObservableIntegerValue updateObservable
) {
var topLevel = all.filtered(
section -> {
return DataStorage.get().isRootEntry(section.getEntry());
},
category,
StoreViewState.get().getEntriesListChangeObservable());
updateObservable);
var cached = topLevel.mapped(
storeEntryWrapper -> create(List.of(), storeEntryWrapper, 1, all, entryFilter, filterString, category));
var ordered = sorted(cached, category);
storeEntryWrapper -> create(List.of(), storeEntryWrapper, 1, all, entryFilter, filterString, category, updateObservable));
var ordered = sorted(cached, category, updateObservable);
var shown = ordered.filtered(
section -> {
// matches filter
@ -160,7 +143,8 @@ public class StoreSection {
DerivedObservableList<StoreEntryWrapper> all,
Predicate<StoreEntryWrapper> entryFilter,
ObservableStringValue filterString,
ObservableValue<StoreCategoryWrapper> category) {
ObservableValue<StoreCategoryWrapper> category,
ObservableIntegerValue updateObservable) {
if (e.getEntry().getValidity() == DataStoreEntry.Validity.LOAD_FAILED) {
return new StoreSection(
e,
@ -186,11 +170,11 @@ public class StoreSection {
},
e.getPersistentState(),
e.getCache(),
StoreViewState.get().getEntriesListChangeObservable());
updateObservable);
var l = new ArrayList<>(parents);
l.add(e);
var cached = allChildren.mapped(c -> create(l, c, depth + 1, all, entryFilter, filterString, category));
var ordered = sorted(cached, category);
var cached = allChildren.mapped(c -> create(l, c, depth + 1, all, entryFilter, filterString, category, updateObservable));
var ordered = sorted(cached, category, updateObservable);
var filtered = ordered.filtered(
section -> {
// matches filter

View file

@ -34,10 +34,7 @@ public class StoreViewState {
new DerivedObservableList<>(FXCollections.observableList(new CopyOnWriteArrayList<>()), true);
@Getter
private final IntegerProperty entriesOrderChangeObservable = new SimpleIntegerProperty();
@Getter
private final IntegerProperty entriesListChangeObservable = new SimpleIntegerProperty();
private final IntegerProperty entriesListUpdateObservable = new SimpleIntegerProperty();
@Getter
private final Property<StoreCategoryWrapper> activeCategory = new SimpleObjectProperty<>();
@ -86,7 +83,7 @@ public class StoreViewState {
private void initSections() {
try {
currentTopLevelSection =
StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory);
StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory, entriesListUpdateObservable);
} catch (Exception exception) {
currentTopLevelSection = new StoreSection(
null,
@ -124,15 +121,9 @@ public class StoreViewState {
.orElseThrow()));
}
public void toggleStoreOrderUpdate() {
PlatformThread.runLaterIfNeeded(() -> {
entriesOrderChangeObservable.set(entriesOrderChangeObservable.get() + 1);
});
}
public void toggleStoreListUpdate() {
PlatformThread.runLaterIfNeeded(() -> {
entriesListChangeObservable.set(entriesListChangeObservable.get() + 1);
entriesListUpdateObservable.set(entriesListUpdateObservable.get() + 1);
});
}
@ -152,13 +143,6 @@ public class StoreViewState {
// Watch out for synchronizing all calls to the entries and categories list!
DataStorage.get().addListener(new StorageListener() {
@Override
public void onStoreOrderUpdate() {
Platform.runLater(() -> {
toggleStoreOrderUpdate();
});
}
@Override
public void onStoreListUpdate() {
Platform.runLater(() -> {

View file

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

View file

@ -333,9 +333,9 @@ public abstract class DataStorage {
saveAsync();
}
public void orderBefore(DataStoreEntry entry, DataStoreEntry reference) {
entry.setOrderBefore(reference != null ? reference.getUuid() : null);
listeners.forEach(storageListener -> storageListener.onStoreOrderUpdate());
public void setOrder(DataStoreEntry entry, DataStoreEntry.Order order) {
entry.setExplicitOrder(order);
listeners.forEach(storageListener -> storageListener.onStoreListUpdate());
}
public boolean refreshChildren(DataStoreEntry e) {

View file

@ -73,7 +73,7 @@ public class DataStoreEntry extends StorageElement {
String notes;
@NonFinal
UUID orderBefore;
Order explicitOrder;
private DataStoreEntry(
Path directory,
@ -90,7 +90,8 @@ public class DataStoreEntry extends StorageElement {
boolean expanded,
DataStoreColor color,
String notes,
UUID orderBefore) {
Order explicitOrder
) {
super(directory, uuid, name, lastUsed, lastModified, dirty);
this.categoryUuid = categoryUuid;
this.store = DataStorageParser.storeFromNode(storeNode);
@ -99,7 +100,7 @@ public class DataStoreEntry extends StorageElement {
this.configuration = configuration;
this.expanded = expanded;
this.color = color;
this.orderBefore = orderBefore;
this.explicitOrder = explicitOrder;
this.provider = store != null
? DataStoreProviders.byStoreClass(store.getClass()).orElse(null)
: null;
@ -115,11 +116,12 @@ public class DataStoreEntry extends StorageElement {
Instant lastUsed,
Instant lastModified,
DataStore store,
UUID orderBefore) {
Order explicitOrder
) {
super(directory, uuid, name, lastUsed, lastModified, false);
this.categoryUuid = categoryUuid;
this.store = store;
this.orderBefore = orderBefore;
this.explicitOrder = explicitOrder;
this.storeNode = null;
this.validity = Validity.INCOMPLETE;
this.configuration = Configuration.defaultConfiguration();
@ -186,7 +188,7 @@ public class DataStoreEntry extends StorageElement {
boolean expanded,
DataStoreColor color,
String notes,
UUID orderBeforeEntry) {
Order order) {
return new DataStoreEntry(
directory,
uuid,
@ -202,7 +204,7 @@ public class DataStoreEntry extends StorageElement {
expanded,
color,
notes,
orderBeforeEntry);
order);
}
public static Optional<DataStoreEntry> fromDirectory(Path dir) throws Exception {
@ -237,10 +239,10 @@ public class DataStoreEntry extends StorageElement {
.map(jsonNode -> jsonNode.textValue())
.map(Instant::parse)
.orElse(Instant.EPOCH);
var order = Optional.ofNullable(stateJson.get("orderBefore"))
var order = Optional.ofNullable(stateJson.get("order"))
.map(node -> {
try {
return mapper.treeToValue(node, UUID.class);
return mapper.treeToValue(node, Order.class);
} catch (JsonProcessingException e) {
return null;
}
@ -299,9 +301,9 @@ public class DataStoreEntry extends StorageElement {
order));
}
public void setOrderBefore(UUID uuid) {
var changed = !Objects.equals(orderBefore, uuid);
this.orderBefore = uuid;
public void setExplicitOrder(Order uuid) {
var changed = !Objects.equals(explicitOrder, uuid);
this.explicitOrder = uuid;
if (changed) {
notifyUpdate(false, true);
}
@ -415,7 +417,7 @@ public class DataStoreEntry extends StorageElement {
stateObj.set("persistentState", storePersistentStateNode);
obj.set("configuration", mapper.valueToTree(configuration));
stateObj.put("expanded", expanded);
stateObj.put("orderBefore", orderBefore != null ? orderBefore.toString() : null);
stateObj.put("orderBefore", explicitOrder != null ? explicitOrder.toString() : null);
var entryString = mapper.writeValueAsString(obj);
var stateString = mapper.writeValueAsString(stateObj);
@ -601,4 +603,13 @@ public class DataStoreEntry extends StorageElement {
this.isUsable = isUsable;
}
}
@Getter
public enum Order {
@JsonProperty("top")
TOP,
@JsonProperty("bottom")
BOTTOM;
}
}

View file

@ -2,8 +2,6 @@ package io.xpipe.app.storage;
public interface StorageListener {
void onStoreOrderUpdate();
void onStoreListUpdate();
void onStoreAdd(DataStoreEntry... entry);

View file

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

View file

@ -0,0 +1,33 @@
package io.xpipe.beacon.api;
import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.store.FilePath;
import lombok.Builder;
import lombok.NonNull;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.util.UUID;
public class FsReadExchange extends BeaconInterface<FsReadExchange.Request> {
@Override
public String getPath() {
return "/fs/read";
}
@Jacksonized
@Builder
@Value
public static class Request {
@NonNull
UUID connection;
@NonNull
FilePath path;
}
@Jacksonized
@Builder
@Value
public static class Response {}
}

View file

@ -1,10 +1,9 @@
import com.fasterxml.jackson.databind.Module;
import io.xpipe.beacon.BeaconInterface;
import io.xpipe.beacon.BeaconJacksonModule;
import io.xpipe.beacon.api.*;
import io.xpipe.core.util.ModuleLayerLoader;
import com.fasterxml.jackson.databind.Module;
open module io.xpipe.beacon {
exports io.xpipe.beacon;
exports io.xpipe.beacon.test;
@ -40,5 +39,9 @@ open module io.xpipe.beacon {
AskpassExchange,
TerminalWaitExchange,
TerminalLaunchExchange,
FsReadExchange,
FsBlobExchange,
FsWriteExchange,
FsScriptExchange,
DaemonVersionExchange;
}

View file

@ -460,11 +460,10 @@ notes=Bemærkninger
addNotes=Tilføj noter
order=Bestille ...
stickToTop=Hold dig på toppen
stickToBottom=Hold på bunden
orderAheadOf=Bestil på forhånd ...
httpServer=HTTP-server
httpServerConfiguration=Konfiguration af HTTP-server
httpServerPort=Port
httpServerPortDescription=Den port, som HTTP-serveren vil lytte på.\n\nBemærk, at hvis du ændrer dette, skal alle andre programmer, der interagerer med serveren, også konfigureres til at bruge den nye port.\n\nKræver en genstart for at gælde.
apiKey=API-nøgle
apiKeyDescription=API-nøglen til godkendelse af XPipe-dæmonens API-anmodninger. Se den generelle API-dokumentation for at få flere oplysninger om, hvordan du godkender.\n\nKræver en genstart for at blive anvendt.
disableApiAuthentication=Deaktiver API-godkendelse
@ -479,3 +478,4 @@ isOnlySupportedLimit=understøttes kun med en professionel licens, når man har
areOnlySupportedLimit=understøttes kun med en professionel licens, når man har mere end $COUNT$ forbindelser
enabled=Aktiveret
enableGitStoragePtbDisabled=Git-synkronisering er deaktiveret for offentlige test-builds for at forhindre brug med almindelige release-git-lagre og for at modvirke, at man bruger en PTB-build som sin daglige driver.
copyId=Kopi ID

View file

@ -454,11 +454,10 @@ notes=Anmerkungen
addNotes=Notizen hinzufügen
order=Bestellen ...
stickToTop=Oben bleiben
stickToBottom=Auf dem Boden bleiben
orderAheadOf=Vorbestellen ...
httpServer=HTTP-Server
httpServerConfiguration=HTTP-Server-Konfiguration
httpServerPort=Port
httpServerPortDescription=Der Port, auf dem der HTTP-Server lauschen wird.\n\nWenn du diesen Wert änderst, müssen alle anderen Anwendungen, die mit dem Server interagieren, so konfiguriert werden, dass sie ebenfalls den neuen Port verwenden.\n\nZur Anwendung ist ein Neustart erforderlich.
apiKey=API-Schlüssel
apiKeyDescription=Der API-Schlüssel zur Authentifizierung von XPipe Daemon API-Anfragen. Weitere Informationen zur Authentifizierung findest du in der allgemeinen API-Dokumentation.\n\nErfordert einen Neustart zur Anwendung.
disableApiAuthentication=API-Authentifizierung deaktivieren
@ -473,3 +472,4 @@ isOnlySupportedLimit=wird nur mit einer professionellen Lizenz unterstützt, wen
areOnlySupportedLimit=werden nur mit einer professionellen Lizenz unterstützt, wenn mehr als $COUNT$ Verbindungen bestehen
enabled=Aktiviert
enableGitStoragePtbDisabled=Die Git-Synchronisierung ist für öffentliche Test-Builds deaktiviert, um die Verwendung mit regulären Git-Repositories zu verhindern und um davon abzuraten, einen PTB-Build als täglichen Treiber zu verwenden.
copyId=ID kopieren

View file

@ -458,6 +458,7 @@ addNotes=Add notes
#context: verb
order=Order ...
stickToTop=Keep on top
stickToBottom=Keep on bottom
orderAheadOf=Order ahead of ...
httpServer=HTTP server
httpServerConfiguration=HTTP server configuration

View file

@ -441,11 +441,10 @@ notes=Notas
addNotes=Añadir notas
order=Ordenar ...
stickToTop=Mantener arriba
stickToBottom=Mantener en la parte inferior
orderAheadOf=Haz tu pedido antes de ...
httpServer=Servidor HTTP
httpServerConfiguration=Configuración del servidor HTTP
httpServerPort=Puerto
httpServerPortDescription=El puerto en el que escuchará el servidor HTTP.\n\nTen en cuenta que si cambias esto, cualquier otra aplicación que interactúe con el servidor deberá configurarse para utilizar también el nuevo puerto.\n\nRequiere un reinicio para aplicarse.
apiKey=Clave API
apiKeyDescription=La clave API para autenticar las peticiones API del demonio XPipe. Para más información sobre cómo autenticarse, consulta la documentación general de la API.\n\nRequiere un reinicio para aplicarse.
disableApiAuthentication=Desactivar la autenticación de la API
@ -460,3 +459,4 @@ isOnlySupportedLimit=sólo es compatible con una licencia profesional cuando tie
areOnlySupportedLimit=sólo son compatibles con una licencia profesional cuando tienen más de $COUNT$ conexiones
enabled=Activado
enableGitStoragePtbDisabled=La sincronización Git está desactivada para las compilaciones públicas de prueba, para evitar que se utilicen con los repositorios git de publicación regular y para desalentar el uso de una compilación PTB como tu conductor diario.
copyId=ID de copia

View file

@ -441,11 +441,10 @@ notes=Notes
addNotes=Ajouter des notes
order=Commander...
stickToTop=Garde le dessus
stickToBottom=Garde en bas
orderAheadOf=Commande en avance...
httpServer=Serveur HTTP
httpServerConfiguration=Configuration du serveur HTTP
httpServerPort=Port
httpServerPortDescription=Le port sur lequel le serveur HTTP écoutera.\n\nNote que si tu modifies ce paramètre, toutes les autres applications qui interagissent avec le serveur doivent être configurées pour utiliser également le nouveau port.\n\nIl faut redémarrer l'ordinateur pour l'appliquer.
apiKey=Clé API
apiKeyDescription=La clé API pour authentifier les demandes API du démon XPipe. Pour plus d'informations sur la manière de s'authentifier, voir la documentation générale de l'API.\n\nNécessite un redémarrage pour être appliquée.
disableApiAuthentication=Désactiver l'authentification de l'API
@ -460,3 +459,4 @@ isOnlySupportedLimit=n'est pris en charge qu'avec une licence professionnelle lo
areOnlySupportedLimit=ne sont pris en charge qu'avec une licence professionnelle lorsqu'il y a plus de $COUNT$ connexions
enabled=Activé
enableGitStoragePtbDisabled=La synchronisation Git est désactivée pour les versions de test publiques afin d'éviter toute utilisation avec les dépôts git des versions régulières et de décourager l'utilisation d'une version PTB comme conducteur quotidien.
copyId=ID de copie

View file

@ -441,11 +441,10 @@ notes=Note
addNotes=Aggiungi note
order=Ordinare ...
stickToTop=Continua a essere in cima
stickToBottom=Tieni sul fondo
orderAheadOf=Ordina prima di ...
httpServer=Server HTTP
httpServerConfiguration=Configurazione del server HTTP
httpServerPort=Porta
httpServerPortDescription=La porta su cui il server HTTP si metterà in ascolto.\n\nSe la modifichi, tutte le altre applicazioni che interagiscono con il server devono essere configurate per utilizzare la nuova porta.\n\nRichiede un riavvio per essere applicata.
apiKey=Chiave API
apiKeyDescription=La chiave API per autenticare le richieste API del demone XPipe. Per ulteriori informazioni sulle modalità di autenticazione, consulta la documentazione generale dell'API.\n\nRichiede un riavvio per essere applicata.
disableApiAuthentication=Disabilita l'autenticazione API
@ -460,3 +459,4 @@ isOnlySupportedLimit=è supportato solo con una licenza professionale quando ci
areOnlySupportedLimit=sono supportati solo con una licenza professionale quando ci sono più di $COUNT$ connessioni
enabled=Abilitato
enableGitStoragePtbDisabled=La sincronizzazione Git è disabilitata per le build di test pubbliche per evitare l'uso con i repository git di rilascio regolari e per scoraggiare l'uso di una build PTB come guida quotidiana.
copyId=Copia ID

View file

@ -441,11 +441,10 @@ notes=備考
addNotes=メモを追加する
order=注文する
stickToTop=トップをキープする
stickToBottom=底を保つ
orderAheadOf=先に注文する
httpServer=HTTPサーバー
httpServerConfiguration=HTTPサーバーの設定
httpServerPort=ポート
httpServerPortDescription=HTTPサーバーがリッスンするポート。\n\nこれを変更すると、サーバーとやりとりする他のアプリケーションも新しいポートを使うように設定する必要があることに注意。\n\n適用するには再起動が必要である。
apiKey=APIキー
apiKeyDescription=XPipeデーモンAPIリクエストを認証するためのAPIキー。認証方法の詳細については、一般的なAPIドキュメントを参照のこと。\n\n適用には再起動が必要。
disableApiAuthentication=API認証を無効にする
@ -460,3 +459,4 @@ isOnlySupportedLimit=は、$COUNT$ を超える接続がある場合、プロフ
areOnlySupportedLimit=$COUNT$ 以上の接続がある場合、プロフェッショナルライセンスでのみサポートされる。
enabled=有効にする
enableGitStoragePtbDisabled=Gitの同期をパブリックテストビルドでは無効にしているのは、通常のリリース用gitリポジトリとの使い回しを防ぎ、PTBビルドをデイリードライバーとして使わないようにするためだ。
copyId=コピーID

View file

@ -441,11 +441,10 @@ notes=Opmerkingen
addNotes=Opmerkingen toevoegen
order=Bestellen ...
stickToTop=Bovenaan houden
stickToBottom=Onderaan houden
orderAheadOf=Vooruitbestellen ...
httpServer=HTTP-server
httpServerConfiguration=HTTP-server configuratie
httpServerPort=Poort
httpServerPortDescription=De poort waarop de HTTP-server zal luisteren.\n\nMerk op dat als je dit verandert, andere applicaties die communiceren met de server ook geconfigureerd moeten worden om de nieuwe poort te gebruiken.\n\nVereist een herstart om toe te passen.
apiKey=API-sleutel
apiKeyDescription=De API sleutel om XPipe daemon API verzoeken te authenticeren. Voor meer informatie over hoe te authenticeren, zie de algemene API documentatie.\n\nVereist een herstart om toe te passen.
disableApiAuthentication=API-authenticatie uitschakelen
@ -460,3 +459,4 @@ isOnlySupportedLimit=wordt alleen ondersteund met een professionele licentie bij
areOnlySupportedLimit=worden alleen ondersteund met een professionele licentie bij meer dan $COUNT$ verbindingen
enabled=Ingeschakeld
enableGitStoragePtbDisabled=Git synchronisatie is uitgeschakeld voor publieke test builds om gebruik met reguliere release git repositories te voorkomen en om het gebruik van een PTB build als je dagelijkse driver te ontmoedigen.
copyId=ID kopiëren

View file

@ -441,11 +441,10 @@ notes=Nota
addNotes=Adiciona notas
order=Encomenda ...
stickToTop=Mantém-te no topo
stickToBottom=Mantém na parte inferior
orderAheadOf=Encomenda antes de ...
httpServer=Servidor HTTP
httpServerConfiguration=Configuração do servidor HTTP
httpServerPort=Porta
httpServerPortDescription=A porta em que o servidor HTTP irá escutar.\n\nTem em atenção que, se alterares isto, quaisquer outras aplicações que interajam com o servidor têm de ser configuradas para utilizar também a nova porta.\n\nRequer uma reinicialização para ser aplicado.
apiKey=Chave API
apiKeyDescription=A chave da API para autenticar os pedidos de API do daemon XPipe. Para mais informações sobre como autenticar, vê a documentação geral da API.\n\nRequer um reinício para ser aplicado.
disableApiAuthentication=Desativar a autenticação da API
@ -460,3 +459,4 @@ isOnlySupportedLimit=só é suportado com uma licença profissional se tiver mai
areOnlySupportedLimit=só são suportados com uma licença profissional quando têm mais de $COUNT$ ligações
enabled=Ativado
enableGitStoragePtbDisabled=A sincronização do Git está desactivada para compilações de teste públicas para evitar a utilização com repositórios git de lançamento regulares e para desencorajar a utilização de uma compilação PTB como o teu condutor diário.
copyId=ID de cópia

View file

@ -441,11 +441,10 @@ notes=Заметки
addNotes=Добавляй заметки
order=Заказать ...
stickToTop=Держись на высоте
stickToBottom=Держать на дне
orderAheadOf=Заказать заранее ...
httpServer=HTTP-сервер
httpServerConfiguration=Конфигурация HTTP-сервера
httpServerPort=Порт
httpServerPortDescription=Порт, на котором будет прослушиваться HTTP-сервер.\n\nОбрати внимание, что если ты изменишь этот параметр, то все остальные приложения, которые взаимодействуют с сервером, тоже должны быть настроены на использование нового порта.\n\nТребуется перезагрузка для применения.
apiKey=Ключ API
apiKeyDescription=API-ключ для аутентификации API-запросов демона XPipe. Подробнее о том, как проходить аутентификацию, читай в общей документации по API.\n\nТребуется перезагрузка для применения.
disableApiAuthentication=Отключить аутентификацию API
@ -460,3 +459,4 @@ isOnlySupportedLimit=поддерживается только професси
areOnlySupportedLimit=поддерживаются только профессиональной лицензией при наличии более чем $COUNT$ соединений
enabled=Включено
enableGitStoragePtbDisabled=Git-синхронизация отключена для публичных тестовых сборок, чтобы предотвратить их использование с обычными релизными git-репозиториями и не допустить использования PTB-сборки в качестве ежедневного драйвера.
copyId=Идентификатор копии

View file

@ -442,11 +442,10 @@ notes=Notlar
addNotes=Notlar ekleyin
order=Sipariş ...
stickToTop=Zirvede kal
stickToBottom=Altta kal
orderAheadOf=Önceden sipariş verin ...
httpServer=HTTP sunucusu
httpServerConfiguration=HTTP sunucu yapılandırması
httpServerPort=Liman
httpServerPortDescription=HTTP sunucusunun dinleyeceği bağlantı noktası.\n\nBunu değiştirirseniz, sunucuyla etkileşime giren diğer uygulamaların da yeni bağlantı noktasını kullanacak şekilde yapılandırılması gerektiğini unutmayın.\n\nUygulamak için yeniden başlatma gerekir.
apiKey=API anahtarı
apiKeyDescription=XPipe daemon API isteklerinin kimliğini doğrulamak için API anahtarı. Kimlik doğrulamanın nasıl yapılacağı hakkında daha fazla bilgi için genel API belgelerine bakın.\n\nUygulamak için yeniden başlatma gerekir.
disableApiAuthentication=API kimlik doğrulamasını devre dışı bırakma
@ -461,3 +460,4 @@ isOnlySupportedLimit=yalnızca $COUNT$ adresinden daha fazla bağlantıya sahip
areOnlySupportedLimit=yalnızca $COUNT$ adresinden daha fazla bağlantıya sahip olunduğunda profesyonel lisans ile desteklenir
enabled=Etkin
enableGitStoragePtbDisabled=Git senkronizasyonu, normal sürüm git depoları ile kullanımı önlemek ve günlük sürücünüz olarak bir PTB derlemesini kullanmaktan vazgeçirmek için genel test derlemeleri için devre dışı bırakılmıştır.
copyId=Kopya Kimliği

View file

@ -441,11 +441,10 @@ notes=说明
addNotes=添加注释
order=订购 ...
stickToTop=保持在顶部
stickToBottom=保持在底部
orderAheadOf=提前订购...
httpServer=HTTP 服务器
httpServerConfiguration=HTTP 服务器配置
httpServerPort=端口
httpServerPortDescription=HTTP 服务器监听的端口。\n\n请注意如果更改端口则与服务器交互的任何其他应用程序也需要配置为使用新端口。\n\n需要重新启动才能应用。
apiKey=应用程序接口密钥
apiKeyDescription=用于验证 XPipe 守护进程 API 请求的 API 密钥。有关如何验证的更多信息,请参阅一般 API 文档。\n\n需要重新启动才能应用。
disableApiAuthentication=禁用 API 身份验证
@ -460,3 +459,4 @@ isOnlySupportedLimit=只有在连接数超过$COUNT$ 时才支持专业许可证
areOnlySupportedLimit=只有在连接数超过$COUNT$ 时才支持专业许可证
enabled=已启用
enableGitStoragePtbDisabled=公共测试版已禁用 Git 同步功能,以防止与常规发布版本的 git 仓库一起使用,并避免将公共测试版作为日常驱动程序使用。
copyId=复制 ID

View file

@ -152,8 +152,8 @@ serviceRemotePortDescription=Den port, som tjenesten kører på
serviceHost=Servicevært
serviceHostDescription=Den vært, som tjenesten kører på
openWebsite=Åben hjemmeside
serviceGroup.displayName=Service-gruppe
serviceGroup.displayDescription=Gruppér flere tjenester i én kategori
customServiceGroup.displayName=Service-gruppe
customServiceGroup.displayDescription=Gruppér flere tjenester i én kategori
initScript=Kører på shell init
shellScript=Gør script tilgængeligt under shell-session
fileScript=Gør det muligt at kalde et script med filargumenter i filbrowseren
@ -163,3 +163,5 @@ fixedServiceGroup.displayName=Service-gruppe
fixedServiceGroup.displayDescription=Liste over tilgængelige tjenester på et system
mappedService.displayName=Service
mappedService.displayDescription=Interagere med en tjeneste, der er eksponeret af en container
customService.displayName=Service
customService.displayDescription=Tilføj en brugerdefineret tjeneste til tunnel og åben

View file

@ -143,8 +143,8 @@ serviceRemotePortDescription=Der Port, auf dem der Dienst läuft
serviceHost=Diensthost
serviceHostDescription=Der Host, auf dem der Dienst läuft
openWebsite=Website öffnen
serviceGroup.displayName=Dienstgruppe
serviceGroup.displayDescription=Mehrere Dienste in einer Kategorie zusammenfassen
customServiceGroup.displayName=Dienstgruppe
customServiceGroup.displayDescription=Mehrere Dienste in einer Kategorie zusammenfassen
initScript=Auf der Shell init ausführen
shellScript=Skript während der Shell-Sitzung verfügbar machen
fileScript=Skriptaufruf mit Dateiargumenten im Dateibrowser zulassen
@ -154,3 +154,5 @@ fixedServiceGroup.displayName=Dienstgruppe
fixedServiceGroup.displayDescription=Liste der verfügbaren Dienste auf einem System
mappedService.displayName=Dienst
mappedService.displayDescription=Interaktion mit einem Dienst, der von einem Container angeboten wird
customService.displayName=Dienst
customService.displayDescription=Einen benutzerdefinierten Dienst zum Tunnel hinzufügen und öffnen

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=El puerto en el que se ejecuta el servicio
serviceHost=Host de servicio
serviceHostDescription=El host en el que se ejecuta el servicio
openWebsite=Abrir sitio web
serviceGroup.displayName=Grupo de servicios
serviceGroup.displayDescription=Agrupa varios servicios en una categoría
customServiceGroup.displayName=Grupo de servicios
customServiceGroup.displayDescription=Agrupa varios servicios en una categoría
initScript=Ejecutar en shell init
shellScript=Hacer que el script esté disponible durante la sesión shell
fileScript=Permitir llamar a un script con argumentos de archivo en el explorador de archivos
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Grupo de servicios
fixedServiceGroup.displayDescription=Enumerar los servicios disponibles en un sistema
mappedService.displayName=Servicio
mappedService.displayDescription=Interactúa con un servicio expuesto por un contenedor
customService.displayName=Servicio
customService.displayDescription=Añade un servicio personalizado para tunelizar y abrir

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=Le port sur lequel le service fonctionne
serviceHost=Hôte du service
serviceHostDescription=L'hôte sur lequel le service est exécuté
openWebsite=Ouvrir un site web
serviceGroup.displayName=Groupe de service
serviceGroup.displayDescription=Regrouper plusieurs services dans une même catégorie
customServiceGroup.displayName=Groupe de service
customServiceGroup.displayDescription=Regrouper plusieurs services dans une même catégorie
initScript=Exécute sur le shell init
shellScript=Rendre le script disponible pendant la session shell
fileScript=Permet d'appeler un script avec des arguments de fichier dans le navigateur de fichiers
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Groupe de service
fixedServiceGroup.displayDescription=Liste les services disponibles sur un système
mappedService.displayName=Service
mappedService.displayDescription=Interagir avec un service exposé par un conteneur
customService.displayName=Service
customService.displayDescription=Ajouter un service personnalisé au tunnel et à l'ouverture

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=La porta su cui è in esecuzione il servizio
serviceHost=Servizio host
serviceHostDescription=L'host su cui è in esecuzione il servizio
openWebsite=Sito web aperto
serviceGroup.displayName=Gruppo di servizio
serviceGroup.displayDescription=Raggruppa più servizi in un'unica categoria
customServiceGroup.displayName=Gruppo di servizio
customServiceGroup.displayDescription=Raggruppa più servizi in un'unica categoria
initScript=Eseguire su shell init
shellScript=Rendere disponibile lo script durante la sessione di shell
fileScript=Consente di richiamare uno script con argomenti di file nel browser di file
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Gruppo di servizio
fixedServiceGroup.displayDescription=Elenco dei servizi disponibili su un sistema
mappedService.displayName=Servizio
mappedService.displayDescription=Interagire con un servizio esposto da un contenitore
customService.displayName=Servizio
customService.displayDescription=Aggiungi un servizio personalizzato per il tunnel e l'apertura

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=サービスが実行されているポート
serviceHost=サービスホスト
serviceHostDescription=サービスが稼働しているホスト
openWebsite=オープンウェブサイト
serviceGroup.displayName=サービスグループ
serviceGroup.displayDescription=複数のサービスを1つのカテゴリーにまとめる
customServiceGroup.displayName=サービスグループ
customServiceGroup.displayDescription=複数のサービスを1つのカテゴリーにまとめる
initScript=シェル init で実行する
shellScript=シェルセッション中にスクリプトを利用可能にする
fileScript=ファイルブラウザでファイル引数を指定してスクリプトを呼び出せるようにする
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=サービスグループ
fixedServiceGroup.displayDescription=システムで利用可能なサービスをリストアップする
mappedService.displayName=サービス
mappedService.displayDescription=コンテナによって公開されたサービスとやりとりする
customService.displayName=サービス
customService.displayDescription=トンネルとオープンにカスタムサービスを追加する

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=De poort waarop de service draait
serviceHost=Service host
serviceHostDescription=De host waarop de service draait
openWebsite=Open website
serviceGroup.displayName=Servicegroep
serviceGroup.displayDescription=Groepeer meerdere diensten in één categorie
customServiceGroup.displayName=Servicegroep
customServiceGroup.displayDescription=Groepeer meerdere diensten in één categorie
initScript=Uitvoeren op shell init
shellScript=Script beschikbaar maken tijdens shellsessie
fileScript=Laat toe dat een script wordt aangeroepen met bestandsargumenten in de bestandsbrowser
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Servicegroep
fixedServiceGroup.displayDescription=Een lijst van beschikbare services op een systeem
mappedService.displayName=Service
mappedService.displayDescription=Interactie met een service die wordt aangeboden door een container
customService.displayName=Service
customService.displayDescription=Een aangepaste service toevoegen aan tunnel en openen

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=A porta em que o serviço está a ser executado
serviceHost=Anfitrião de serviço
serviceHostDescription=O anfitrião em que o serviço está a ser executado
openWebsite=Abre o sítio Web
serviceGroup.displayName=Grupo de serviços
serviceGroup.displayDescription=Agrupa vários serviços numa categoria
customServiceGroup.displayName=Grupo de serviços
customServiceGroup.displayDescription=Agrupa vários serviços numa categoria
initScript=Corre no shell init
shellScript=Torna o script disponível durante a sessão da shell
fileScript=Permite que o script seja chamado com argumentos de ficheiro no navegador de ficheiros
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Grupo de serviços
fixedServiceGroup.displayDescription=Lista os serviços disponíveis num sistema
mappedService.displayName=Serviço
mappedService.displayDescription=Interage com um serviço exposto por um contentor
customService.displayName=Serviço
customService.displayDescription=Adiciona um serviço personalizado ao túnel e abre

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=Порт, на котором работает сл
serviceHost=Сервисный хост
serviceHostDescription=Хост, на котором запущена служба
openWebsite=Открытый сайт
serviceGroup.displayName=Группа услуг
serviceGroup.displayDescription=Сгруппируйте несколько сервисов в одну категорию
customServiceGroup.displayName=Группа услуг
customServiceGroup.displayDescription=Сгруппируйте несколько сервисов в одну категорию
initScript=Запуск на shell init
shellScript=Сделать скрипт доступным во время сеанса оболочки
fileScript=Разрешить вызов скрипта с аргументами в виде файлов в браузере файлов
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Группа услуг
fixedServiceGroup.displayDescription=Список доступных сервисов в системе
mappedService.displayName=Сервис
mappedService.displayDescription=Взаимодействие с сервисом, открываемым контейнером
customService.displayName=Сервис
customService.displayDescription=Добавьте пользовательский сервис для туннелирования и открытия

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=Hizmetin üzerinde çalıştığı bağlantı nokta
serviceHost=Hizmet sunucusu
serviceHostDescription=Hizmetin üzerinde çalıştığı ana bilgisayar
openWebsite=ık web sitesi
serviceGroup.displayName=Hizmet grubu
serviceGroup.displayDescription=Birden fazla hizmeti tek bir kategoride gruplayın
customServiceGroup.displayName=Hizmet grubu
customServiceGroup.displayDescription=Birden fazla hizmeti tek bir kategoride gruplayın
initScript=Kabuk başlangıcında çalıştır
shellScript=Kabuk oturumu sırasında komut dosyasını kullanılabilir hale getirme
fileScript=Kodun dosya tarayıcısında dosya bağımsız değişkenleriyle çağrılmasına izin ver
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Hizmet grubu
fixedServiceGroup.displayDescription=Bir sistemdeki mevcut hizmetleri listeleme
mappedService.displayName=Hizmet
mappedService.displayDescription=Bir konteyner tarafından sunulan bir hizmetle etkileşim
customService.displayName=Hizmet
customService.displayDescription=Tünele özel bir hizmet ekleyin ve açın

View file

@ -141,8 +141,8 @@ serviceRemotePortDescription=服务运行的端口
serviceHost=服务主机
serviceHostDescription=服务运行的主机
openWebsite=打开网站
serviceGroup.displayName=服务组
serviceGroup.displayDescription=将多项服务归为一类
customServiceGroup.displayName=服务组
customServiceGroup.displayDescription=将多项服务归为一类
initScript=在 shell init 上运行
shellScript=在 shell 会话中提供脚本
fileScript=允许在文件浏览器中使用文件参数调用脚本
@ -152,3 +152,5 @@ fixedServiceGroup.displayName=服务组
fixedServiceGroup.displayDescription=列出系统中可用的服务
mappedService.displayName=服务
mappedService.displayDescription=与容器暴露的服务交互
customService.displayName=服务
customService.displayDescription=为隧道和开放添加自定义服务

View file

@ -264,6 +264,40 @@ paths:
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/fs/read:
post:
summary: Read the content of a remote file
description: |
Reads the entire content of a remote file through an active shell session.
operationId: fsRead
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FsReadRequest'
examples:
simple:
summary: Read file
value: { "connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b", "path": "/home/user/myfile.txt" }
responses:
'200':
description: The operation was successful. The file was read.
content:
application/octet-stream:
schema:
type: string
format: binary
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/fs/write:
post:
summary: Write a blob to a remote file
@ -402,6 +436,18 @@ components:
- connection
- blob
- path
FsReadRequest:
type: object
properties:
connection:
type: string
description: The connection uuid
path:
type: string
description: The target file path
required:
- connection
- path
FsScriptRequest:
type: object
properties:

View file

@ -1 +1 @@
10.0-10
10.0-11