mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-06-28 19:10:57 +12:00
Add dynamic tunnels
This commit is contained in:
parent
a218f9ac35
commit
c8cf6aa3fb
|
@ -55,7 +55,15 @@ public class StoreCreationBarComp extends SimpleComp {
|
||||||
.shortcut(new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN))
|
.shortcut(new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN))
|
||||||
.apply(new FancyTooltipAugment<>("addDatabase"));
|
.apply(new FancyTooltipAugment<>("addDatabase"));
|
||||||
|
|
||||||
var box = new VerticalComp(List.of(newHostStore, newShellStore, newStreamStore, newDbStore))
|
var newTunnelStore = new ButtonComp(AppI18n.observable("addTunnel"), new FontIcon("mdi2v-vector-polyline-plus"), () -> {
|
||||||
|
GuiDsStoreCreator.showCreation(
|
||||||
|
v -> v.getDisplayCategory().equals(DataStoreProvider.DisplayCategory.TUNNEL));
|
||||||
|
})
|
||||||
|
.styleClass(Styles.FLAT)
|
||||||
|
.shortcut(new KeyCodeCombination(KeyCode.T, KeyCombination.SHORTCUT_DOWN))
|
||||||
|
.apply(new FancyTooltipAugment<>("addTunnel"));
|
||||||
|
|
||||||
|
var box = new VerticalComp(List.of(newHostStore, newShellStore, newStreamStore, newDbStore, newTunnelStore))
|
||||||
.apply(struc -> struc.get().setFillWidth(true));
|
.apply(struc -> struc.get().setFillWidth(true));
|
||||||
box.apply(s -> AppFont.medium(s.get()));
|
box.apply(s -> AppFont.medium(s.get()));
|
||||||
var bar = box.createRegion();
|
var bar = box.createRegion();
|
||||||
|
|
|
@ -197,6 +197,7 @@ public class StoreEntryWrapper implements StorageFilter.Filterable {
|
||||||
found.createAction(entry.getStore().asNeeded()).execute();
|
found.createAction(entry.getStore().asNeeded()).execute();
|
||||||
} else if (getEntry().getStore() instanceof FixedHierarchyStore) {
|
} else if (getEntry().getStore() instanceof FixedHierarchyStore) {
|
||||||
refreshWithChildrenAsync();
|
refreshWithChildrenAsync();
|
||||||
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import lombok.experimental.FieldDefaults;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
|
public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
|
||||||
|
|
||||||
DataStoreProvider.DataCategory category;
|
DataStoreProvider.DisplayCategory category;
|
||||||
Property<DataStore> chosenStore;
|
Property<DataStore> chosenStore;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -34,7 +34,7 @@ public class DataStoreSelectorComp extends Comp<CompStructure<Button>> {
|
||||||
"inProgress",
|
"inProgress",
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
v -> v.getCategory().equals(category),
|
v -> v.getDisplayCategory().equals(category),
|
||||||
entry -> {
|
entry -> {
|
||||||
chosenStore.setValue(entry.getStore());
|
chosenStore.setValue(entry.getStore());
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
package io.xpipe.app.comp.store;
|
|
||||||
|
|
||||||
import io.xpipe.app.core.AppFont;
|
|
||||||
import io.xpipe.app.core.AppI18n;
|
|
||||||
import io.xpipe.app.ext.DataSourceProvider;
|
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
|
||||||
import io.xpipe.app.fxcomps.SimpleComp;
|
|
||||||
import io.xpipe.app.fxcomps.impl.TabPaneComp;
|
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
|
||||||
import io.xpipe.core.store.DataStore;
|
|
||||||
import javafx.beans.binding.Bindings;
|
|
||||||
import javafx.beans.property.Property;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.scene.layout.Region;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
public class DsDbStoreChooserComp extends SimpleComp {
|
|
||||||
|
|
||||||
private final Property<DataStore> input;
|
|
||||||
private final ObservableValue<DataSourceProvider<?>> provider;
|
|
||||||
|
|
||||||
public DsDbStoreChooserComp(Property<DataStore> input, ObservableValue<DataSourceProvider<?>> provider) {
|
|
||||||
this.input = input;
|
|
||||||
this.provider = provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Region createSimple() {
|
|
||||||
var filter = Bindings.createObjectBinding(
|
|
||||||
() -> (Predicate<DataStoreEntry>) e -> {
|
|
||||||
if (provider.getValue() == null) {
|
|
||||||
return e.getProvider().getCategory() == DataStoreProvider.DataCategory.DATABASE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider.getValue().couldSupportStore(e.getStore());
|
|
||||||
},
|
|
||||||
provider);
|
|
||||||
|
|
||||||
var connections = new TabPaneComp.Entry(
|
|
||||||
AppI18n.observable("savedConnections"),
|
|
||||||
"mdi2m-monitor",
|
|
||||||
NamedStoreChoiceComp.create(filter, input, DataStoreProvider.DataCategory.DATABASE)
|
|
||||||
.styleClass("store-local-file-chooser"));
|
|
||||||
|
|
||||||
var pane = new TabPaneComp(new SimpleObjectProperty<>(connections), List.of(connections));
|
|
||||||
pane.apply(s -> AppFont.normal(s.get()));
|
|
||||||
return pane.createRegion();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -121,7 +121,7 @@ public class DsStreamStoreChoiceComp extends SimpleComp implements Validatable {
|
||||||
var other = new TabPaneComp.Entry(
|
var other = new TabPaneComp.Entry(
|
||||||
AppI18n.observable("other"),
|
AppI18n.observable("other"),
|
||||||
"mdrmz-web_asset",
|
"mdrmz-web_asset",
|
||||||
new DataStoreSelectorComp(DataStoreProvider.DataCategory.STREAM, otherStore));
|
new DataStoreSelectorComp(DataStoreProvider.DisplayCategory.HOST, otherStore));
|
||||||
|
|
||||||
var selectedTab = new SimpleObjectProperty<TabPaneComp.Entry>();
|
var selectedTab = new SimpleObjectProperty<TabPaneComp.Entry>();
|
||||||
if (localStore.get() != null) {
|
if (localStore.get() != null) {
|
||||||
|
|
|
@ -105,11 +105,11 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
v -> true,
|
v -> true,
|
||||||
newE -> {
|
newE -> {
|
||||||
ThreadHelper.runAsync(() -> {
|
ThreadHelper.runAsync(() -> {
|
||||||
e.applyChanges(newE);
|
|
||||||
if (!DataStorage.get().getStoreEntries().contains(e)) {
|
if (!DataStorage.get().getStoreEntries().contains(e)) {
|
||||||
DataStorage.get().addStoreEntry(e);
|
DataStorage.get().addStoreEntry(e);
|
||||||
|
} else {
|
||||||
|
DataStorage.get().updateEntry(e, newE);
|
||||||
}
|
}
|
||||||
DataStorage.get().refresh();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
|
|
|
@ -146,7 +146,7 @@ public class NamedStoreChoiceComp extends SimpleComp implements Validatable {
|
||||||
var text = new LabelComp(AppI18n.observable("noMatchingStoreFound"))
|
var text = new LabelComp(AppI18n.observable("noMatchingStoreFound"))
|
||||||
.apply(struc -> VBox.setVgrow(struc.get(), Priority.ALWAYS));
|
.apply(struc -> VBox.setVgrow(struc.get(), Priority.ALWAYS));
|
||||||
var addButton = new ButtonComp(AppI18n.observable("addStore"), null, () -> {
|
var addButton = new ButtonComp(AppI18n.observable("addStore"), null, () -> {
|
||||||
GuiDsStoreCreator.showCreation(v -> v.getCategory().equals(category));
|
// GuiDsStoreCreator.showCreation(v -> v.getCategory().equals(category));
|
||||||
});
|
});
|
||||||
var notice = new VerticalComp(List.of(text, addButton))
|
var notice = new VerticalComp(List.of(text, addButton))
|
||||||
.apply(struc -> {
|
.apply(struc -> {
|
||||||
|
|
|
@ -195,6 +195,10 @@ public class AppI18n {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMarkdownDocumentation(String name) {
|
public String getMarkdownDocumentation(String name) {
|
||||||
|
if (!markdownDocumentations.containsKey(name)) {
|
||||||
|
TrackEvent.withWarn("Markdown documentation for key " + name + " not found").handle();
|
||||||
|
}
|
||||||
|
|
||||||
return markdownDocumentations.getOrDefault(name, "");
|
return markdownDocumentations.getOrDefault(name, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.xpipe.app.core.mode;
|
package io.xpipe.app.core.mode;
|
||||||
|
|
||||||
import io.xpipe.app.core.*;
|
import io.xpipe.app.core.*;
|
||||||
|
import io.xpipe.app.ext.DataStoreProviders;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.issue.ErrorHandler;
|
import io.xpipe.app.issue.ErrorHandler;
|
||||||
import io.xpipe.app.issue.TrackEvent;
|
import io.xpipe.app.issue.TrackEvent;
|
||||||
|
@ -105,6 +106,11 @@ public abstract class OperationMode {
|
||||||
setup(args);
|
setup(args);
|
||||||
LauncherCommand.runLauncher(usedArgs);
|
LauncherCommand.runLauncher(usedArgs);
|
||||||
inStartup = false;
|
inStartup = false;
|
||||||
|
postInit(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void postInit(String[] args) {
|
||||||
|
DataStoreProviders.postInit(AppExtensionManager.getInstance().getExtendedLayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInStartup() {
|
public static boolean isInStartup() {
|
||||||
|
|
|
@ -15,12 +15,12 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response handleRequest(BeaconHandler handler, Request msg) {
|
public Response handleRequest(BeaconHandler handler, Request msg) {
|
||||||
var categories = DataStoreProvider.DataCategory.values();
|
var categories = DataStoreProvider.DisplayCategory.values();
|
||||||
var all = DataStoreProviders.getAll();
|
var all = DataStoreProviders.getAll();
|
||||||
var map = Arrays.stream(categories)
|
var map = Arrays.stream(categories)
|
||||||
.collect(Collectors.toMap(category -> getName(category), category -> all.stream()
|
.collect(Collectors.toMap(category -> getName(category), category -> all.stream()
|
||||||
.filter(dataStoreProvider ->
|
.filter(dataStoreProvider ->
|
||||||
dataStoreProvider.getCategory().equals(category))
|
dataStoreProvider.getDisplayCategory().equals(category))
|
||||||
.map(p -> ProviderEntry.builder()
|
.map(p -> ProviderEntry.builder()
|
||||||
.id(p.getId())
|
.id(p.getId())
|
||||||
.description(p.getDisplayDescription())
|
.description(p.getDisplayDescription())
|
||||||
|
@ -31,7 +31,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange
|
||||||
return Response.builder().entries(map).build();
|
return Response.builder().entries(map).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getName(DataStoreProvider.DataCategory category) {
|
private String getName(DataStoreProvider.DisplayCategory category) {
|
||||||
return category.name().substring(0, 1).toUpperCase()
|
return category.name().substring(0, 1).toUpperCase()
|
||||||
+ category.name().substring(1).toLowerCase();
|
+ category.name().substring(1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ public interface DataStoreProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
default void validate() {
|
default void validate() {
|
||||||
getCategory();
|
|
||||||
for (Class<?> storeClass : getStoreClasses()) {
|
for (Class<?> storeClass : getStoreClasses()) {
|
||||||
if (!JacksonizedValue.class.isAssignableFrom(storeClass)) {
|
if (!JacksonizedValue.class.isAssignableFrom(storeClass)) {
|
||||||
throw new ExtensionException(
|
throw new ExtensionException(
|
||||||
|
@ -34,6 +33,8 @@ public interface DataStoreProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void preAdd(DataStore store) {}
|
||||||
|
|
||||||
default Comp<?> customDisplay(StoreSection s) {
|
default Comp<?> customDisplay(StoreSection s) {
|
||||||
return new StandardStoreEntryComp(s.getWrapper(), null);
|
return new StandardStoreEntryComp(s.getWrapper(), null);
|
||||||
}
|
}
|
||||||
|
@ -90,27 +91,7 @@ public interface DataStoreProvider {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
default DataCategory getCategory() {
|
|
||||||
var c = getStoreClasses().get(0);
|
|
||||||
if (StreamDataStore.class.isAssignableFrom(c)) {
|
|
||||||
return DataCategory.STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FileSystem.class.isAssignableFrom(c) || ShellStore.class.isAssignableFrom(c)) {
|
|
||||||
return DataCategory.SHELL;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ExtensionException("Provider " + getId() + " has no set category");
|
|
||||||
}
|
|
||||||
|
|
||||||
default DisplayCategory getDisplayCategory() {
|
default DisplayCategory getDisplayCategory() {
|
||||||
var category = getCategory();
|
|
||||||
if (category.equals(DataCategory.SHELL)) {
|
|
||||||
return DisplayCategory.HOST;
|
|
||||||
}
|
|
||||||
if (category.equals(DataCategory.DATABASE)) {
|
|
||||||
return DisplayCategory.DATABASE;
|
|
||||||
}
|
|
||||||
return DisplayCategory.OTHER;
|
return DisplayCategory.OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,19 +111,26 @@ public interface DataStoreProvider {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void postInit(){
|
||||||
|
}
|
||||||
|
|
||||||
default void storageInit() throws Exception {}
|
default void storageInit() throws Exception {}
|
||||||
|
|
||||||
default boolean isShareable() {
|
default boolean isShareable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String queryInformationString(DataStore store, int length) throws Exception;
|
default String queryInformationString(DataStore store, int length) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
default String queryInvalidInformationString(DataStore store, int length) throws Exception {
|
default String queryInvalidInformationString(DataStore store, int length) throws Exception {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String toSummaryString(DataStore store, int length);
|
default String toSummaryString(DataStore store, int length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
default String i18n(String key) {
|
default String i18n(String key) {
|
||||||
return AppI18n.get(getId() + "." + key);
|
return AppI18n.get(getId() + "." + key);
|
||||||
|
@ -205,6 +193,7 @@ public interface DataStoreProvider {
|
||||||
DATABASE,
|
DATABASE,
|
||||||
SHELL,
|
SHELL,
|
||||||
COMMAND,
|
COMMAND,
|
||||||
|
TUNNEL,
|
||||||
OTHER
|
OTHER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ public class DataStoreProviders {
|
||||||
if (ALL == null) {
|
if (ALL == null) {
|
||||||
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream()
|
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream()
|
||||||
.map(ServiceLoader.Provider::get)
|
.map(ServiceLoader.Provider::get)
|
||||||
.sorted(Comparator.comparing(DataStoreProvider::getId))
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
ALL.removeIf(p -> {
|
ALL.removeIf(p -> {
|
||||||
try {
|
try {
|
||||||
|
@ -35,6 +34,20 @@ public class DataStoreProviders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void postInit(ModuleLayer layer) {
|
||||||
|
ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream()
|
||||||
|
.map(ServiceLoader.Provider::get)
|
||||||
|
.sorted(Comparator.comparing(DataStoreProvider::getId))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
ALL.forEach(p -> {
|
||||||
|
try {
|
||||||
|
p.postInit();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
ErrorEvent.fromThrowable(e).handle();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static Optional<DataStoreProvider> byName(String name) {
|
public static Optional<DataStoreProvider> byName(String name) {
|
||||||
if (ALL == null) {
|
if (ALL == null) {
|
||||||
throw new IllegalStateException("Not initialized");
|
throw new IllegalStateException("Not initialized");
|
||||||
|
|
|
@ -42,6 +42,11 @@ public class DataStateProviderImpl extends DataStateProvider {
|
||||||
return c.cast(result);
|
return c.cast(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInStorage(DataStore store) {
|
||||||
|
var entry = DataStorage.get().getStoreEntryIfPresent(store);
|
||||||
|
return entry.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getInternalStreamStore(UUID id) {
|
public Path getInternalStreamStore(UUID id) {
|
||||||
return DataStorage.get().getInternalStreamPath(id);
|
return DataStorage.get().getInternalStreamPath(id);
|
||||||
|
|
|
@ -92,6 +92,7 @@ public abstract class DataStorage {
|
||||||
Collections.reverse(ordered);
|
Collections.reverse(ordered);
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
ordered.forEach(entry -> entry.finalizeEntry());
|
||||||
this.storeEntries.removeAll(ordered);
|
this.storeEntries.removeAll(ordered);
|
||||||
this.listeners.forEach(l -> l.onStoreRemove(ordered.toArray(DataStoreEntry[]::new)));
|
this.listeners.forEach(l -> l.onStoreRemove(ordered.toArray(DataStoreEntry[]::new)));
|
||||||
}
|
}
|
||||||
|
@ -213,6 +214,12 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateEntry(DataStoreEntry entry, DataStoreEntry newEntry) {
|
||||||
|
newEntry.finalizeEntry();
|
||||||
|
entry.applyChanges(newEntry);
|
||||||
|
entry.initializeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
public void refreshAsync(DataStoreEntry element, boolean deep) {
|
public void refreshAsync(DataStoreEntry element, boolean deep) {
|
||||||
ThreadHelper.runAsync(() -> {
|
ThreadHelper.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -233,6 +240,8 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addStoreEntry(@NonNull DataStoreEntry e) {
|
public void addStoreEntry(@NonNull DataStoreEntry e) {
|
||||||
|
e.getProvider().preAdd(e.getStore());
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
||||||
this.storeEntries.add(e);
|
this.storeEntries.add(e);
|
||||||
|
@ -241,16 +250,22 @@ public abstract class DataStorage {
|
||||||
save();
|
save();
|
||||||
|
|
||||||
this.listeners.forEach(l -> l.onStoreAdd(e));
|
this.listeners.forEach(l -> l.onStoreAdd(e));
|
||||||
|
e.initializeEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addStoreEntries(@NonNull DataStoreEntry... es) {
|
public void addStoreEntries(@NonNull DataStoreEntry... es) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (DataStoreEntry e : es) {
|
for (DataStoreEntry e : es) {
|
||||||
|
e.getProvider().preAdd(e.getStore());
|
||||||
|
|
||||||
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
e.setDirectory(getStoresDir().resolve(e.getUuid().toString()));
|
||||||
this.storeEntries.add(e);
|
this.storeEntries.add(e);
|
||||||
propagateUpdate(e);
|
propagateUpdate(e);
|
||||||
}
|
}
|
||||||
this.listeners.forEach(l -> l.onStoreAdd(es));
|
this.listeners.forEach(l -> l.onStoreAdd(es));
|
||||||
|
for (DataStoreEntry e : es) {
|
||||||
|
e.initializeEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
@ -284,6 +299,7 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteStoreEntry(@NonNull DataStoreEntry store) {
|
public void deleteStoreEntry(@NonNull DataStoreEntry store) {
|
||||||
|
store.finalizeEntry();
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
this.storeEntries.remove(store);
|
this.storeEntries.remove(store);
|
||||||
}
|
}
|
||||||
|
@ -298,13 +314,6 @@ public abstract class DataStorage {
|
||||||
|
|
||||||
public abstract void load();
|
public abstract void load();
|
||||||
|
|
||||||
public void refresh() {
|
|
||||||
getStoreEntries().forEach(entry -> {
|
|
||||||
entry.simpleRefresh();
|
|
||||||
});
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void save();
|
public abstract void save();
|
||||||
|
|
||||||
public synchronized Optional<DataStoreEntry> getStoreEntry(UUID id) {
|
public synchronized Optional<DataStoreEntry> getStoreEntry(UUID id) {
|
||||||
|
|
|
@ -288,6 +288,36 @@ public class DataStoreEntry extends StorageElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void initializeEntry() {
|
||||||
|
try {
|
||||||
|
state = State.VALIDATING;
|
||||||
|
listeners.forEach(l -> l.onUpdate());
|
||||||
|
store.initializeValidate();
|
||||||
|
state = State.COMPLETE_AND_VALID;
|
||||||
|
} catch (Exception e) {
|
||||||
|
state = State.COMPLETE_BUT_INVALID;
|
||||||
|
ErrorEvent.fromThrowable(e).handle();
|
||||||
|
} finally {
|
||||||
|
propagateUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void finalizeEntry() {
|
||||||
|
try {
|
||||||
|
state = State.VALIDATING;
|
||||||
|
listeners.forEach(l -> l.onUpdate());
|
||||||
|
store.finalizeValidate();
|
||||||
|
state = State.COMPLETE_AND_VALID;
|
||||||
|
} catch (Exception e) {
|
||||||
|
state = State.COMPLETE_BUT_INVALID;
|
||||||
|
ErrorEvent.fromThrowable(e).handle();
|
||||||
|
} finally {
|
||||||
|
propagateUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldSave() {
|
protected boolean shouldSave() {
|
||||||
return getStore() == null || getStore().shouldSave();
|
return getStore() == null || getStore().shouldSave();
|
||||||
|
|
|
@ -42,6 +42,12 @@ public class OptionsBuilder {
|
||||||
entries.add(entry);
|
entries.add(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OptionsBuilder sub(OptionsBuilder builder) {
|
||||||
|
props.addAll(builder.props);
|
||||||
|
pushComp(builder.buildComp());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public OptionsBuilder addTitle(String titleKey) {
|
public OptionsBuilder addTitle(String titleKey) {
|
||||||
finishCurrent();
|
finishCurrent();
|
||||||
entries.add(new OptionsComp.Entry(
|
entries.add(new OptionsComp.Entry(
|
||||||
|
|
|
@ -42,6 +42,7 @@ clean=Clean
|
||||||
refresh=Refresh
|
refresh=Refresh
|
||||||
remove=Remove
|
remove=Remove
|
||||||
addDatabase=Add Database ...
|
addDatabase=Add Database ...
|
||||||
|
addTunnel=Add Tunnel ...
|
||||||
addHost=Add Remote Host ...
|
addHost=Add Remote Host ...
|
||||||
addShell=Add Environment ...
|
addShell=Add Environment ...
|
||||||
addCommand=Add Command ...
|
addCommand=Add Command ...
|
||||||
|
|
|
@ -116,7 +116,6 @@ noMatchingSourceFound=No matching source found
|
||||||
addSource=Add Source
|
addSource=Add Source
|
||||||
edit=Edit
|
edit=Edit
|
||||||
addStream=Add File
|
addStream=Add File
|
||||||
addDatabase=Add Database
|
|
||||||
pipeStream=Pipe File
|
pipeStream=Pipe File
|
||||||
pipeDatabase=Pipe Database
|
pipeDatabase=Pipe Database
|
||||||
transfer=Transfer
|
transfer=Transfer
|
||||||
|
|
|
@ -9,13 +9,10 @@ import lombok.Getter;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@JsonTypeName("internalStream")
|
@JsonTypeName("internalStream")
|
||||||
|
@ -35,20 +32,10 @@ public class InternalStreamStore extends JacksonizedValue implements StreamDataS
|
||||||
return DataFlow.INPUT_OUTPUT;
|
return DataFlow.INPUT_OUTPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<String> determineDefaultName() {
|
|
||||||
return Optional.of(uuid.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path getFile() {
|
private Path getFile() {
|
||||||
return DataStateProvider.get().getInternalStreamStore(uuid);
|
return DataStateProvider.get().getInternalStreamStore(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Instant> determineLastModified() throws IOException {
|
|
||||||
return Optional.of(Files.getLastModifiedTime(getFile()).toInstant());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream openInput() throws Exception {
|
public InputStream openInput() throws Exception {
|
||||||
return Files.newInputStream(getFile());
|
return Files.newInputStream(getFile());
|
||||||
|
|
|
@ -5,11 +5,7 @@ import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@JsonTypeName("localDir")
|
@JsonTypeName("localDir")
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
|
@ -22,21 +18,6 @@ public class LocalDirectoryDataStore implements DataStore {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<String> determineDefaultName() {
|
|
||||||
return Optional.of(file.getFileName().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Instant> determineLastModified() {
|
|
||||||
try {
|
|
||||||
var l = Files.getLastModifiedTime(file);
|
|
||||||
return Optional.of(l.toInstant());
|
|
||||||
} catch (IOException e) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getPath() {
|
public Path getPath() {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,6 @@ import lombok.Getter;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store that refers to another store in the XPipe storage.
|
* A store that refers to another store in the XPipe storage.
|
||||||
* The referenced store has to be resolved by the caller manually, as this class does not act as a resolver.
|
* The referenced store has to be resolved by the caller manually, as this class does not act as a resolver.
|
||||||
|
@ -36,13 +33,4 @@ public final class NamedStore implements DataStore {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<String> determineDefaultName() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Instant> determineLastModified() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,6 @@ import io.xpipe.core.impl.StdinDataStore;
|
||||||
import io.xpipe.core.impl.StdoutDataStore;
|
import io.xpipe.core.impl.StdoutDataStore;
|
||||||
import io.xpipe.core.source.DataSource;
|
import io.xpipe.core.source.DataSource;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data store represents some form of a location where data is stored, e.g. a file or a database.
|
* A data store represents some form of a location where data is stored, e.g. a file or a database.
|
||||||
* It does not contain any information on what data is stored,
|
* It does not contain any information on what data is stored,
|
||||||
|
@ -77,6 +73,10 @@ public interface DataStore {
|
||||||
*/
|
*/
|
||||||
default void validate() throws Exception {}
|
default void validate() throws Exception {}
|
||||||
|
|
||||||
|
default void initializeValidate() throws Exception {}
|
||||||
|
|
||||||
|
default void finalizeValidate() throws Exception {}
|
||||||
|
|
||||||
default void checkComplete() throws Exception {}
|
default void checkComplete() throws Exception {}
|
||||||
|
|
||||||
default boolean delete() {
|
default boolean delete() {
|
||||||
|
@ -90,19 +90,4 @@ public interface DataStore {
|
||||||
default <DS extends DataStore> DS asNeeded() {
|
default <DS extends DataStore> DS asNeeded() {
|
||||||
return (DS) this;
|
return (DS) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines on optional default name for this data store that is
|
|
||||||
* used when determining a suitable default name for a data source.
|
|
||||||
*/
|
|
||||||
default Optional<String> determineDefaultName() {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines the last modified of this data store if this data store supports it.
|
|
||||||
*/
|
|
||||||
default Optional<Instant> determineLastModified() throws IOException {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,11 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a store that has a filename.
|
* Represents a store that has a filename.
|
||||||
* Note that this does not only apply to file stores but any other store as well that has some kind of file name.
|
* Note that this does not only apply to file stores but any other store as well that has some kind of file name.
|
||||||
*/
|
*/
|
||||||
public interface FilenameStore extends DataStore {
|
public interface FilenameStore extends DataStore {
|
||||||
|
|
||||||
@Override
|
|
||||||
default Optional<String> determineDefaultName() {
|
|
||||||
var n = getFileName();
|
|
||||||
var i = n.lastIndexOf('.');
|
|
||||||
return Optional.of(i != -1 ? n.substring(0, i) : n);
|
|
||||||
}
|
|
||||||
|
|
||||||
default String getFileExtension() {
|
default String getFileExtension() {
|
||||||
var split = getFileName().split("[\\\\.]");
|
var split = getFileName().split("[\\\\.]");
|
||||||
if (split.length == 0) {
|
if (split.length == 0) {
|
||||||
|
|
|
@ -6,6 +6,10 @@ import java.util.function.Supplier;
|
||||||
|
|
||||||
public interface StatefulDataStore extends DataStore {
|
public interface StatefulDataStore extends DataStore {
|
||||||
|
|
||||||
|
default boolean isInStorage() {
|
||||||
|
return DataStateProvider.get().isInStorage(this);
|
||||||
|
}
|
||||||
|
|
||||||
default <T> T getState(String key, Class<T> c, T def) {
|
default <T> T getState(String key, Class<T> c, T def) {
|
||||||
return DataStateProvider.get().getState(this, key, c, () -> def);
|
return DataStateProvider.get().getState(this, key, c, () -> def);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,5 +25,7 @@ public abstract class DataStateProvider {
|
||||||
|
|
||||||
public abstract <T> T getState(DataStore store, String key, Class<T> c, Supplier<T> def);
|
public abstract <T> T getState(DataStore store, String key, Class<T> c, Supplier<T> def);
|
||||||
|
|
||||||
|
public abstract boolean isInStorage(DataStore store);
|
||||||
|
|
||||||
public abstract Path getInternalStreamStore(UUID id);
|
public abstract Path getInternalStreamStore(UUID id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.nio.charset.Charset;
|
||||||
import java.nio.charset.IllegalCharsetNameException;
|
import java.nio.charset.IllegalCharsetNameException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@JsonTypeName("http")
|
@JsonTypeName("http")
|
||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
|
@ -101,11 +100,6 @@ public class HttpStore extends JacksonizedValue implements StreamDataStore, Stat
|
||||||
Validators.nonNull(headers, "Headers");
|
Validators.nonNull(headers, "Headers");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<String> determineDefaultName() {
|
|
||||||
return Optional.ofNullable(getURL().getHost());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws Exception {
|
public void validate() throws Exception {
|
||||||
var client = createClient();
|
var client = createClient();
|
||||||
|
|
|
@ -70,11 +70,6 @@ public class InMemoryStoreProvider implements DataStoreProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataCategory getCategory() {
|
|
||||||
return DataCategory.STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataStore defaultStore() {
|
public DataStore defaultStore() {
|
||||||
return new InMemoryStore(new byte[0]);
|
return new InMemoryStore(new byte[0]);
|
||||||
|
|
Loading…
Reference in a new issue