Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
1b48c86
bump jsinterop/elemental2 vers
niloc132 Feb 5, 2026
b440877
Add grpc-gwt and protobuf-gwt, compiles with warnings
niloc132 Feb 5, 2026
5c48afc
fix warnings
niloc132 Feb 5, 2026
b74daf0
adapt ts transport types
niloc132 Feb 5, 2026
352ffd2
Start compiling our generated grpc
niloc132 Feb 5, 2026
426153b
Passes javac and gwtc (and spotless!)
niloc132 Mar 30, 2026
e5e0f4a
More cleanup of some remaining imports
niloc132 Mar 30, 2026
b1c9be0
API loads, but doesn't work yet
niloc132 Mar 30, 2026
888731d
add logging, fix login, work on websockets
niloc132 Mar 31, 2026
50d026d
Handle emulated headers over websockets, fix auth headers vs trailers
niloc132 Apr 1, 2026
1bf1d97
fix buffer reuse on server, fix byte[] casts
niloc132 Apr 2, 2026
7be971d
Avoid toString on protos, fix another bad cast
niloc132 Apr 2, 2026
215b551
Remove some junk logs/code
niloc132 Apr 2, 2026
23a809c
Actually use the bidi interceptor
niloc132 Apr 2, 2026
0ab9615
Fixed more ticket->bytes, corrected bidi stream
niloc132 Apr 2, 2026
55b2e5c
better name
niloc132 Apr 2, 2026
4bace79
Fix websocket transport errors
niloc132 Apr 3, 2026
74b70ab
Tests mostly pass, fix a few bugs
niloc132 Apr 6, 2026
8388afa
fix off-by-one
niloc132 Apr 6, 2026
860218e
Remove unnecessary log
niloc132 Apr 7, 2026
e7c7947
Simplify error messages, get a clearer failure for a test
niloc132 Apr 7, 2026
4ce353b
Filter toString, spotless
niloc132 Apr 7, 2026
675cc94
fixed view/drop columns bug
niloc132 Apr 7, 2026
da99e3c
Merge branch 'main' into 19901-grpc-gwt
niloc132 Apr 7, 2026
d464d34
Review feedback
niloc132 Apr 7, 2026
c99ce79
Fix error case, message
niloc132 Apr 7, 2026
883c2d4
local review feedback/cleanup/docs
niloc132 Apr 7, 2026
2459bb1
Rework figure api to avoid needing old callbacks method
niloc132 Apr 7, 2026
cd41498
More cleanup, spotless
niloc132 Apr 7, 2026
4a095b8
Support headers, h2/tls
niloc132 Apr 9, 2026
2a1de37
Add/remove newlines, add empty dh-internal.js
niloc132 Apr 9, 2026
b74c363
fix an error message, cleanup dead/simple code
niloc132 Apr 9, 2026
7b49cae
Unwrap metadata to headers obj, fix nullable/optional mismatch
niloc132 Apr 9, 2026
7e217a6
Add missing onCOmpleted
niloc132 Apr 9, 2026
151e98e
fix a warning, moving a reusable method to somewhere it is used
niloc132 Apr 9, 2026
91c5f49
Limit to just one build, avoid another compile warning
niloc132 Apr 9, 2026
6db4536
Merge branch 'main' into 19901-grpc-gwt
niloc132 Apr 9, 2026
1d9fcdc
Remove fallback ws support, spotless
niloc132 Apr 9, 2026
7c80cb5
Clean up readability
niloc132 Apr 9, 2026
b3c780b
Handle bidi streams correctly with fetch
niloc132 Apr 9, 2026
72297a9
Ensure we read message sizes in LE
niloc132 Apr 9, 2026
15ae86a
Support other transport errors, don't unset auth header right away
niloc132 Apr 9, 2026
76702a1
spotless
niloc132 Apr 9, 2026
e172519
Remove dead code
niloc132 Apr 10, 2026
13d0b62
fix fetchTotals count bugs, closeSession bug
niloc132 Apr 14, 2026
04f2765
spotlss
niloc132 Apr 14, 2026
a27ccc3
Added a comment, test at clod's behest, to confirm it is making up a bug
niloc132 Apr 14, 2026
c10687f
Better err handling
niloc132 Apr 14, 2026
2501e26
Add a javadoc note about an ignored param
niloc132 Apr 14, 2026
9c0096e
rename local
niloc132 Apr 14, 2026
d98dddd
login/deauth cleanup
niloc132 Apr 15, 2026
33ca2c6
Provide our own fetch() impl to make ts behave, fix a logging issue
niloc132 Apr 15, 2026
6944d32
spotless
niloc132 Apr 15, 2026
485deb9
Remove useless assert, add clearer comments and handle future null body
niloc132 Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion buildSrc/src/main/groovy/GwtTools.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class GwtTools {
checkAssertions = true
setExtraArgs('-includeJsInteropExports', 'io.deephaven.*')
if (gwtDev) {
extraArgs = [
'-includeJsInteropExports', 'io.deephaven.*',
'-setProperty', 'gwt.logging.logLevel=FINE',
'-setProperty', 'jre.logging.logLevel=ALL',
]
saveSource = true
extra = extras
logLevel = 'INFO'
Expand All @@ -80,6 +85,8 @@ class GwtTools {
def libs = p.getExtensions().getByType(VersionCatalogsExtension).named("libs")
def gwtVersion = libs.findVersion("gwt").map(VersionConstraint::getRequiredVersion).orElseThrow()
def gwtJettyVersion = libs.findVersion("gwtJetty").map(VersionConstraint::getRequiredVersion).orElseThrow()
def protobufVers = libs.findVersion('protobuf-gwt').get().requiredVersion
def grpcVers = libs.findVersion('grpc-gwt').get().requiredVersion

gwt.gwtVersion = gwtVersion
gwt.jettyVersion = gwtJettyVersion
Expand All @@ -91,7 +98,22 @@ class GwtTools {
.using(sub.module("org.gwtproject:gwt-user:${gwtVersion}"))
sub.substitute(sub.module("com.google.gwt:gwt-dev"))
.using(sub.module("org.gwtproject:gwt-dev:${gwtVersion}"))
sub.substitute(sub.module('com.google.protobuf:protobuf-java'))
.using(sub.module("com.vertispan.protobuf:protobuf-gwt:${protobufVers}"))
sub.substitute(sub.module('io.grpc:grpc-api'))
.using(sub.module("com.vertispan.grpc:grpc-gwt:${grpcVers}"))
sub.substitute(sub.module('io.grpc:grpc-core'))
.using(sub.module("com.vertispan.grpc:grpc-gwt:${grpcVers}"))
sub.substitute(sub.module('io.grpc:grpc-stub'))
.using(sub.module("com.vertispan.grpc:grpc-gwt:${grpcVers}"))
sub.substitute(sub.module('io.grpc:grpc-protobuf'))
.using(sub.module("com.vertispan.grpc:grpc-gwt:${grpcVers}"))
sub.substitute(sub.module('io.grpc:grpc-protobuf-stub'))
.using(sub.module("com.vertispan.grpc:grpc-gwt:${grpcVers}"))
}

c.exclude(group: 'io.grpc', module: 'grpc-netty')
c.exclude(group: 'com.google.protobuf', module: 'protobuf-java-util')
}
String warPath = new File(p.buildDir, 'gwt').absolutePath

Expand All @@ -114,7 +136,7 @@ class GwtTools {
/** Fail compilation if any input file contains an error. */
strict = true
/** Specifies Java source level. ("1.6", "1.7")*/
sourceLevel = "11"
sourceLevel = "17"
/** The number of local workers to use when compiling permutations. */
localWorkers = 1
/** Emit extra information allow chrome dev tools to display Java identifiers in many places instead of JavaScript functions. (NONE, ONLY_METHOD_NAME, ABBREVIATED, FULL)*/
Expand Down
2 changes: 1 addition & 1 deletion extensions/protobuf/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ spotless {

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${libs.versions.protobuf.get()}"
artifact = libs.protoc.get().toString()
}
}
17 changes: 14 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ deephaven-hash = "0.5.0"
deephaven-suan-shu = "0.1.1"
dev-dirs = "26"
dsi = "8.5.18"
elemental = "1.2.3"
elemental = "1.3.2"
f4b6a3 = "6.1.1"
flatbuffers = "25.2.10"
freemarker = "2.3.33"
Expand All @@ -42,7 +42,12 @@ groovy = "3.0.25"
grpc = "1.76.2"
netty = "4.1.127.Final"

guava = "33.4.8-jre"
protobuf-gwt='4.33.2-2'
grpc-gwt='1.76.2-2'

grpc-web-gwt-fetch='1.2.0'

guava = "33.5.0-jre"
gwt = "2.12.2"
# used by GwtTools
gwtJetty = "9.4.44.v20210927"
Expand All @@ -63,7 +68,7 @@ jetbrains = "26.0.1"
jetty = "12.0.33"
jetty11 = "11.0.20"
jpy = "1.3.0"
jsinterop = "2.0.2"
jsinterop = "2.1.0"
# google is annoying, and have different versions released for the same groupId
jsinterop-base = "1.0.3"
logback = "1.5.26"
Expand Down Expand Up @@ -203,7 +208,12 @@ netty-bom = { module = "io.netty:netty-bom", version.ref = "netty" }

google-rpc-protos = { module="com.google.api.grpc:proto-google-common-protos", version.ref="google-rpc-protos" }

protobuf-gwt = { module = 'com.vertispan.protobuf:protobuf-gwt', version.ref = 'protobuf-gwt' }
grpc-gwt = { module = 'com.vertispan.grpc:grpc-gwt', version.ref = 'grpc-gwt' }
grpc-gwt-fetch = { module = 'com.vertispan.grpc:grpc-web-gwt-fetch', version.ref = 'grpc-web-gwt-fetch' }

guava = { module = "com.google.guava:guava", version.ref = "guava" }
guava-gwt = { module = "com.google.guava:guava-gwt", version.ref = "guava" }

gwt-user = { module = "org.gwtproject:gwt-user", version.ref = "gwt" }

Expand Down Expand Up @@ -300,6 +310,7 @@ postgresql = { module = "org.postgresql:postgresql", version.ref = "postgresql"

protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuf" }
protobuf-java-util = { module = "com.google.protobuf:protobuf-java-util", version.ref = "protobuf" }
protoc = { module = "com.google.protobuf:protoc", version.ref = "protobuf" }

randelshofer-fastdoubleparser = { module = "ch.randelshofer:fastdoubleparser", version.ref = "randelshofer" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ public void onMessage(ByteBuffer message) throws IOException {
}

// Having already stripped the control flow byte, the rest of the payload is our request message
stream.inboundDataReceived(ReadableBuffers.wrap(message), false);
ByteBuffer copy = ByteBuffer.allocate(message.remaining());
copy.put(message);
stream.inboundDataReceived(ReadableBuffers.wrap(copy.flip()), false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<module>
<source path="" />
</module>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<module>
<inherits name="io.grpc.Grpc" />
<source path="script" />
<source path="grpc" />
</module>
11 changes: 8 additions & 3 deletions web/client-api/client-api.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ configurations {

dependencies {
gwt libs.gwt.user
gwt platform(libs.grpc.bom)
gwt libs.grpc.api
api libs.protobuf.gwt
api libs.grpc.gwt
api libs.grpc.gwt.fetch
api libs.guava.gwt

gwt project(':engine-chunk')
gwt project(':extensions-barrage')
Expand All @@ -63,9 +65,12 @@ dependencies {
gwt libs.vertispan.nio.gwt
gwt libs.vertispan.flatbuffers.gwt

js project(path: ':proto:raw-js-openapi', configuration: 'js')
gwt project(':proto:proto-backplane-grpc')

gwt libs.arrow.flight.core

gwt libs.guava
gwt libs.guava.gwt

gwt libs.elemental.core
gwt libs.elemental.promise
Expand Down
2 changes: 2 additions & 0 deletions web/client-api/gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
io.deephaven.project.ProjectType=JAVA_PUBLIC
languageLevel=17
testLanguageLevel=17
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,27 @@
<inherits name="elemental2.dom.Dom"/>
<inherits name="com.google.flatbuffers.FlatBuffers"/>
<inherits name="org.apache.arrow.flatbuf.FlightFlatbufFormat"/>
<inherits name="org.apache.arrow.flight.impl.FlightProto"/>
<inherits name="io.deephaven.barrage.flatbuf.BarrageFlatbufFormat"/>

<inherits name="io.deephaven.base.Base" />
<inherits name="io.deephaven.Util" />
<inherits name="io.deephaven.io.IO" />
<inherits name="io.deephaven.chunk.Chunk" />
<inherits name="io.deephaven.extensions.barrage.Barrage" />
<inherits name="io.deephaven.flightjs.protocol.BrowserFlight" />
<inherits name="io.deephaven.proto.backplane.DeephavenCoreProto" />

<inherits name="com.vertispan.grpc.fetch.Fetch" />

<inherits name="com.google.gwt.logging.Logging"/>

<define-property name="dh.dev" values="true, false" />
<source path="client" />
<source path="shared" />
<super-source path="super" />
<set-property name="dh.dev" value="false" />

<inherits name="io.deephaven.javascript.proto.dhinternal.DeephavenInternal" />

<inherits name="com.google.gwt.i18n.I18N" />
<inherits name="io.deephaven.web.DeephavenSharedApi" />

Expand All @@ -29,6 +34,13 @@
<add-linker name="dh_linker" />

<set-configuration-property name="user.agent.runtimeWarning" value="false"/>
<set-configuration-property name="document.compatMode.severity" value="IGNORE"/>
<set-property name="gwt.uncaughtexceptionhandler.windowonerror" value="IGNORE"/>

Comment thread
niloc132 marked this conversation as resolved.
<set-property name="jsinterop.checks" value="ENABLED"/>

<!-- Limit to one permutation, which we'll assume to be "safari" - this is what chromium registers as as well,
and for our purposes firefox will be compatible too.
-->
<set-property name="user.agent" value="safari" />
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ bindTo($wnd, globalThis);
var window = $wnd;
var dh = {};
$wnd.dh = dh;
import {dhinternal} from './dh-internal.js';
$wnd.dhinternal = dhinternal;
var $gwt_version = "__GWT_VERSION__";
__JAVASCRIPT_RESULT__
gwtOnLoad(null, '__MODULE_NAME__', null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import elemental2.dom.DomGlobal;
import elemental2.promise.Promise;
import elemental2.promise.Promise.PromiseExecutorCallbackFn.RejectCallbackFn;
import io.deephaven.web.client.api.barrage.stream.TrailersCapturingInterceptor;
import io.deephaven.web.client.api.event.HasEventHandling;
import io.deephaven.web.shared.fu.JsBiConsumer;
import io.grpc.Context;
import io.grpc.Metadata;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;

import javax.annotation.Nullable;
import java.util.function.BiConsumer;
Expand All @@ -18,6 +22,19 @@
*/
public interface Callbacks {

static <T> StreamObserver<T> ignore() {
return new StreamObserver<T>() {
@Override
public void onNext(T value) {}

@Override
public void onError(Throwable t) {}

@Override
public void onCompleted() {}
};
}

static <S, T> Promise<S> promise(@Nullable HasEventHandling failHandler, Consumer<Callback<S, T>> t) {
return new Promise<>((
Promise.PromiseExecutorCallbackFn.ResolveCallbackFn<S> resolve,
Expand Down Expand Up @@ -48,31 +65,20 @@ static <S> RejectCallbackFn notNull(
};
}

static <S> Callback<S, String> of(@Nullable HasEventHandling failHandler, Consumer<S> from) {
return of((v, f) -> {
if (f == null) {
from.accept(v);
} else {
failLog(failHandler, from, f);
}
});
}

static <S, F> void failLog(HasEventHandling failHandler, Consumer<S> from, F failure) {
if (failHandler != null) {
failHandler.failureHandled(failure == null ? null : String.valueOf(failure));
} else {
DomGlobal.console.error("Request ", from, " failed with reason ", failure);
}

}

/**
* Transform a bi-consumer into a callback. It is the caller's responsibility to fire "requestfailed" events as
* appropriate.
*/
static <S, F> Callback<S, F> of(BiConsumer<S, F> from) {
return new Callback<S, F>() {
return new Callback<>() {
F fail;

@Override
Expand All @@ -88,29 +94,77 @@ public void onSuccess(S result) {
};
}

static <S, F> Promise<S> grpcUnaryPromise(Consumer<JsBiConsumer<F, S>> t) {
/**
* Propagates the message and the context into a Promise, as a promise's microtask will result in losing the
* context. Does not resolve until the unary stream is closed, in order to read the trailers, in contrast with
* {@link #grpcUnaryPromise(Consumer)}.
*/
static <S> Promise<Response<S>> grpcUnaryPromiseWrapped(Consumer<StreamObserver<S>> t) {
return new Promise<>((resolve, reject) -> {
t.accept((fail, success) -> {
if (fail == null) {
resolve.onInvoke(success);
} else {
reject.onInvoke(fail);
t.accept(new StreamObserver<>() {
private S success;

@Override
public void onNext(S s) {
success = s;
}

@Override
public void onError(Throwable throwable) {
assert success == null;
reject.onInvoke(getError(throwable));
}

@Override
public void onCompleted() {
if (success != null) {
// Capture the context here, when the call has finished
Context current = Context.current();
resolve.onInvoke(new Response<>(success, current,
TrailersCapturingInterceptor.getTrailersFromContext()));
}
}
});
});
}

static <S, F> void translateCallback(Callback<S, String> callback, Consumer<JsBiConsumer<F, S>> t) {
try {
t.accept((fail, success) -> {
if (fail != null) {
callback.onSuccess(success);
} else {
callback.onFailure(fail.toString());
/**
* Returns a promise that resolves when the first payload arrives from a unary request. Because promises resolve on
* a microtask, the later called promise will not necessarily share the same Context as the call, use
* {@link #grpcUnaryPromiseWrapped(Consumer)} for that.
*/
static <S> Promise<S> grpcUnaryPromise(Consumer<StreamObserver<S>> t) {
return new Promise<>((resolve, reject) -> {
t.accept(new StreamObserver<>() {

@Override
public void onNext(S s) {
resolve.onInvoke(s);
}

@Override
public void onError(Throwable throwable) {
reject.onInvoke(getError(throwable));
}

@Override
public void onCompleted() {
// no-op since we don't need context/trailers
}
});
} catch (Exception exception) {
callback.onFailure(exception.getMessage());
});
}

private static Object getError(Throwable throwable) {
if (throwable instanceof StatusRuntimeException sre) {
String description = sre.getStatus().getDescription();
return "Error: " + (description == null ? sre.getMessage() : description);
} else {
return "Error: " + throwable;
}
}

@SuppressWarnings("unusable-by-js")
record Response<M>(M message, Context context, Metadata trailers) {
Comment thread
niloc132 marked this conversation as resolved.
}
}
Loading
Loading