diff --git a/web/client-api/src/main/java/io/deephaven/web/client/api/WorkerConnection.java b/web/client-api/src/main/java/io/deephaven/web/client/api/WorkerConnection.java index 3ae41375b2b..d5817f0c9f9 100644 --- a/web/client-api/src/main/java/io/deephaven/web/client/api/WorkerConnection.java +++ b/web/client-api/src/main/java/io/deephaven/web/client/api/WorkerConnection.java @@ -134,6 +134,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @@ -559,7 +560,6 @@ public void exportedTableUpdateMessage(TableTicket clientId, long size) { public void connectionLost() { // notify all active tables and widgets that the connection is closed - // TODO(deephaven-core#3604) when a new session is created, refetch all widgets and use that to drive reconnect simpleReconnectableInstances.forEach((item, index, array) -> { try { item.disconnected(); @@ -730,7 +730,9 @@ public Promise> getObject(JsVariableDefinition definition) { return getHierarchicalTable(definition); } else { warnLegacyTicketTypes(definition.getType()); - return getWidget(definition).then(JsWidget::refetch); + return getWidget(definition) + .then(JsWidget::refetch) + .then(JsWidget::markReconnectable); } } @@ -781,7 +783,9 @@ public Promise> getObject(TypedTicket typedTicket) { return new JsWidget(this, typedTicket).refetch().then(w -> Promise.resolve(new JsTreeTable(this, w))); } else { warnLegacyTicketTypes(typedTicket.getType()); - return getWidget(typedTicket).then(JsWidget::refetch); + return getWidget(typedTicket) + .then(JsWidget::refetch) + .then(JsWidget::markReconnectable); } } @@ -1031,6 +1035,10 @@ public void unregisterSimpleReconnectable(HasLifecycle figure) { this.simpleReconnectableInstances.delete(figure); } + public boolean isConnected() { + return state == State.Connected; + } + public TableServiceGrpc.TableServiceStub tableServiceClient() { return tableServiceClient; diff --git a/web/client-api/src/main/java/io/deephaven/web/client/api/widget/JsWidget.java b/web/client-api/src/main/java/io/deephaven/web/client/api/widget/JsWidget.java index f8599c25dd0..b7bb1c1efdd 100644 --- a/web/client-api/src/main/java/io/deephaven/web/client/api/widget/JsWidget.java +++ b/web/client-api/src/main/java/io/deephaven/web/client/api/widget/JsWidget.java @@ -28,7 +28,7 @@ import io.deephaven.web.client.api.ServerObject; import io.deephaven.web.client.api.WorkerConnection; import io.deephaven.web.client.api.barrage.stream.BiDiStream; -import io.deephaven.web.client.api.event.HasEventHandling; +import io.deephaven.web.client.api.lifecycle.HasLifecycle; import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsOptional; import jsinterop.annotations.JsNullable; @@ -97,9 +97,8 @@ * without the server somehow signaling that it will never reference that export again. * */ -// TODO consider reconnect support? This is somewhat tricky without understanding the semantics of the widget @TsName(namespace = "dh", name = "Widget") -public class JsWidget extends HasEventHandling implements ServerObject, WidgetMessageDetails { +public class JsWidget extends HasLifecycle implements ServerObject, WidgetMessageDetails { /** * Fired when a new message is received from the server. *
@@ -122,6 +121,12 @@ public class JsWidget extends HasEventHandling implements ServerObject, WidgetMe
private boolean hasFetched;
+ /**
+ * Set when the connection reports this widget as disconnected, cleared when a same-session revive (via
+ * {@link #reconnect()}) succeeds. While set, the next initial response re-announces the widget to consumers.
+ */
+ private boolean awaitingRevive;
+
private final Supplier