-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial upload of a GRPC implementation for Helidon (#259)
Signed-off-by: Richard Bair <rbair23@users.noreply.github.com> Signed-off-by: litt <austin@swirldslabs.com> Co-authored-by: litt <austin@swirldslabs.com>
- Loading branch information
Showing
31 changed files
with
2,971 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
com.github.spotbugs.annotations=com.github.spotbugs:spotbugs-annotations | ||
com.google.protobuf=com.google.protobuf:protobuf-java | ||
org.antlr.antlr4.runtime=org.antlr:antlr4-runtime | ||
com.google.protobuf.util=com.google.protobuf:protobuf-java-util | ||
io.grpc.netty=io.grpc:grpc-netty | ||
io.grpc.protobuf=io.grpc:grpc-protobuf | ||
io.grpc.stub=io.grpc:grpc-stub | ||
java.annotation=javax.annotation:javax.annotation-api | ||
io.helidon.codegen.apt=io.helidon.codegen:helidon-codegen-apt | ||
io.helidon.builder.codegen=io.helidon.builder:helidon-builder-codegen |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# pbj-grpc-helidon-config | ||
|
||
This project contains just the configuration definition for the | ||
`pbj-grpc-helidon` module. | ||
|
||
Helidon modules require a "config blueprint". An annotation processor takes that | ||
"blueprint" and generates some metadata in META-INF and some code. The module | ||
then needs to compile against the generated code. Since Gradle is not capable of | ||
doing this in a single build, we have to split the configuration into a separate | ||
module. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
plugins { id("com.hedera.pbj.conventions") } | ||
|
||
mainModuleInfo { | ||
annotationProcessor("io.helidon.common.features.processor") | ||
annotationProcessor("io.helidon.config.metadata.processor") | ||
annotationProcessor("io.helidon.codegen.apt") | ||
annotationProcessor("io.helidon.builder.codegen") | ||
} | ||
|
||
tasks.named("javadoc").configure { enabled = false } | ||
|
||
publishing { | ||
publications.withType<MavenPublication>().configureEach { | ||
pom { description.set("Configuration for a Helidon gRPC plugin for PBJ") } | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
...c-helidon-config/src/main/java/com/hedera/pbj/grpc/helidon/config/PbjConfigBlueprint.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.hedera.pbj.grpc.helidon.config; | ||
|
||
import io.helidon.builder.api.Option; | ||
import io.helidon.builder.api.Prototype; | ||
import io.helidon.webserver.spi.ProtocolConfig; | ||
|
||
@Prototype.Blueprint | ||
@Prototype.Configured | ||
@Prototype.Provides(ProtocolConfig.class) | ||
interface PbjConfigBlueprint extends ProtocolConfig { | ||
/** | ||
* Default maximum message size in bytes ({@value}). | ||
* | ||
* @see #maxMessageSizeBytes() | ||
*/ | ||
int DEFAULT_MAX_MESSAGE_SIZE_BYTES = 1024 * 10; // 10KB | ||
|
||
/** | ||
* Maximum size of any message in bytes. Defaults to {@value #DEFAULT_MAX_MESSAGE_SIZE_BYTES}. | ||
* | ||
* @return the maximum number of bytes a single message can be | ||
*/ | ||
@Option.DefaultInt(DEFAULT_MAX_MESSAGE_SIZE_BYTES) | ||
@Option.Configured | ||
int maxMessageSizeBytes(); | ||
|
||
/** | ||
* Protocol configuration type. | ||
* | ||
* @return type of this configuration | ||
*/ | ||
default String type() { | ||
return "pbj"; | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
pbj-core/pbj-grpc-helidon-config/src/main/java/module-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import io.helidon.common.features.api.Feature; | ||
import io.helidon.common.features.api.HelidonFlavor; | ||
import io.helidon.common.features.api.Preview; | ||
|
||
@Preview | ||
@Feature( | ||
value = "PBJConfig", | ||
description = "WebServer gRPC-PBJ Config", | ||
in = HelidonFlavor.SE, | ||
path = {"WebServer", "PBJ"}) | ||
@SuppressWarnings({"requires-automatic"}) | ||
module com.hedera.pbj.grpc.helidon.config { | ||
requires com.hedera.pbj.runtime; | ||
requires io.helidon.webserver.http2; | ||
requires io.helidon.webserver; | ||
requires static io.helidon.common.features.api; | ||
requires static io.helidon.common.features.processor; | ||
requires static io.helidon.config.metadata.processor; | ||
|
||
exports com.hedera.pbj.grpc.helidon.config; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# PBJ GRPC Helidon | ||
|
||
This project produces a module for Helidon that enables native support for PBJ | ||
gRPC services. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
plugins { | ||
id("com.hedera.pbj.conventions") | ||
id("com.hedera.pbj.protoc") // protobuf plugin is only used for tests | ||
} | ||
|
||
// These annotation processors are used to generate config and other files that Helidon needs | ||
mainModuleInfo { | ||
annotationProcessor("io.helidon.common.features.processor") | ||
annotationProcessor("io.helidon.codegen.apt") | ||
annotationProcessor("io.helidon.builder.codegen") | ||
} | ||
|
||
testModuleInfo { | ||
requires("org.assertj.core") | ||
requires("org.junit.jupiter.api") | ||
requires("org.junit.jupiter.params") | ||
requires("io.helidon.webclient") | ||
requires("io.helidon.webserver") | ||
requires("io.helidon.webserver.http2") | ||
requires("io.helidon.webclient.http2") | ||
requires("com.google.protobuf.util") | ||
requires("io.grpc.protobuf") | ||
requires("io.grpc.netty") | ||
requires("io.grpc.stub") | ||
requiresStatic("com.github.spotbugs.annotations") | ||
requiresStatic("java.annotation") | ||
} | ||
|
||
tasks.named("compileJava") { dependsOn(":pbj-runtime:jar") } | ||
|
||
publishing { | ||
publications.withType<MavenPublication>().configureEach { | ||
pom { description.set("A Helidon gRPC plugin with PBJ") } | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
pbj-core/pbj-grpc-helidon/src/main/java/com/hedera/pbj/grpc/helidon/DeadlineDetector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.hedera.pbj.grpc.helidon; | ||
|
||
import com.hedera.pbj.runtime.grpc.GrpcStatus; | ||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import java.util.concurrent.ScheduledFuture; | ||
|
||
/** | ||
* A gRPC client may specify a 'deadline' for a request, which is measured in elapsed time from the | ||
* start of the request. If the deadline is exceeded, then the request will fail with {@link | ||
* GrpcStatus#DEADLINE_EXCEEDED}. An implementation of this interface is responsible for detecting | ||
* when the deadline has been exceeded, and invoking a callback to handle the failure. | ||
*/ | ||
interface DeadlineDetector { | ||
/** | ||
* Schedule a callback to be invoked when the deadline has been exceeded. Please note that no | ||
* operating system can actually measure elapsed time with nanosecond precision, so the actual | ||
* deadline may be exceeded by a small amount of time measuring in the microseconds or even | ||
* milliseconds. | ||
* | ||
* @param deadlineNanos The deadline, in nanoseconds, from now. | ||
* @param onDeadlineExceeded The callback to invoke when the deadline has been exceeded. | ||
* @return A {@link ScheduledFuture} that can be used to cancel the deadline. | ||
*/ | ||
@NonNull | ||
ScheduledFuture<?> scheduleDeadline(long deadlineNanos, @NonNull Runnable onDeadlineExceeded); | ||
} |
97 changes: 97 additions & 0 deletions
97
pbj-core/pbj-grpc-helidon/src/main/java/com/hedera/pbj/grpc/helidon/GrpcHeaders.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* Copyright (C) 2024 Hedera Hashgraph, LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.hedera.pbj.grpc.helidon; | ||
|
||
import static com.hedera.pbj.runtime.grpc.ServiceInterface.RequestOptions.APPLICATION_GRPC; | ||
import static io.helidon.http.HeaderValues.createCached; | ||
|
||
import com.hedera.pbj.runtime.grpc.GrpcStatus; | ||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import io.helidon.http.Header; | ||
import io.helidon.http.HeaderName; | ||
import io.helidon.http.HeaderNames; | ||
import io.helidon.http.HttpMediaType; | ||
|
||
/** Constants for gRPC related HTTP2 Headers. */ | ||
final class GrpcHeaders { | ||
static final HeaderName GRPC_TIMEOUT = HeaderNames.create("grpc-timeout"); | ||
static final HeaderName GRPC_ENCODING = HeaderNames.create("grpc-encoding"); | ||
static final HeaderName GRPC_ACCEPT_ENCODING = HeaderNames.create("grpc-accept-encoding"); | ||
static final HeaderName GRPC_MESSAGE = HeaderNames.createFromLowercase("grpc-message"); | ||
static final HeaderName GRPC_STATUS = HeaderNames.createFromLowercase("grpc-status"); | ||
static final HttpMediaType APPLICATION_GRPC_PROTO_TYPE = HttpMediaType.create(APPLICATION_GRPC); | ||
|
||
// A set of Headers with pre-cached values for the different "grpc-status" header. | ||
static final Header OK = createCached(GRPC_STATUS, GrpcStatus.OK.ordinal()); | ||
static final Header CANCELLED = createCached(GRPC_STATUS, GrpcStatus.CANCELLED.ordinal()); | ||
static final Header UNKNOWN = createCached(GRPC_STATUS, GrpcStatus.UNKNOWN.ordinal()); | ||
static final Header INVALID_ARGUMENT = | ||
createCached(GRPC_STATUS, GrpcStatus.INVALID_ARGUMENT.ordinal()); | ||
static final Header DEADLINE_EXCEEDED = | ||
createCached(GRPC_STATUS, GrpcStatus.DEADLINE_EXCEEDED.ordinal()); | ||
static final Header NOT_FOUND = createCached(GRPC_STATUS, GrpcStatus.NOT_FOUND.ordinal()); | ||
static final Header ALREADY_EXISTS = | ||
createCached(GRPC_STATUS, GrpcStatus.ALREADY_EXISTS.ordinal()); | ||
static final Header PERMISSION_DENIED = | ||
createCached(GRPC_STATUS, GrpcStatus.PERMISSION_DENIED.ordinal()); | ||
static final Header RESOURCE_EXHAUSTED = | ||
createCached(GRPC_STATUS, GrpcStatus.RESOURCE_EXHAUSTED.ordinal()); | ||
static final Header FAILED_PRECONDITION = | ||
createCached(GRPC_STATUS, GrpcStatus.FAILED_PRECONDITION.ordinal()); | ||
static final Header ABORTED = createCached(GRPC_STATUS, GrpcStatus.ABORTED.ordinal()); | ||
static final Header OUT_OF_RANGE = createCached(GRPC_STATUS, GrpcStatus.OUT_OF_RANGE.ordinal()); | ||
static final Header UNIMPLEMENTED = | ||
createCached(GRPC_STATUS, GrpcStatus.UNIMPLEMENTED.ordinal()); | ||
static final Header INTERNAL = createCached(GRPC_STATUS, GrpcStatus.INTERNAL.ordinal()); | ||
static final Header UNAVAILABLE = createCached(GRPC_STATUS, GrpcStatus.UNAVAILABLE.ordinal()); | ||
static final Header DATA_LOSS = createCached(GRPC_STATUS, GrpcStatus.DATA_LOSS.ordinal()); | ||
static final Header UNAUTHENTICATED = | ||
createCached(GRPC_STATUS, GrpcStatus.UNAUTHENTICATED.ordinal()); | ||
|
||
private GrpcHeaders() { | ||
// prevent instantiation | ||
} | ||
|
||
/** | ||
* Maps the given {@link #GRPC_STATUS} to a corresponding {@link Header}. | ||
* | ||
* @param status The status. | ||
* @return The corresponding {@link Header}. | ||
*/ | ||
@NonNull | ||
static Header header(@NonNull final GrpcStatus status) { | ||
return switch (status) { | ||
case OK -> OK; | ||
case CANCELLED -> CANCELLED; | ||
case UNKNOWN -> UNKNOWN; | ||
case INVALID_ARGUMENT -> INVALID_ARGUMENT; | ||
case DEADLINE_EXCEEDED -> DEADLINE_EXCEEDED; | ||
case NOT_FOUND -> NOT_FOUND; | ||
case ALREADY_EXISTS -> ALREADY_EXISTS; | ||
case PERMISSION_DENIED -> PERMISSION_DENIED; | ||
case RESOURCE_EXHAUSTED -> RESOURCE_EXHAUSTED; | ||
case FAILED_PRECONDITION -> FAILED_PRECONDITION; | ||
case ABORTED -> ABORTED; | ||
case OUT_OF_RANGE -> OUT_OF_RANGE; | ||
case UNIMPLEMENTED -> UNIMPLEMENTED; | ||
case INTERNAL -> INTERNAL; | ||
case UNAVAILABLE -> UNAVAILABLE; | ||
case DATA_LOSS -> DATA_LOSS; | ||
case UNAUTHENTICATED -> UNAUTHENTICATED; | ||
}; | ||
} | ||
} |
Oops, something went wrong.