Skip to content

Commit d94e10f

Browse files
committed
Basic project that unpacks and transforms grpc-java
0 parents  commit d94e10f

8 files changed

Lines changed: 459 additions & 0 deletions

File tree

.github/workflows/build.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Maven Build
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout code
13+
uses: actions/checkout@v3
14+
15+
- name: Set up JDK
16+
uses: actions/setup-java@v3
17+
with:
18+
java-version: '17'
19+
distribution: 'temurin'
20+
cache: 'maven'
21+
22+
- name: Build with Maven
23+
run: mvn clean install

.gitignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
6+
### IntelliJ IDEA ###
7+
.idea/
8+
*.iws
9+
*.iml
10+
*.ipr
11+
12+
### Eclipse ###
13+
.apt_generated
14+
.classpath
15+
.factorypath
16+
.project
17+
.settings
18+
.springBeans
19+
.sts4-cache
20+
21+
### NetBeans ###
22+
/nbproject/private/
23+
/nbbuild/
24+
/dist/
25+
/nbdist/
26+
/.nb-gradle/
27+
build/
28+
!**/src/main/**/build/
29+
!**/src/test/**/build/
30+
31+
### VS Code ###
32+
.vscode/
33+
34+
### Mac OS ###
35+
.DS_Store

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# grpc-gwt
2+
3+
gRPC-web support for GWT/J2CL projects - starts with the basic gRPC APIs and stubs, and provides both replacements for
4+
those jars, plus gRPC/gRPC-web Channel implementations.
5+
6+
Generated from the Java projects for grpc-api, grpc-stub, grpc-protobuf, and grpc-protobuf-lite. Makes use of standard
7+
OpenRewrite rules and some rules specifically written to
8+
[simplify projects for GWT](https://github.com/vertispan/gwt-compatible-recipes/).
9+
10+
A future version might split these dependencies into separate jars, but for now a subset of the original classes from
11+
all four are included in a single jar.
12+
13+
## Implementation differences
14+
To simplify the effort of transforming the implementation, two features have been removed. Both technically could be
15+
restored, but at a glance there doesn't seem to be an obvious need.
16+
17+
At present, there is no ASCII charset in GWT, so it is assumed that the server is correctly sending ascii status and
18+
metadata values. All valid ascii (e.g. below 128) are equal to their corresponding utf8 value, so there should be no
19+
difference in behavior.
20+
21+
BinaryStreamMarshaller has also been effectively removed, along with the `Metadata.Key.of()` overload that supports it.
22+
The current implementation used Class.isInstance to check which marshaller was in use, though if required this could be
23+
reimplemented without any reflection at all.
24+
25+
## Browser limitations
26+
gRPC is marketed as a "universal" RPC framework that runs in "any environment", but in practice it is entirely unusable
27+
in browsers. Instead, gRPC-web offers a few small changes over gRPC to make it mostly compatible with browsers:
28+
- http/1.1 is supported instead of just h2. In most browsers this limits the number of concurrent streams (usually
29+
6) to a single server, so h2 is still desired for most use cases.
30+
- Additionally, browsers do not support h2c (h2 over cleartext), so gRPC-web over h2 is limited to TLS connections.
31+
This can make localhost or dev/staging deployments difficult to use.
32+
- Rather than HTTP trailers, a final body payload can be read as if it were an http/1 headers block. This doesn't apply
33+
to trailers-only responses
34+
- The `user-agent` header cannot be controlled by clients in a browser runtime, so `x-user-agent` should be used
35+
instead.
36+
- Since all of this adds up to "not actually gRPC", the `content-type` header should be prefixed with
37+
`application/grpc-web` or `application/grpc-web-text`.
38+
39+
These limitations are intended to "make it easy for a proxy to translate between the protocols as this is the most
40+
likely deployment model." Unfortunately, they only cover a subset of the limitations that browsers impose, so it isn't
41+
actually possible to run a proxy which can translate arbitrary gRPC services. The browser's `fetch()` implementation
42+
does not support any client-streaming use cases, which limits clients from participating in either bidirectional
43+
streaming or client streaming RPCs. At the time the spec was written it was believed that [by 2019 this would be resolved](https://github.com/grpc/grpc/commit/4daba4b6ba9717f7ffdde725043bac7e8fd90d28#diff-5f77fa0e0ca74be75527c69b5e918d30f02999e2285c8bd4787464effea8ed5dR29-R32),
44+
and was [later revised](https://github.com/grpc/grpc/commit/f5809cced8c1161645f964c8b011c9e54e6ae075) (still with a
45+
two-year estimate) to instead be part of the streams spec. While Chrome does now technically support streaming uploads,
46+
it is required that this be done in "half duplex" mode, which still prevents bidirectional streams from being useful.
47+
* https://fetch.spec.whatwg.org/#ref-for-dom-requestinit-duplex
48+
* https://github.com/whatwg/fetch/issues/1254
49+
* https://bugzilla.mozilla.org/show_bug.cgi?id=1387483
50+
51+
For these reasons, other gRPC clients such as (improbable-eng/grpc-web)[https://github.com/improbable-eng/grpc-web/]
52+
have included a websocket transport for gRPC messages. Unfortunately, that repository is no longer maintained, and some
53+
features we have found to be necessary were never shipped or never implemented.
54+
55+
This library includes two websocket transports - the first is compatible with improbable-eng/grpc-web using one
56+
websocket per stream, and the second supports using a single websocket for multiple streams to the same server (in
57+
roughly the same way that http2 would do with streams on a single socket). The first is included for compatibility with
58+
any existing proxies that support this feature - we mostly encourage the use of the second where required.
59+
60+
## Usage
61+
62+
Add `com.vertispan.protobuf:protobuf-gwt` to your project dependencies. The version will be based on the
63+
protobuf-java build being used, with an integer suffix to allow for packaging changes. For example, current
64+
released versions:
65+
66+
| grpc-java | grpc-gwt | Description |
67+
|-----------|----------|--------------------------------------------------------------------------|
68+
| 1.63.1 | 1.63.1-1 | Initial release |
69+
70+
Replace/exclude any existing grpc-java dependencies with this library. Add an inherits in your project's GWT module:
71+
```xml
72+
<inherits name="io.grpc.Grpc" />
73+
```
74+
75+
Then, use the gRPC APIs as you would normally. The gRPC-web Channel is available as `GrpcWebChannel` in the
76+
77+
## Building
78+
79+
This can be built simply with `mvn install`.
80+

pom.xml

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.vertispan.grpc</groupId>
8+
<artifactId>grpc-web-gwt</artifactId>
9+
<version>1.63.1-1-SNAPSHOT</version>
10+
<packaging>gwt-lib</packaging>
11+
12+
<properties>
13+
<grpc.version>1.63.1</grpc.version>
14+
15+
<maven.compiler.source>11</maven.compiler.source>
16+
<maven.compiler.target>11</maven.compiler.target>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
19+
<maven.gwt.plugin>1.1.0</maven.gwt.plugin>
20+
21+
<maven.gpg.plugin>1.6</maven.gpg.plugin>
22+
<maven.javadoc.plugin>3.2.0</maven.javadoc.plugin>
23+
<maven.source.plugin>3.2.1</maven.source.plugin>
24+
</properties>
25+
26+
<dependencyManagement>
27+
<dependencies>
28+
<dependency>
29+
<groupId>org.gwtproject</groupId>
30+
<artifactId>gwt</artifactId>
31+
<version>2.12.2</version>
32+
<scope>import</scope>
33+
<type>pom</type>
34+
</dependency>
35+
</dependencies>
36+
</dependencyManagement>
37+
38+
<dependencies>
39+
<dependency>
40+
<groupId>com.vertispan.protobuf</groupId>
41+
<artifactId>protobuf-gwt</artifactId>
42+
<version>3.25.4-2</version>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>com.google.guava</groupId>
47+
<artifactId>guava-gwt</artifactId>
48+
<version>33.4.0-jre</version>
49+
</dependency>
50+
51+
<dependency>
52+
<groupId>com.google.api.grpc</groupId>
53+
<artifactId>proto-google-common-protos</artifactId>
54+
<version>2.29.0</version>
55+
</dependency>
56+
<dependency>
57+
<groupId>com.google.api.grpc</groupId>
58+
<artifactId>proto-google-common-protos</artifactId>
59+
<version>2.29.0</version>
60+
<classifier>sources</classifier>
61+
</dependency>
62+
63+
64+
<dependency>
65+
<groupId>org.gwtproject</groupId>
66+
<artifactId>gwt-dev</artifactId>
67+
<scope>test</scope>
68+
</dependency>
69+
<dependency>
70+
<groupId>org.gwtproject</groupId>
71+
<artifactId>gwt-user</artifactId>
72+
<scope>test</scope>
73+
</dependency>
74+
<dependency>
75+
<groupId>junit</groupId>
76+
<artifactId>junit</artifactId>
77+
<version>4.13.2</version>
78+
<scope>test</scope>
79+
</dependency>
80+
</dependencies>
81+
82+
<build>
83+
<plugins>
84+
<plugin>
85+
<groupId>org.apache.maven.plugins</groupId>
86+
<artifactId>maven-dependency-plugin</artifactId>
87+
<version>3.8.1</version>
88+
<executions>
89+
<execution>
90+
<id>unpack</id>
91+
<goals>
92+
<goal>unpack</goal>
93+
</goals>
94+
<phase>generate-sources</phase>
95+
<configuration>
96+
<artifactItems>
97+
<artifactItem>
98+
<groupId>io.grpc</groupId>
99+
<artifactId>grpc-api</artifactId>
100+
<version>${grpc.version}</version>
101+
<type>jar</type>
102+
<classifier>sources</classifier>
103+
</artifactItem>
104+
<artifactItem>
105+
<groupId>io.grpc</groupId>
106+
<artifactId>grpc-stub</artifactId>
107+
<version>${grpc.version}</version>
108+
<type>jar</type>
109+
<classifier>sources</classifier>
110+
</artifactItem>
111+
<artifactItem>
112+
<groupId>io.grpc</groupId>
113+
<artifactId>grpc-protobuf</artifactId>
114+
<version>${grpc.version}</version>
115+
<type>jar</type>
116+
<classifier>sources</classifier>
117+
</artifactItem>
118+
<artifactItem>
119+
<groupId>io.grpc</groupId>
120+
<artifactId>grpc-protobuf-lite</artifactId>
121+
<version>${grpc.version}</version>
122+
<type>jar</type>
123+
<classifier>sources</classifier>
124+
</artifactItem>
125+
</artifactItems>
126+
<outputDirectory>src/main/java</outputDirectory>
127+
</configuration>
128+
</execution>
129+
</executions>
130+
</plugin>
131+
<plugin>
132+
<groupId>org.openrewrite.maven</groupId>
133+
<artifactId>rewrite-maven-plugin</artifactId>
134+
<version>6.8.0</version>
135+
<executions>
136+
<execution>
137+
<id>rewrite</id>
138+
<phase>process-sources</phase>
139+
<goals>
140+
<goal>run</goal>
141+
</goals>
142+
</execution>
143+
</executions>
144+
<configuration>
145+
<runPerSubmodule>true</runPerSubmodule>
146+
<activeRecipes>
147+
<recipe>com.vertispan.recipes.GrpcForGwt</recipe>
148+
</activeRecipes>
149+
<configLocation>${maven.multiModuleProjectDirectory}/rewrite.yaml</configLocation>
150+
<exclusions>
151+
<exclusion>**/src/test/**</exclusion>
152+
</exclusions>
153+
</configuration>
154+
<dependencies>
155+
<dependency>
156+
<groupId>com.vertispan.recipes</groupId>
157+
<artifactId>gwt-compatible-recipes</artifactId>
158+
<version>2.0-SNAPSHOT</version>
159+
</dependency>
160+
</dependencies>
161+
</plugin>
162+
<plugin>
163+
<groupId>net.ltgt.gwt.maven</groupId>
164+
<artifactId>gwt-maven-plugin</artifactId>
165+
<version>${maven.gwt.plugin}</version>
166+
<extensions>true</extensions>
167+
<configuration>
168+
<moduleName>io.grpc.Grpc</moduleName>
169+
</configuration>
170+
</plugin>
171+
</plugins>
172+
</build>
173+
174+
<!-- <modules>-->
175+
<!-- <module>grpc-web-gwt</module>-->
176+
<!-- <module>grpc-web-gwt</module>-->
177+
<!-- </modules>-->
178+
<profiles>
179+
<!-- release profile to create sources, javadoc, and sign all artifacts before uploading -->
180+
<profile>
181+
<id>release</id>
182+
<build>
183+
<plugins>
184+
<plugin>
185+
<groupId>org.apache.maven.plugins</groupId>
186+
<artifactId>maven-source-plugin</artifactId>
187+
<version>${maven.source.plugin}</version>
188+
<executions>
189+
<execution>
190+
<id>attach-sources</id>
191+
<goals>
192+
<goal>jar-no-fork</goal>
193+
</goals>
194+
</execution>
195+
</executions>
196+
</plugin>
197+
<plugin>
198+
<groupId>org.apache.maven.plugins</groupId>
199+
<artifactId>maven-javadoc-plugin</artifactId>
200+
<version>${maven.javadoc.plugin}</version>
201+
<executions>
202+
<execution>
203+
<id>attach-javadocs</id>
204+
<goals>
205+
<goal>jar</goal>
206+
</goals>
207+
</execution>
208+
</executions>
209+
<configuration>
210+
<doclint>none</doclint>
211+
</configuration>
212+
</plugin>
213+
<!-- see http://central.sonatype.org/pages/working-with-pgp-signatures.html for more detail -->
214+
<plugin>
215+
<groupId>org.apache.maven.plugins</groupId>
216+
<artifactId>maven-gpg-plugin</artifactId>
217+
<version>${maven.gpg.plugin}</version>
218+
<executions>
219+
<execution>
220+
<id>sign-artifacts</id>
221+
<phase>verify</phase>
222+
<goals>
223+
<goal>sign</goal>
224+
</goals>
225+
</execution>
226+
</executions>
227+
</plugin>
228+
</plugins>
229+
</build>
230+
</profile>
231+
</profiles>
232+
233+
</project>

0 commit comments

Comments
 (0)