Implement drains and small fixes

This commit is contained in:
Christopher Schnick 2022-11-01 08:01:33 +01:00
parent a0c008ab3b
commit 3c72078d2b
14 changed files with 250 additions and 36 deletions

View file

@ -0,0 +1,30 @@
package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder;
import lombok.NonNull;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
public class ReadDrainExchange implements MessageExchange {
@Override
public String getId() {
return "readDrain";
}
@Jacksonized
@Builder
@Value
public static class Request implements RequestMessage {
@NonNull
String name;
}
@Jacksonized
@Builder
@Value
public static class Response implements ResponseMessage {}
}

View file

@ -41,6 +41,7 @@ module io.xpipe.beacon {
RenameStoreExchange,
RemoveStoreExchange,
StoreAddExchange,
ReadDrainExchange,
WritePreparationExchange,
WriteExecuteExchange,
SelectExchange,

View file

@ -5,7 +5,7 @@ import lombok.AllArgsConstructor;
import lombok.Value;
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
@AllArgsConstructor(onConstructor=@__({@JsonCreator}))
public class Choice {
/**

View file

@ -0,0 +1,71 @@
package io.xpipe.core.impl;
import io.xpipe.core.data.node.ArrayNode;
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
import io.xpipe.core.data.node.TupleNode;
import io.xpipe.core.data.type.TupleType;
import io.xpipe.core.source.TableReadConnection;
import java.util.OptionalInt;
import java.util.concurrent.atomic.AtomicInteger;
public class BufferedTableReadConnection implements TableReadConnection {
private final TableReadConnection connection;
private final int maxCount;
private int count = 0;
private ArrayNode read;
public BufferedTableReadConnection(TableReadConnection connection, int maxCount) throws Exception {
this.connection = connection;
this.maxCount = maxCount;
read = connection.readRows(maxCount);
}
private TupleNode get() throws Exception {
if (count == read.size()) {
read = connection.readRows(maxCount);
}
if (read.size() == 0) {
return null;
}
return read.at(count++).asTuple();
}
@Override
public void close() throws Exception {
connection.close();
}
@Override
public TupleType getDataType() {
return connection.getDataType();
}
@Override
public OptionalInt getRowCount() throws Exception {
return connection.getRowCount();
}
@Override
public int withRows(DataStructureNodeAcceptor<TupleNode> lineAcceptor) throws Exception {
AtomicInteger localCounter = new AtomicInteger();
TupleNode node;
while (((node = get()) != null)) {
var returned = lineAcceptor.accept(node);
if (!returned) {
break;
}
localCounter.getAndIncrement();
}
return localCounter.get();
}
@Override
public boolean canRead() throws Exception {
return connection.canRead();
}
}

View file

@ -0,0 +1,67 @@
package io.xpipe.core.impl;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.core.charsetter.NewLine;
import io.xpipe.core.charsetter.StreamCharset;
import io.xpipe.core.store.KnownFormatStreamDataStore;
import io.xpipe.core.util.JacksonizedValue;
import lombok.Getter;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.Pipe;
@JsonTypeName("drain")
@SuperBuilder
@Jacksonized
@Getter
public class DrainStore extends JacksonizedValue implements KnownFormatStreamDataStore {
private final String description;
private final StreamCharset charset;
private final NewLine newLine;
@JsonIgnore
private boolean open;
@JsonIgnore
private Pipe pipe;
private boolean used;
private void waitForOpen() {
while (!open) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
break;
}
}
}
@Override
public boolean canOpen() throws Exception {
return false;
}
@Override
public InputStream openInput() throws Exception {
if (used) {
throw new IllegalStateException("Drain has already been used");
}
waitForOpen();
return Channels.newInputStream(pipe.source());
}
@Override
public OutputStream openOutput() throws Exception {
used = true;
pipe = Pipe.open();
open = true;
return Channels.newOutputStream(pipe.sink());
}
}

View file

@ -11,14 +11,15 @@ import java.util.Optional;
public abstract class TableDataSource<DS extends DataStore> extends DataSource<DS> {
public Optional<TupleType> determineDataType() throws Exception {
try (var readConnection = newReadConnection()) {
var canRead = readConnection != null && readConnection.canRead();
if (canRead) {
var readConnection = newReadConnection();
var canRead = readConnection != null && readConnection.canRead();
if (canRead) {
try (var in = readConnection) {
readConnection.init();
return Optional.ofNullable(readConnection.getDataType());
} else {
return Optional.empty();
}
} else {
return Optional.empty();
}
}

View file

@ -6,6 +6,7 @@ import io.xpipe.core.data.node.DataStructureNodeAcceptor;
import io.xpipe.core.data.node.TupleNode;
import io.xpipe.core.data.type.TupleType;
import io.xpipe.core.data.typed.TypedDataStreamWriter;
import io.xpipe.core.impl.BufferedTableReadConnection;
import io.xpipe.core.impl.LimitTableReadConnection;
import java.io.OutputStream;
@ -63,6 +64,14 @@ public interface TableReadConnection extends DataSourceReadConnection {
return new LimitTableReadConnection(this, limit);
}
default TableReadConnection buffered() throws Exception {
return buffered(Integer.MAX_VALUE);
}
default TableReadConnection buffered(int limit) throws Exception {
return new BufferedTableReadConnection(this, limit);
}
/**
* Consumes the table rows until the acceptor returns false.
*

View file

@ -0,0 +1,11 @@
package io.xpipe.core.store;
import io.xpipe.core.charsetter.NewLine;
import io.xpipe.core.charsetter.StreamCharset;
public interface KnownFormatStreamDataStore extends StreamDataStore {
StreamCharset getCharset();
NewLine getNewLine();
}

View file

@ -2,6 +2,7 @@ package io.xpipe.extension;
import io.xpipe.core.store.DataStore;
import io.xpipe.extension.event.ErrorEvent;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.Region;
import java.util.ArrayList;
@ -40,7 +41,7 @@ public interface DataStoreActionProvider<T extends DataStore> {
default void applyToRegion(T store, Region region) {}
String getName(T store);
ObservableValue<String> getName(T store);
String getIcon(T store);

View file

@ -4,6 +4,7 @@ import io.xpipe.core.store.DataFlow;
import io.xpipe.extension.I18n;
import io.xpipe.fxcomps.SimpleComp;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.Region;
import lombok.EqualsAndHashCode;
@ -24,7 +25,7 @@ public class DataStoreFlowChoiceComp extends SimpleComp {
map.put(DataFlow.INPUT, I18n.observable("extension.input"));
map.put(DataFlow.OUTPUT, I18n.observable("extension.output"));
map.put(DataFlow.INPUT_OUTPUT, I18n.observable("extension.inout"));
return new ToggleGroupComp<>(selected, map)
return new ToggleGroupComp<>(selected, new SimpleObjectProperty<>(map))
.apply(struc -> {
new FancyTooltipAugment<>("extension.inputDescription")
.augment(struc.get().getChildren().get(0));

View file

@ -4,6 +4,7 @@ import io.xpipe.fxcomps.Comp;
import io.xpipe.fxcomps.CompStructure;
import io.xpipe.fxcomps.SimpleCompStructure;
import io.xpipe.fxcomps.util.PlatformThread;
import io.xpipe.fxcomps.util.SimpleChangeListener;
import javafx.beans.property.Property;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ToggleButton;
@ -15,9 +16,9 @@ import java.util.Map;
public class ToggleGroupComp<T> extends Comp<CompStructure<HBox>> {
private final Property<T> value;
private final Map<T, ObservableValue<String>> range;
private final ObservableValue<Map<T, ObservableValue<String>>> range;
public ToggleGroupComp(Property<T> value, Map<T, ObservableValue<String>> range) {
public ToggleGroupComp(Property<T> value, ObservableValue<Map<T, ObservableValue<String>>> range) {
this.value = value;
this.range = range;
}
@ -27,29 +28,36 @@ public class ToggleGroupComp<T> extends Comp<CompStructure<HBox>> {
var box = new HBox();
box.getStyleClass().add("toggle-group-comp");
ToggleGroup group = new ToggleGroup();
for (var entry : range.entrySet()) {
var b = new ToggleButton(entry.getValue().getValue());
b.setOnAction(e -> {
value.setValue(entry.getKey());
e.consume();
});
box.getChildren().add(b);
b.setToggleGroup(group);
value.addListener((c, o, n) -> {
PlatformThread.runLaterIfNeeded(() -> b.setSelected(entry.equals(n)));
});
if (entry.getKey().equals(value.getValue())) {
b.setSelected(true);
SimpleChangeListener.apply(PlatformThread.sync(range), val -> {
if (!val.containsKey(value.getValue())) {
this.value.setValue(null);
}
}
if (box.getChildren().size() > 0) {
box.getChildren().get(0).getStyleClass().add("first");
for (int i = 1; i < box.getChildren().size() - 1; i++) {
box.getChildren().get(i).getStyleClass().add("center");
box.getChildren().clear();
for (var entry : val.entrySet()) {
var b = new ToggleButton(entry.getValue().getValue());
b.setOnAction(e -> {
value.setValue(entry.getKey());
e.consume();
});
box.getChildren().add(b);
b.setToggleGroup(group);
value.addListener((c, o, n) -> {
PlatformThread.runLaterIfNeeded(() -> b.setSelected(entry.equals(n)));
});
if (entry.getKey().equals(value.getValue())) {
b.setSelected(true);
}
}
box.getChildren().get(box.getChildren().size() - 1).getStyleClass().add("last");
}
if (box.getChildren().size() > 0) {
box.getChildren().get(0).getStyleClass().add("first");
for (int i = 1; i < box.getChildren().size() - 1; i++) {
box.getChildren().get(i).getStyleClass().add("center");
}
box.getChildren().get(box.getChildren().size() - 1).getStyleClass().add("last");
}
});
group.selectedToggleProperty().addListener((obsVal, oldVal, newVal) -> {
if (newVal == null) oldVal.setSelected(true);

View file

@ -7,26 +7,30 @@ import io.xpipe.extension.util.Validatable;
import io.xpipe.extension.util.Validator;
import io.xpipe.extension.util.Validators;
import io.xpipe.fxcomps.SimpleComp;
import io.xpipe.fxcomps.util.PlatformThread;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.layout.Region;
import lombok.EqualsAndHashCode;
import lombok.Value;
import net.synedra.validatorfx.Check;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Value
@EqualsAndHashCode(callSuper = true)
public class WriteModeChoiceComp extends SimpleComp implements Validatable {
Property<WriteMode> selected;
List<WriteMode> available;
ObservableList<WriteMode> available;
Validator validator = new SimpleValidator();
Check check;
public WriteModeChoiceComp(Property<WriteMode> selected, List<WriteMode> available) {
public WriteModeChoiceComp(Property<WriteMode> selected, ObservableList<WriteMode> available) {
this.selected = selected;
this.available = available;
if (available.size() == 1) {
@ -38,11 +42,19 @@ public class WriteModeChoiceComp extends SimpleComp implements Validatable {
@Override
protected Region createSimple() {
var a = available;
var map = new LinkedHashMap<WriteMode, ObservableValue<String>>();
Property<Map<WriteMode, ObservableValue<String>>> map = new SimpleObjectProperty<>(new LinkedHashMap<WriteMode, ObservableValue<String>>());
for (WriteMode writeMode : a) {
map.put(writeMode,I18n.observable(writeMode.getId()));
map.getValue().put(writeMode,I18n.observable(writeMode.getId()));
}
PlatformThread.sync(available).addListener((ListChangeListener<? super WriteMode>) c -> {
var newMap = new LinkedHashMap<WriteMode, ObservableValue<String>>();
for (WriteMode writeMode : a) {
newMap.put(writeMode,I18n.observable(writeMode.getId()));
}
map.setValue(newMap);
});
return new ToggleGroupComp<>(selected, map)
.apply(struc -> {
for (int i = 0; i < a.size(); i++) {

View file

@ -8,6 +8,7 @@ import io.xpipe.extension.comp.*;
import io.xpipe.fxcomps.Comp;
import io.xpipe.fxcomps.CompStructure;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
@ -95,7 +96,7 @@ public class DynamicOptionsBuilder {
public <V> DynamicOptionsBuilder addToggle(
Property<V> prop, ObservableValue<String> name, Map<V, ObservableValue<String>> names) {
var comp = new ToggleGroupComp<>(prop, names);
var comp = new ToggleGroupComp<>(prop, new SimpleObjectProperty<>(names));
entries.add(new DynamicOptionsComp.Entry(name, comp));
props.add(prop);
return this;

View file

@ -32,6 +32,7 @@ public class ExpectHelper {
return String.format("""
echo(false)
if spawn(%s) then
expect(":")
sendln("%s")
echo(true)
end