├── CHANGELOG.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── rsocket-rpc-core ├── src │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── rsocket │ │ │ └── rpc │ │ │ ├── annotations │ │ │ ├── internal │ │ │ │ ├── ResourceType.java │ │ │ │ ├── GeneratedMethod.java │ │ │ │ └── Generated.java │ │ │ ├── Annotation.java │ │ │ └── Client.java │ │ │ ├── RSocketRpcService.java │ │ │ ├── tracing │ │ │ ├── Tag.java │ │ │ ├── ImmutableTag.java │ │ │ ├── SpanSubscription.java │ │ │ └── Tracing.java │ │ │ ├── exception │ │ │ ├── ServiceNotFound.java │ │ │ └── TimeoutException.java │ │ │ ├── util │ │ │ ├── StringUtil.java │ │ │ └── DnsUntil.java │ │ │ ├── AbstractRSocketService.java │ │ │ ├── rsocket │ │ │ └── RequestHandlingRSocket.java │ │ │ ├── metrics │ │ │ ├── MetricsSubscriber.java │ │ │ ├── MetricsConditionalSubscriber.java │ │ │ ├── Metrics.java │ │ │ ├── MetricsFuseableSubscriber.java │ │ │ └── MetricsFuseableConditionalSubscriber.java │ │ │ └── frames │ │ │ └── Metadata.java │ └── test │ │ └── java │ │ └── io │ │ └── rsocket │ │ └── rpc │ │ ├── util │ │ ├── StringUtilTest.java │ │ └── DnsUntilTest.java │ │ ├── tracing │ │ └── TracingTest.java │ │ └── frames │ │ └── MetadataTest.java └── build.gradle ├── rsocket-ipc-graphql ├── src │ ├── test │ │ ├── resources │ │ │ └── schema.graphqls │ │ └── java │ │ │ └── io │ │ │ └── rsocket │ │ │ └── graphql │ │ │ └── GraphQLDataFetchers.java │ └── main │ │ └── java │ │ └── io │ │ └── rsocket │ │ └── graphql │ │ ├── GraphQLErrorException.java │ │ ├── Util.java │ │ ├── VariablesDeserializer.java │ │ ├── GraphQLRequest.java │ │ ├── GraphQLServerRequestResponse.java │ │ └── GraphQLServerRequestStream.java └── build.gradle ├── rsocket-rpc-protobuf-idl ├── src │ └── main │ │ └── proto │ │ └── rsocket │ │ └── options.proto └── build.gradle ├── gradle.properties ├── rsocket-rpc-metrics-idl ├── build.gradle └── src │ └── main │ └── proto │ └── metrics.proto ├── ci ├── install_protobuf.sh └── travis.sh ├── settings.gradle ├── rsocket-ipc-core ├── src │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── rsocket │ │ │ └── ipc │ │ │ ├── SelfRegistrable.java │ │ │ ├── Marshaller.java │ │ │ ├── tracing │ │ │ ├── Tag.java │ │ │ ├── SimpleSpanContext.java │ │ │ ├── SpanSubscription.java │ │ │ └── ImmutableTag.java │ │ │ ├── Unmarshaller.java │ │ │ ├── util │ │ │ ├── IPCFunction.java │ │ │ ├── IPCChannelFunction.java │ │ │ ├── TriFunction.java │ │ │ ├── IPCFireAndForgetFunction.java │ │ │ ├── IPCRequestStreamFunction.java │ │ │ ├── IPCRequestResponseFunction.java │ │ │ ├── IPCMetricsAwareFireAndForgetFunction.java │ │ │ ├── IPCMetricsAwareRequestStreamFunction.java │ │ │ ├── IPCMetricsAwareRequestResponseFunction.java │ │ │ ├── IPCTracingAwareFireAndForgetFunction.java │ │ │ ├── IPCRequestChannelFunction.java │ │ │ ├── IPCTracingAwareRequestStreamFunction.java │ │ │ ├── IPCTracingAwareRequestResponseFunction.java │ │ │ ├── IPCTracingAndMetricsAwareFireAndForgetFunction.java │ │ │ ├── IPCTracingAndMetricsAwareRequestStreamFunction.java │ │ │ ├── IPCMetricsAwareRequestChannelFunction.java │ │ │ ├── IPCTracingAndMetricsAwareRequestResponseFunction.java │ │ │ ├── IPCTracingAwareRequestChannelFunction.java │ │ │ └── IPCTracingAndMetricsAwareRequestChannelFunction.java │ │ │ ├── MetadataEncoder.java │ │ │ ├── IPCRSocket.java │ │ │ ├── MetadataDecoder.java │ │ │ ├── exception │ │ │ └── RouteNotFound.java │ │ │ ├── Router.java │ │ │ ├── marshallers │ │ │ ├── Strings.java │ │ │ ├── Bytes.java │ │ │ └── Primitives.java │ │ │ ├── MutableRouter.java │ │ │ ├── RequestHandlingRSocket.java │ │ │ ├── encoders │ │ │ ├── PlainMetadataEncoder.java │ │ │ ├── CompositeMetadataEncoder.java │ │ │ └── DefaultMetadataEncoder.java │ │ │ ├── IPCServerRSocket.java │ │ │ ├── Functions.java │ │ │ ├── metrics │ │ │ ├── MetricsSubscriber.java │ │ │ ├── MetricsConditionalSubscriber.java │ │ │ ├── Metrics.java │ │ │ ├── MetricsFuseableSubscriber.java │ │ │ └── MetricsFuseableConditionalSubscriber.java │ │ │ ├── routing │ │ │ └── SimpleRouter.java │ │ │ ├── frames │ │ │ └── Metadata.java │ │ │ └── RoutingServerRSocket.java │ └── test │ │ └── java │ │ └── io │ │ └── rsocket │ │ └── ipc │ │ └── IntegrationTest.java └── build.gradle ├── rsocket-ipc-protobuf ├── src │ └── main │ │ └── java │ │ └── io │ │ └── rsocket │ │ └── ipc │ │ └── marshallers │ │ └── Protobuf.java └── build.gradle ├── rsocket-ipc-jackson ├── build.gradle └── src │ └── main │ └── java │ └── io │ └── rsocket │ └── ipc │ └── marshallers │ ├── Cbor.java │ └── Json.java ├── artifactory.gradle ├── docs └── motivation.md ├── dependencies-managment.gradle ├── README.md ├── rsocket-rpc-protobuf └── src │ └── java_plugin │ └── cpp │ ├── blocking_java_generator.h │ └── java_generator.h ├── bintray.gradle ├── publication.gradle ├── gradlew.bat └── .travis.yml /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsocket/rsocket-rpc-java/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/annotations/internal/ResourceType.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.annotations.internal; 2 | 3 | public enum ResourceType { 4 | CLIENT, 5 | SERVICE 6 | } 7 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/RSocketRpcService.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc; 2 | 3 | import io.rsocket.ipc.IPCRSocket; 4 | 5 | @Deprecated 6 | public interface RSocketRpcService extends IPCRSocket {} 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/test/resources/schema.graphqls: -------------------------------------------------------------------------------- 1 | type Query { 2 | bookById(id: ID): Book 3 | } 4 | 5 | type Book { 6 | id: ID 7 | name: String 8 | pageCount: Int 9 | author: Author 10 | } 11 | 12 | type Author { 13 | id: ID 14 | firstName: String 15 | lastName: String 16 | } -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/tracing/Tag.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.tracing; 2 | 3 | @Deprecated 4 | public interface Tag { 5 | static Tag of(String key, String value) { 6 | return new ImmutableTag(key, value); 7 | } 8 | 9 | String getKey(); 10 | 11 | String getValue(); 12 | } 13 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/exception/ServiceNotFound.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.exception; 2 | 3 | @Deprecated 4 | public class ServiceNotFound extends RuntimeException { 5 | private static final long serialVersionUID = 1L; 6 | 7 | public ServiceNotFound(String service) { 8 | super("can not find service " + service); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/exception/TimeoutException.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.exception; 2 | 3 | public final class TimeoutException extends Exception { 4 | 5 | public static final TimeoutException INSTANCE = new TimeoutException(); 6 | 7 | private static final long serialVersionUID = -3094321310317812063L; 8 | 9 | private TimeoutException() {} 10 | } 11 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.util; 2 | 3 | public final class StringUtil { 4 | private StringUtil() {} 5 | 6 | public static boolean hasLetters(String host) { 7 | int length = host.length(); 8 | for (int i = 0; i < length; i++) { 9 | char c = host.charAt(i); 10 | if (Character.isLetter(c)) { 11 | return true; 12 | } 13 | } 14 | 15 | return false; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/annotations/Annotation.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Meta-annotation that marks all RSocketRpc related annotations. */ 9 | @Target(ElementType.ANNOTATION_TYPE) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface Annotation {} 12 | -------------------------------------------------------------------------------- /rsocket-rpc-protobuf-idl/src/main/proto/rsocket/options.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package io.rsocket.rpc; 4 | 5 | import "google/protobuf/descriptor.proto"; 6 | 7 | option java_package = "io.rsocket.rpc"; 8 | option java_outer_classname = "RSocketOptions"; 9 | option java_multiple_files = true; 10 | 11 | extend google.protobuf.MethodOptions { 12 | RSocketMethodOptions options = 1057; 13 | } 14 | 15 | message RSocketMethodOptions { 16 | bool fire_and_forget = 1; 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=io.rsocket.rpc 2 | version=0.3.0 3 | 4 | reactorBomVersion=2020.0.0 5 | rsocketVersion=1.1.0 6 | graphqlVersion=11.0 7 | protobufVersion=3.7.1 8 | log4jVersion=2.12.1 9 | slf4jVersion=1.7.29 10 | junitVersion=5.4.0 11 | mockitoVersion=2.23.0 12 | hamcrestVersion=1.3 13 | jmhVersion=1.21 14 | micrometerVersion=1.0.6 15 | assertjVersion=3.11.1 16 | opentracingVersion=0.31.0 17 | opentracingBraveVersion=0.33.10 18 | zipkinSenderVersion=2.8.0 19 | hdrhistogramVersion=2.1.10 20 | -------------------------------------------------------------------------------- /rsocket-rpc-metrics-idl/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.google.protobuf' 3 | } 4 | 5 | description = 'RSocket RPC Metrics IDL' 6 | 7 | protobuf { 8 | generateProtoTasks { 9 | all().each { task -> 10 | task.enabled = false 11 | 12 | task.builtins { 13 | // Generates C++ code in the output folder: 14 | cpp { } 15 | 16 | // Avoid generating Java files: 17 | remove java 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /rsocket-rpc-protobuf-idl/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.google.protobuf' 3 | } 4 | 5 | description = 'RSocket RPC Protobf IDL' 6 | 7 | protobuf { 8 | generateProtoTasks { 9 | all().each { task -> 10 | task.enabled = false 11 | 12 | task.builtins { 13 | // Generates C++ code in the output folder: 14 | cpp { } 15 | 16 | // Avoid generating Java files: 17 | remove java 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /ci/install_protobuf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR=./protobuf-3.6.1 4 | 5 | if [ ! -d "$DIR" ] || [ ! "$(ls -A $DIR)" ]; then 6 | echo 'install protobuf from scratch' 7 | curl -O -L https://github.com/google/protobuf/releases/download/v3.6.1/protobuf-cpp-3.6.1.tar.gz 8 | tar -xzvf protobuf-cpp-3.6.1.tar.gz 9 | pushd protobuf-3.6.1 || exit 10 | ./autogen.sh 11 | ./configure --disable-shared && make && sudo make install 12 | popd || exit 13 | else 14 | echo 'install protobuf from cache' 15 | pushd protobuf-3.6.1 || exit 16 | sudo make install 17 | popd || exit 18 | fi -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.gradle.enterprise' version '3.1' 3 | } 4 | 5 | rootProject.name = 'rsocket-rpc-java' 6 | 7 | include 'rsocket-ipc-core' 8 | include 'rsocket-ipc-graphql' 9 | include 'rsocket-ipc-jackson' 10 | include 'rsocket-ipc-protobuf' 11 | include 'rsocket-rpc-core' 12 | include 'rsocket-rpc-metrics-idl' 13 | include 'rsocket-rpc-protobuf' 14 | include 'rsocket-rpc-protobuf-idl' 15 | 16 | 17 | 18 | gradleEnterprise { 19 | buildScan { 20 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 21 | termsOfServiceAgree = 'yes' 22 | } 23 | } -------------------------------------------------------------------------------- /rsocket-rpc-core/src/test/java/io/rsocket/rpc/util/StringUtilTest.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.util; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class StringUtilTest { 7 | @Test 8 | public void testShouldReturnTrue() { 9 | boolean l = StringUtil.hasLetters("localhost"); 10 | Assert.assertTrue(l); 11 | 12 | l = StringUtil.hasLetters("foo.com"); 13 | Assert.assertTrue(l); 14 | } 15 | 16 | @Test 17 | public void testShouldReturnFalse() { 18 | boolean l = StringUtil.hasLetters("123.123.123.123"); 19 | Assert.assertFalse(l); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/annotations/internal/GeneratedMethod.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.annotations.internal; 2 | 3 | import io.rsocket.rpc.annotations.Annotation; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Annotation 10 | @Target(ElementType.METHOD) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | public @interface GeneratedMethod { 13 | 14 | /** 15 | * Type of the class returned from the generated method. 16 | * 17 | * @return parameterized type of return class 18 | */ 19 | Class returnTypeClass(); 20 | } 21 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/AbstractRSocketService.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc; 2 | 3 | import io.rsocket.Payload; 4 | import io.rsocket.RSocket; 5 | import io.rsocket.ipc.IPCRSocket; 6 | import reactor.core.publisher.Flux; 7 | 8 | public abstract class AbstractRSocketService implements RSocket, IPCRSocket { 9 | @Override 10 | public String getService() { 11 | return getClass().getName(); 12 | } 13 | 14 | @Override 15 | public Flux requestChannel(Payload payload, Flux publisher) { 16 | return Flux.error(new UnsupportedOperationException("Request-Channel not implemented.")); 17 | } 18 | 19 | @Override 20 | public double availability() { 21 | return 1.0; 22 | } 23 | 24 | public abstract Class getServiceClass(); 25 | } 26 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/SelfRegistrable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | public interface SelfRegistrable { 19 | 20 | void selfRegister(MutableRouter router); 21 | } 22 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/main/java/io/rsocket/graphql/GraphQLErrorException.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import graphql.GraphQLError; 4 | import java.util.List; 5 | 6 | public class GraphQLErrorException extends Exception { 7 | private static final long serialVersionUID = 1; 8 | 9 | private GraphQLErrorException(String message) { 10 | super(message); 11 | } 12 | 13 | public static GraphQLErrorException from(List exceptions) { 14 | StringBuilder errorMessages = new StringBuilder("Received the following errors: \n"); 15 | 16 | for (GraphQLError g : exceptions) { 17 | errorMessages 18 | .append("Error Type: ") 19 | .append(g.getErrorType()) 20 | .append(", Message: " + g.getMessage()) 21 | .append("\n"); 22 | } 23 | 24 | return new GraphQLErrorException(errorMessages.toString()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/Marshaller.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import java.util.function.Function; 20 | 21 | public interface Marshaller extends Function { 22 | @Override 23 | ByteBuf apply(T t); 24 | } 25 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/tracing/Tag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.tracing; 17 | 18 | public interface Tag { 19 | static Tag of(String key, String value) { 20 | return new ImmutableTag(key, value); 21 | } 22 | 23 | String getKey(); 24 | 25 | String getValue(); 26 | } 27 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/Unmarshaller.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import java.util.function.Function; 20 | 21 | public interface Unmarshaller extends Function { 22 | @Override 23 | T apply(ByteBuf byteBuf); 24 | } 25 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.MetadataDecoder; 20 | 21 | public interface IPCFunction { 22 | 23 | RESULT apply(Payload payload, MetadataDecoder.Metadata metadata) throws Exception; 24 | } 25 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/test/java/io/rsocket/rpc/tracing/TracingTest.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.tracing; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.ByteBufAllocator; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | public class TracingTest { 11 | 12 | @Test 13 | public void testSerializeAndDeserialize() throws Exception { 14 | Map map = new HashMap<>(); 15 | 16 | map.put("one", "1"); 17 | map.put("two", "2"); 18 | map.put("three", "3"); 19 | map.put("four", "4"); 20 | map.put("five", "5"); 21 | 22 | ByteBuf byteBuf = Tracing.mapToByteBuf(ByteBufAllocator.DEFAULT, map); 23 | 24 | Map byteBufMap = Tracing.byteBufToMap(byteBuf); 25 | 26 | Assert.assertEquals(map.size(), byteBufMap.size()); 27 | Assert.assertEquals(map.get("two"), byteBufMap.get("two")); 28 | Assert.assertEquals(map.get("four"), byteBufMap.get("four")); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/annotations/Client.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Annotation that identifies RSocketRpc client implementations. */ 9 | @Annotation 10 | @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | public @interface Client { 13 | 14 | /** 15 | * The group name that the client will be communicating with. 16 | * 17 | * @return RSocketRpc group name 18 | */ 19 | String group(); 20 | 21 | /** 22 | * The destination name that the client will be communicating with. If not specified, requests by 23 | * this client will be load balanced across all destinations within the specified group. 24 | * 25 | * @return RSocketRpc destination name 26 | */ 27 | String destination() default ""; 28 | } 29 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/test/java/io/rsocket/rpc/util/DnsUntilTest.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.util; 2 | 3 | import java.net.InetSocketAddress; 4 | import java.net.SocketAddress; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | public class DnsUntilTest { 9 | @Test 10 | public void testShouldReturnIpAddress() { 11 | InetSocketAddress inetSocketAddress = DnsUntil.toIpAddress("localhost", 8001); 12 | InetSocketAddress unresolved = InetSocketAddress.createUnresolved("127.0.0.1", 8001); 13 | Assert.assertTrue(unresolved.equals(inetSocketAddress)); 14 | } 15 | 16 | @Test 17 | public void testShouldReturnIpAddressFromHostName() { 18 | InetSocketAddress inetSocketAddress = InetSocketAddress.createUnresolved("localhost", 8001); 19 | SocketAddress socketAddress = DnsUntil.checkInetSocketAddress(inetSocketAddress); 20 | InetSocketAddress unresolved = InetSocketAddress.createUnresolved("127.0.0.1", 8001); 21 | Assert.assertTrue(socketAddress.equals(unresolved)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/annotations/internal/Generated.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.annotations.internal; 2 | 3 | import io.rsocket.rpc.annotations.Annotation; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Annotation that identifies RSocket RPC generated services and stores metadata that can be used by 11 | * dependency injection frameworks and custom annotation processors. 12 | */ 13 | @Annotation 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Generated { 17 | 18 | /** 19 | * Type of the generated RSocketRpc resource. 20 | * 21 | * @return type of generated resource 22 | */ 23 | ResourceType type(); 24 | 25 | /** 26 | * Class of the RSocketRpc service hosted by the annotated class. 27 | * 28 | * @return RSocketRpc service class 29 | */ 30 | Class idlClass(); 31 | } 32 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/MetadataEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.opentracing.SpanContext; 20 | 21 | @FunctionalInterface 22 | public interface MetadataEncoder { 23 | 24 | ByteBuf encode(ByteBuf metadata, SpanContext spanContext, String baseRoute, String... parts); 25 | } 26 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/IPCRSocket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.RSocket; 20 | import reactor.core.publisher.Flux; 21 | 22 | public interface IPCRSocket extends RSocket, SelfRegistrable { 23 | String getService(); 24 | 25 | Flux requestChannel(Payload payload, Flux publisher); 26 | } 27 | -------------------------------------------------------------------------------- /rsocket-ipc-protobuf/src/main/java/io/rsocket/ipc/marshallers/Protobuf.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.ipc.marshallers; 2 | 3 | import com.google.protobuf.Message; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.ByteBufAllocator; 6 | import io.netty.buffer.ByteBufOutputStream; 7 | import io.rsocket.ipc.Marshaller; 8 | import io.rsocket.ipc.Unmarshaller; 9 | import java.util.function.Function; 10 | import reactor.core.Exceptions; 11 | 12 | public class Protobuf { 13 | @SuppressWarnings("unused") 14 | public static Marshaller marshaller(Class clazz) { 15 | return t -> { 16 | ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(); 17 | ByteBufOutputStream bos = new ByteBufOutputStream(buffer); 18 | try { 19 | t.writeTo(bos); 20 | } catch (Exception e) { 21 | throw Exceptions.propagate(e); 22 | } 23 | return buffer; 24 | }; 25 | } 26 | 27 | public static Unmarshaller unmarshaller(Function f) { 28 | return f::apply; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCChannelFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.MetadataDecoder; 20 | import reactor.core.publisher.Flux; 21 | 22 | public interface IPCChannelFunction { 23 | 24 | Flux apply(Flux source, Payload payload, MetadataDecoder.Metadata metadata) 25 | throws Exception; 26 | } 27 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/TriFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | @FunctionalInterface 19 | public interface TriFunction { 20 | /** 21 | * Applies this function to the given arguments. 22 | * 23 | * @param t the first function argument 24 | * @param u the second function argument 25 | * @param v the third function argument 26 | * @return the function result 27 | */ 28 | R apply(T t, U u, V v); 29 | } 30 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/rsocket/RequestHandlingRSocket.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.rsocket; 2 | 3 | import io.rsocket.ipc.SelfRegistrable; 4 | import io.rsocket.rpc.RSocketRpcService; 5 | 6 | @Deprecated 7 | public class RequestHandlingRSocket extends io.rsocket.ipc.RequestHandlingRSocket { 8 | 9 | public RequestHandlingRSocket(RSocketRpcService... services) { 10 | super(); 11 | for (RSocketRpcService rsocketService : services) { 12 | withEndpoint(rsocketService); 13 | } 14 | } 15 | 16 | /** 17 | * @deprecated in favour of {@link #withService(RSocketRpcService)} 18 | * @param rsocketService 19 | */ 20 | @Deprecated 21 | public void addService(RSocketRpcService rsocketService) { 22 | withEndpoint(rsocketService); 23 | } 24 | 25 | @Deprecated 26 | public RequestHandlingRSocket withService(RSocketRpcService rSocketRpcService) { 27 | return withEndpoint(rSocketRpcService); 28 | } 29 | 30 | @Override 31 | public RequestHandlingRSocket withEndpoint(SelfRegistrable selfRegistrable) { 32 | return (RequestHandlingRSocket) super.withEndpoint(selfRegistrable); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/MetadataDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.opentracing.SpanContext; 20 | 21 | @FunctionalInterface 22 | public interface MetadataDecoder { 23 | 24 | Metadata decode(ByteBuf metadataByteBuf) throws Exception; 25 | 26 | interface Metadata { 27 | ByteBuf metadata(); 28 | 29 | String route(); 30 | 31 | SpanContext spanContext(); 32 | 33 | boolean isComposite(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rsocket-ipc-protobuf/build.gradle: -------------------------------------------------------------------------------- 1 | description = 'RSocket IPC Protobuf Support' 2 | 3 | dependencies { 4 | api project (':rsocket-ipc-core') 5 | 6 | implementation 'com.google.protobuf:protobuf-java' 7 | implementation 'org.slf4j:slf4j-api' 8 | 9 | testImplementation 'io.opentracing.brave:brave-opentracing' 10 | testImplementation 'junit:junit' 11 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 12 | testImplementation 'org.junit.vintage:junit-vintage-engine' 13 | 14 | testImplementation 'javax.inject:javax.inject' 15 | testImplementation 'io.projectreactor:reactor-test' 16 | testImplementation 'com.google.protobuf:protobuf-java' 17 | testImplementation 'org.hdrhistogram:HdrHistogram' 18 | testImplementation 'org.apache.logging.log4j:log4j-api' 19 | testImplementation 'org.apache.logging.log4j:log4j-core' 20 | testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl' 21 | testImplementation 'io.rsocket:rsocket-transport-netty' 22 | testImplementation 'io.rsocket:rsocket-transport-local' 23 | testImplementation 'org.mockito:mockito-core' 24 | testImplementation 'io.zipkin.reporter2:zipkin-sender-okhttp3' 25 | } -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/tracing/SimpleSpanContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.tracing; 17 | 18 | import io.opentracing.SpanContext; 19 | import java.util.Map; 20 | 21 | public class SimpleSpanContext implements SpanContext { 22 | final Map baggage; 23 | 24 | public SimpleSpanContext(Map baggage) { 25 | this.baggage = baggage; 26 | } 27 | 28 | @Override 29 | public Iterable> baggageItems() { 30 | return baggage.entrySet(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/exception/RouteNotFound.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.exception; 17 | 18 | import io.rsocket.exceptions.CustomRSocketException; 19 | 20 | public class RouteNotFound extends CustomRSocketException { 21 | private static final long serialVersionUID = 1L; 22 | 23 | public RouteNotFound(String route) { 24 | super(0x00000404, "Handler not found for route [" + route + "]"); 25 | } 26 | 27 | @Override 28 | public synchronized Throwable fillInStackTrace() { 29 | return this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/util/DnsUntil.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.util; 2 | 3 | import static io.rsocket.rpc.util.StringUtil.hasLetters; 4 | 5 | import java.net.InetAddress; 6 | import java.net.InetSocketAddress; 7 | import java.net.SocketAddress; 8 | import java.net.UnknownHostException; 9 | 10 | public final class DnsUntil { 11 | private DnsUntil() {} 12 | 13 | public static SocketAddress checkInetSocketAddress(SocketAddress address) { 14 | InetSocketAddress inetSocketAddress = (InetSocketAddress) address; 15 | String hostName = inetSocketAddress.getHostName(); 16 | if (hasLetters(hostName)) { 17 | return toIpAddress(hostName, inetSocketAddress.getPort()); 18 | } else { 19 | return inetSocketAddress; 20 | } 21 | } 22 | 23 | public static InetSocketAddress toIpAddress(String hostName, int port) { 24 | InetSocketAddress socketAddress; 25 | try { 26 | InetAddress address = InetAddress.getByName(hostName); 27 | String ipAddress = address.getHostAddress(); 28 | socketAddress = InetSocketAddress.createUnresolved(ipAddress, port); 29 | } catch (UnknownHostException e) { 30 | throw new RuntimeException(e); 31 | } 32 | 33 | return socketAddress; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/tracing/ImmutableTag.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.tracing; 2 | 3 | import static java.util.Objects.requireNonNull; 4 | 5 | import io.micrometer.core.lang.Nullable; 6 | import java.util.Objects; 7 | 8 | @Deprecated 9 | class ImmutableTag implements Tag { 10 | private String key; 11 | private String value; 12 | 13 | public ImmutableTag(String key, String value) { 14 | requireNonNull(key); 15 | requireNonNull(value); 16 | this.key = key; 17 | this.value = value; 18 | } 19 | 20 | @Override 21 | public String getKey() { 22 | return key; 23 | } 24 | 25 | @Override 26 | public String getValue() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public boolean equals(@Nullable Object o) { 32 | if (this == o) return true; 33 | if (o == null || getClass() != o.getClass()) return false; 34 | Tag that = (Tag) o; 35 | return Objects.equals(key, that.getKey()) && Objects.equals(value, that.getValue()); 36 | } 37 | 38 | @Override 39 | public int hashCode() { 40 | return Objects.hash(key, value); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "ImmutableTag{" + "key='" + key + '\'' + ", value='" + value + '\'' + '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/Router.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.util.IPCChannelFunction; 20 | import io.rsocket.ipc.util.IPCFunction; 21 | import reactor.core.publisher.Flux; 22 | import reactor.core.publisher.Mono; 23 | 24 | public interface Router { 25 | 26 | IPCFunction> routeFireAndForget(String route); 27 | 28 | IPCFunction> routeRequestResponse(String route); 29 | 30 | IPCFunction> routeRequestStream(String route); 31 | 32 | IPCChannelFunction routeRequestChannel(String route); 33 | } 34 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/marshallers/Strings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.marshallers; 17 | 18 | import io.netty.buffer.ByteBufAllocator; 19 | import io.netty.buffer.ByteBufUtil; 20 | import io.rsocket.ipc.Marshaller; 21 | import io.rsocket.ipc.Unmarshaller; 22 | import java.nio.charset.StandardCharsets; 23 | 24 | public final class Strings { 25 | private Strings() {} 26 | 27 | public static Marshaller marshaller() { 28 | return s -> ByteBufUtil.writeUtf8(ByteBufAllocator.DEFAULT, s); 29 | } 30 | 31 | public static Unmarshaller unmarshaller() { 32 | return byteBuf -> byteBuf.toString(StandardCharsets.UTF_8); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rsocket-ipc-core/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'io.spring.dependency-management' 3 | } 4 | 5 | description = 'RSocket IPC Library' 6 | 7 | dependencies { 8 | implementation 'org.slf4j:slf4j-api' 9 | 10 | api 'io.opentracing:opentracing-api' 11 | api 'javax.inject:javax.inject' 12 | api 'javax.annotation:javax.annotation-api' 13 | api 'io.rsocket:rsocket-core' 14 | api 'io.micrometer:micrometer-core' 15 | 16 | testImplementation 'io.opentracing.brave:brave-opentracing' 17 | testImplementation 'junit:junit' 18 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 19 | testImplementation 'org.junit.vintage:junit-vintage-engine' 20 | 21 | testImplementation 'javax.inject:javax.inject' 22 | testImplementation 'io.projectreactor:reactor-test' 23 | testImplementation 'com.google.protobuf:protobuf-java' 24 | testImplementation 'org.hdrhistogram:HdrHistogram' 25 | testImplementation 'org.apache.logging.log4j:log4j-api' 26 | testImplementation 'org.apache.logging.log4j:log4j-core' 27 | testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl' 28 | testImplementation 'io.rsocket:rsocket-transport-netty' 29 | testImplementation 'io.rsocket:rsocket-transport-local' 30 | testImplementation 'org.mockito:mockito-core' 31 | testImplementation 'io.zipkin.reporter2:zipkin-sender-okhttp3' 32 | } -------------------------------------------------------------------------------- /rsocket-ipc-jackson/build.gradle: -------------------------------------------------------------------------------- 1 | description = 'RSocket IPC Jackson Support' 2 | 3 | dependencies { 4 | api project (':rsocket-ipc-core') 5 | 6 | implementation 'com.fasterxml.jackson.core:jackson-core:2.9.9' 7 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.9' 8 | implementation 'com.fasterxml.jackson.module:jackson-module-afterburner:2.9.9' 9 | compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.9.9' 10 | 11 | testImplementation 'io.opentracing.brave:brave-opentracing' 12 | testImplementation 'junit:junit' 13 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 14 | testImplementation 'org.junit.vintage:junit-vintage-engine' 15 | 16 | testImplementation 'javax.inject:javax.inject' 17 | testImplementation 'io.projectreactor:reactor-test' 18 | testImplementation 'com.google.protobuf:protobuf-java' 19 | testImplementation 'org.hdrhistogram:HdrHistogram' 20 | testImplementation 'org.apache.logging.log4j:log4j-api' 21 | testImplementation 'org.apache.logging.log4j:log4j-core' 22 | testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl' 23 | testImplementation 'io.rsocket:rsocket-transport-netty' 24 | testImplementation 'io.rsocket:rsocket-transport-local' 25 | testImplementation 'org.mockito:mockito-core' 26 | testImplementation 'io.zipkin.reporter2:zipkin-sender-okhttp3' 27 | } -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/MutableRouter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.util.IPCChannelFunction; 20 | import io.rsocket.ipc.util.IPCFunction; 21 | import reactor.core.publisher.Flux; 22 | import reactor.core.publisher.Mono; 23 | 24 | public interface MutableRouter> extends Router { 25 | SELF withFireAndForgetRoute(String route, IPCFunction> function); 26 | 27 | SELF withRequestResponseRoute(String route, IPCFunction> function); 28 | 29 | SELF withRequestStreamRoute(String route, IPCFunction> function); 30 | 31 | SELF withRequestChannelRoute(String route, IPCChannelFunction function); 32 | } 33 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/RequestHandlingRSocket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.opentracing.Tracer; 19 | import io.rsocket.ipc.routing.SimpleRouter; 20 | 21 | public class RequestHandlingRSocket extends RoutingServerRSocket { 22 | 23 | public RequestHandlingRSocket() { 24 | super(new SimpleRouter()); 25 | } 26 | 27 | public RequestHandlingRSocket(Tracer tracer) { 28 | super(tracer, new SimpleRouter()); 29 | } 30 | 31 | public RequestHandlingRSocket(MetadataDecoder decoder) { 32 | super(decoder, new SimpleRouter()); 33 | } 34 | 35 | public RequestHandlingRSocket withEndpoint(SelfRegistrable selfRegistrable) { 36 | selfRegistrable.selfRegister((MutableRouter) router); 37 | return this; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/main/java/io/rsocket/graphql/Util.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import graphql.ExecutionInput; 4 | import graphql.ExecutionResult; 5 | import graphql.GraphQL; 6 | import graphql.execution.ExecutionId; 7 | import graphql.execution.instrumentation.Instrumentation; 8 | import graphql.schema.GraphQLSchema; 9 | import io.netty.buffer.ByteBuf; 10 | import java.util.concurrent.CompletableFuture; 11 | import org.dataloader.DataLoaderRegistry; 12 | 13 | class Util { 14 | private Util() {} 15 | 16 | static CompletableFuture executeGraphQLRequest( 17 | GraphQLRequest request, 18 | ByteBuf byteBuf, 19 | DataLoaderRegistry registry, 20 | GraphQLSchema graphQLSchema, 21 | Instrumentation instrumentation) { 22 | ExecutionInput.Builder builder = 23 | ExecutionInput.newExecutionInput() 24 | .query(request.getQuery()) 25 | .operationName(request.getOperationName()) 26 | .variables(request.getVariables()) 27 | .context(byteBuf) 28 | .executionId(ExecutionId.generate()); 29 | 30 | if (registry != null) { 31 | builder.dataLoaderRegistry(registry); 32 | } 33 | 34 | ExecutionInput executionInput = builder.build(); 35 | 36 | return GraphQL.newGraphQL(graphQLSchema) 37 | .instrumentation(instrumentation) 38 | .build() 39 | .executeAsync(executionInput); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/build.gradle: -------------------------------------------------------------------------------- 1 | description = 'RSocket GraphQL using IPC Library' 2 | 3 | dependencies { 4 | api project (':rsocket-ipc-jackson') 5 | 6 | implementation 'com.fasterxml.jackson.core:jackson-core:2.9.9' 7 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.9' 8 | implementation 'com.fasterxml.jackson.module:jackson-module-afterburner:2.9.9' 9 | compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.9.9' 10 | 11 | implementation 'com.graphql-java:graphql-java:13.0' // NEW 12 | 13 | testImplementation 'io.opentracing.brave:brave-opentracing' 14 | testImplementation 'junit:junit' 15 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 16 | testImplementation 'org.junit.vintage:junit-vintage-engine' 17 | 18 | testImplementation 'javax.inject:javax.inject' 19 | testImplementation 'io.projectreactor:reactor-test' 20 | testImplementation 'com.google.protobuf:protobuf-java' 21 | testImplementation 'org.hdrhistogram:HdrHistogram' 22 | testImplementation 'org.apache.logging.log4j:log4j-api' 23 | testImplementation 'org.apache.logging.log4j:log4j-core' 24 | testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl' 25 | testImplementation 'io.rsocket:rsocket-transport-netty' 26 | testImplementation 'io.rsocket:rsocket-transport-local' 27 | testImplementation 'org.mockito:mockito-core' 28 | testImplementation 'io.zipkin.reporter2:zipkin-sender-okhttp3' 29 | } -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/main/java/io/rsocket/graphql/VariablesDeserializer.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.ObjectCodec; 5 | import com.fasterxml.jackson.core.type.TypeReference; 6 | import com.fasterxml.jackson.databind.DeserializationContext; 7 | import com.fasterxml.jackson.databind.JsonDeserializer; 8 | import java.io.IOException; 9 | import java.util.Map; 10 | 11 | /** @author Andrew Potter */ 12 | public class VariablesDeserializer extends JsonDeserializer> { 13 | @Override 14 | public Map deserialize(JsonParser p, DeserializationContext ctxt) 15 | throws IOException { 16 | return deserializeVariablesObject(p.readValueAs(Object.class), p.getCodec()); 17 | } 18 | 19 | public static Map deserializeVariablesObject( 20 | Object variables, ObjectCodec codec) { 21 | if (variables instanceof Map) { 22 | @SuppressWarnings("unchecked") 23 | Map genericVariables = (Map) variables; 24 | return genericVariables; 25 | } else if (variables instanceof String) { 26 | try { 27 | return codec.readValue( 28 | codec.getFactory().createParser((String) variables), 29 | new TypeReference>() {}); 30 | } catch (IOException e) { 31 | throw new RuntimeException(e); 32 | } 33 | } else { 34 | throw new RuntimeException("variables should be either an object or a string"); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /artifactory.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | if (project.hasProperty('bintrayUser') && project.hasProperty('bintrayKey')) { 18 | 19 | subprojects { 20 | plugins.withId('com.jfrog.artifactory') { 21 | artifactory { 22 | contextUrl = 'https://oss.jfrog.org' 23 | publish { 24 | contextUrl = 'https://oss.jfrog.org' 25 | 26 | repository { 27 | repoKey = 'oss-snapshot-local' 28 | 29 | // Credentials for oss.jfrog.org are a user's Bintray credentials 30 | username = project.property('bintrayUser') 31 | password = project.property('bintrayKey') 32 | } 33 | 34 | defaults { 35 | publications('maven') 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/main/java/io/rsocket/graphql/GraphQLRequest.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** @author Andrew Potter */ 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class GraphQLRequest { 11 | private String query; 12 | 13 | @JsonDeserialize(using = VariablesDeserializer.class) 14 | private Map variables = new HashMap<>(); 15 | 16 | private String operationName; 17 | 18 | public GraphQLRequest() {} 19 | 20 | public GraphQLRequest(String query, Map variables, String operationName) { 21 | this.query = query; 22 | this.operationName = operationName; 23 | if (variables != null) { 24 | this.variables = variables; 25 | } 26 | } 27 | 28 | public String getQuery() { 29 | return query; 30 | } 31 | 32 | public void setQuery(String query) { 33 | this.query = query; 34 | } 35 | 36 | public Map getVariables() { 37 | return variables; 38 | } 39 | 40 | public void setVariables(Map variables) { 41 | if (variables != null) { 42 | this.variables = variables; 43 | } 44 | } 45 | 46 | public String getOperationName() { 47 | if (operationName != null && !operationName.isEmpty()) { 48 | return operationName; 49 | } 50 | 51 | return null; 52 | } 53 | 54 | public void setOperationName(String operationName) { 55 | this.operationName = operationName; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /rsocket-rpc-metrics-idl/src/main/proto/metrics.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package io.rsocket.rpc.metrics.om; 4 | 5 | option java_package = "io.rsocket.rpc.metrics.om"; 6 | option java_outer_classname = "Metrics"; 7 | option java_multiple_files = true; 8 | 9 | enum MeterType { 10 | COUNTER = 0; 11 | GAUGE = 1; 12 | LONG_TASK_TIMER = 2; 13 | TIMER = 3; 14 | DISTRIBUTION_SUMMARY = 4; 15 | OTHER = 5; 16 | } 17 | 18 | message MeterTag { 19 | string key = 1; 20 | string value = 2; 21 | } 22 | 23 | message MeterId { 24 | string name = 1; 25 | repeated MeterTag tag = 2; 26 | MeterType type = 3; 27 | string description = 4; 28 | string baseUnit = 5; 29 | } 30 | 31 | enum MeterStatistic { 32 | TOTAL = 0; 33 | TOTAL_TIME = 1; 34 | COUNT = 2; 35 | MAX = 3; 36 | VALUE = 4; 37 | UNKNOWN = 5; 38 | ACTIVE_TASKS = 6; 39 | DURATION = 7; 40 | } 41 | 42 | message MeterMeasurement { 43 | double value = 1; 44 | MeterStatistic statistic = 2; 45 | } 46 | 47 | message Meter { 48 | MeterId id = 1; 49 | repeated MeterMeasurement measure = 2; 50 | } 51 | 52 | message MetricsSnapshot { 53 | map tags = 1; 54 | repeated Meter meters = 2; 55 | } 56 | 57 | message Skew { 58 | int64 timestamp = 1; 59 | } 60 | 61 | service MetricsSnapshotHandler { 62 | // Returns a Hello World Message 63 | rpc StreamMetrics (stream MetricsSnapshot) returns (stream Skew) {} 64 | } 65 | -------------------------------------------------------------------------------- /docs/motivation.md: -------------------------------------------------------------------------------- 1 | # Motivation for RSocket-RPC 2 | 3 | As many of us might know, there is an RPC project called gRPC. The gRPC project allows us easily setup RPC communication between several services. Even though the communication is reactive, asynchronous and non-blocking, the current implementation of gRPC does not allow to achieve one of the central goals for Reactive Streams - Backpressure control. At that moment, gRPC uses HTTP/2 as a transport and employee its flow control in order to achieve backpressure. HTTP/2 flow allows only byte-acknowledgment-based flow control, which means there is no specific part of the protocol that can say how many logical-elements a consumer ready to accept. That limitation may impact system stability under high-load which may be either performance degradation or resilience degradation. 4 | 5 | Therefore, RSocket-RPC comes for rescue. The central idea of RSocket-RPC is to provide identical communication features as there are in gRPC. As we might remember, gRPC offers Protocol Buffer integration, which along with common data structures generation, allows generating stubs for services. The RSocket-RPC library employees the same techniques and provides the same plugin for stub generation. In turn, RSocket-RPC uses RSocket protocol as an application level transport for message exchange which includes out-of-the-box logical-elements-based backpressure control, therefore offers better resilience without impact on system's performance. 6 | 7 | Also, RSocket-RPC is language agnostic and at the current moment provides integration with [JavaScript](https://github.com/rsocket/rsocket-rpc-js) as well as with [Java](https://github.com/rsocket/rsocket-rpc-java). -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/tracing/SpanSubscription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.rsocket.ipc.tracing; 18 | 19 | import org.reactivestreams.Subscription; 20 | import reactor.core.CoreSubscriber; 21 | import reactor.core.Fuseable; 22 | 23 | /** 24 | * A {@link SpanSubscription} is a {@link Subscription} that fakes being {@link Fuseable} 25 | * (implementing {@link Fuseable.QueueSubscription} with default no-op methods and always 26 | * negotiating fusion to be {@link Fuseable#NONE}). 27 | * 28 | * @author Marcin Grzejszczak 29 | */ 30 | interface SpanSubscription 31 | extends Subscription, CoreSubscriber, Fuseable.QueueSubscription { 32 | 33 | @Override 34 | default T poll() { 35 | return null; 36 | } 37 | 38 | @Override 39 | default int requestFusion(int i) { 40 | return Fuseable.NONE; // always negotiate to no fusion 41 | } 42 | 43 | @Override 44 | default int size() { 45 | return 0; 46 | } 47 | 48 | @Override 49 | default boolean isEmpty() { 50 | return true; 51 | } 52 | 53 | @Override 54 | default void clear() { 55 | // NO-OP 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/encoders/PlainMetadataEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.encoders; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufAllocator; 20 | import io.opentracing.SpanContext; 21 | import io.rsocket.ipc.MetadataEncoder; 22 | import java.nio.charset.Charset; 23 | 24 | public class PlainMetadataEncoder implements MetadataEncoder { 25 | 26 | final CharSequence delimiter; 27 | private final Charset charset; 28 | 29 | public PlainMetadataEncoder(CharSequence delimiter, Charset charset) { 30 | this.delimiter = delimiter; 31 | this.charset = charset; 32 | } 33 | 34 | @Override 35 | public ByteBuf encode(ByteBuf metadata, SpanContext context, String baseRoute, String... parts) { 36 | ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(); 37 | 38 | StringBuilder stringBuilder = new StringBuilder(); 39 | 40 | stringBuilder.append(baseRoute); 41 | 42 | for (String part : parts) { 43 | stringBuilder.append(delimiter).append(part); 44 | } 45 | 46 | buffer.writeCharSequence(stringBuilder, charset); 47 | 48 | return buffer; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rsocket-ipc-jackson/src/main/java/io/rsocket/ipc/marshallers/Cbor.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.ipc.marshallers; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.dataformat.cbor.CBORFactory; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.buffer.ByteBufAllocator; 7 | import io.netty.buffer.ByteBufInputStream; 8 | import io.netty.buffer.ByteBufOutputStream; 9 | import io.rsocket.ipc.Marshaller; 10 | import io.rsocket.ipc.Unmarshaller; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.OutputStream; 14 | import reactor.core.Exceptions; 15 | 16 | public class Cbor { 17 | private final ObjectMapper mapper; 18 | 19 | private Cbor() { 20 | CBORFactory f = new CBORFactory(); 21 | mapper = new ObjectMapper(f); 22 | } 23 | 24 | private static class Lazy { 25 | private static Cbor INSTANCE = new Cbor(); 26 | } 27 | 28 | public static Cbor getInstance() { 29 | return Lazy.INSTANCE; 30 | } 31 | 32 | @SuppressWarnings("unused") 33 | public static Marshaller marshaller(Class clazz) { 34 | return t -> { 35 | ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(); 36 | OutputStream bos = new ByteBufOutputStream(byteBuf); 37 | try { 38 | Cbor.getInstance().mapper.writeValue(bos, t); 39 | } catch (IOException e) { 40 | throw Exceptions.propagate(e); 41 | } 42 | return byteBuf; 43 | }; 44 | } 45 | 46 | public static Unmarshaller unmarshaller(Class clazz) { 47 | return byteBuf -> { 48 | InputStream bis = new ByteBufInputStream(byteBuf); 49 | try { 50 | return Cbor.getInstance().mapper.readValue(bis, clazz); 51 | } catch (Throwable t) { 52 | throw Exceptions.propagate(t); 53 | } 54 | }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/tracing/SpanSubscription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.rsocket.rpc.tracing; 18 | 19 | import org.reactivestreams.Subscription; 20 | import reactor.core.CoreSubscriber; 21 | import reactor.core.Fuseable; 22 | 23 | /** 24 | * A {@link SpanSubscription} is a {@link Subscription} that fakes being {@link Fuseable} 25 | * (implementing {@link reactor.core.Fuseable.QueueSubscription} with default no-op methods and 26 | * always negotiating fusion to be {@link Fuseable#NONE}). 27 | * 28 | * @author Marcin Grzejszczak 29 | */ 30 | @Deprecated 31 | interface SpanSubscription 32 | extends Subscription, CoreSubscriber, Fuseable.QueueSubscription { 33 | 34 | @Override 35 | default T poll() { 36 | return null; 37 | } 38 | 39 | @Override 40 | default int requestFusion(int i) { 41 | return Fuseable.NONE; // always negotiate to no fusion 42 | } 43 | 44 | @Override 45 | default int size() { 46 | return 0; 47 | } 48 | 49 | @Override 50 | default boolean isEmpty() { 51 | return true; 52 | } 53 | 54 | @Override 55 | default void clear() { 56 | // NO-OP 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCFireAndForgetFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.Functions; 20 | import io.rsocket.ipc.Marshaller; 21 | import io.rsocket.ipc.MetadataDecoder; 22 | import io.rsocket.ipc.Unmarshaller; 23 | import reactor.core.publisher.Mono; 24 | 25 | @SuppressWarnings("rawtypes") 26 | public class IPCFireAndForgetFunction implements IPCFunction> { 27 | 28 | final String route; 29 | final Unmarshaller unmarshaller; 30 | final Marshaller marshaller; 31 | final Functions.FireAndForget fnf; 32 | 33 | public IPCFireAndForgetFunction( 34 | String route, Unmarshaller unmarshaller, Marshaller marshaller, Functions.FireAndForget fnf) { 35 | this.route = route; 36 | this.unmarshaller = unmarshaller; 37 | this.marshaller = marshaller; 38 | this.fnf = fnf; 39 | } 40 | 41 | @Override 42 | @SuppressWarnings("unchecked") 43 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 44 | Object input = unmarshaller.apply(payload.sliceData()); 45 | return fnf.apply(input, metadata.metadata()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rsocket-ipc-jackson/src/main/java/io/rsocket/ipc/marshallers/Json.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.ipc.marshallers; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.module.afterburner.AfterburnerModule; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.buffer.ByteBufAllocator; 7 | import io.netty.buffer.ByteBufInputStream; 8 | import io.netty.buffer.ByteBufOutputStream; 9 | import io.rsocket.ipc.Marshaller; 10 | import io.rsocket.ipc.Unmarshaller; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.OutputStream; 14 | import reactor.core.Exceptions; 15 | 16 | public class Json { 17 | private final ObjectMapper mapper; 18 | 19 | private Json() { 20 | mapper = new ObjectMapper(); 21 | mapper.registerModule(new AfterburnerModule()); 22 | } 23 | 24 | private static class Lazy { 25 | private static Json INSTANCE = new Json(); 26 | } 27 | 28 | public static Json getInstance() { 29 | return Lazy.INSTANCE; 30 | } 31 | 32 | @SuppressWarnings("unused") 33 | public static Marshaller marshaller(Class clazz) { 34 | return t -> { 35 | ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(); 36 | OutputStream bos = new ByteBufOutputStream(byteBuf); 37 | try { 38 | Json.getInstance().mapper.writeValue(bos, t); 39 | } catch (IOException e) { 40 | throw Exceptions.propagate(e); 41 | } 42 | return byteBuf; 43 | }; 44 | } 45 | 46 | public static Unmarshaller unmarshaller(Class clazz) { 47 | return byteBuf -> { 48 | InputStream bis = new ByteBufInputStream(byteBuf); 49 | try { 50 | return Json.getInstance().mapper.readValue(bis, clazz); 51 | } catch (Throwable t) { 52 | throw Exceptions.propagate(t); 53 | } 54 | }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /dependencies-managment.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'io.spring.dependency-management' 2 | 3 | dependencyManagement { 4 | imports { 5 | mavenBom "io.projectreactor:reactor-bom:$reactorBomVersion" 6 | mavenBom "io.rsocket:rsocket-bom:$rsocketVersion" 7 | mavenBom "org.junit:junit-bom:$junitVersion" 8 | mavenBom "com.google.protobuf:protobuf-bom:$protobufVersion" 9 | } 10 | 11 | dependencies { 12 | dependency "javax.inject:javax.inject:1" 13 | dependency "javax.annotation:javax.annotation-api:1.2" 14 | 15 | dependency "com.google.protobuf:protoc:3.6.1" 16 | 17 | dependencySet(group: 'org.apache.logging.log4j', version: log4jVersion) { 18 | entry "log4j-api" 19 | entry "log4j-core" 20 | entry "log4j-slf4j-impl" 21 | } 22 | 23 | dependency "org.slf4j:slf4j-api:$slf4jVersion" 24 | dependency "org.slf4j:slf4j-simple:$slf4jVersion" 25 | 26 | dependency "io.micrometer:micrometer-core:$micrometerVersion" 27 | dependency "io.opentracing:opentracing-api:$opentracingVersion" 28 | dependency "io.opentracing.brave:brave-opentracing:$opentracingBraveVersion" 29 | dependency "io.zipkin.reporter2:zipkin-sender-okhttp3:$zipkinSenderVersion" 30 | 31 | // TODO: Remove after JUnit5 migration 32 | // TEST DEPENDENCIES 33 | 34 | dependency 'junit:junit:4.12' 35 | 36 | dependency "org.mockito:mockito-core:$mockitoVersion" 37 | dependency "org.hamcrest:hamcrest-library:$hamcrestVersion" 38 | dependency "org.assertj:assertj-core:$assertjVersion" 39 | dependency "org.hdrhistogram:HdrHistogram:$hdrhistogramVersion" 40 | 41 | dependencySet(group: 'org.openjdk.jmh', version: jmhVersion) { 42 | entry 'jmh-core' 43 | entry 'jmh-generator-annprocess' 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/marshallers/Bytes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.marshallers; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufAllocator; 20 | import io.rsocket.ipc.Marshaller; 21 | import io.rsocket.ipc.Unmarshaller; 22 | import java.nio.ByteBuffer; 23 | 24 | public final class Bytes { 25 | private Bytes() {} 26 | 27 | public static Marshaller byteBufferMarshaller() { 28 | return value -> ByteBufAllocator.DEFAULT.buffer().writeBytes(value); 29 | } 30 | 31 | public static Unmarshaller byteBufferUnmarshaller() { 32 | return ByteBuf::nioBuffer; 33 | } 34 | 35 | public static Marshaller byteArrayMarshaller() { 36 | return value -> ByteBufAllocator.DEFAULT.buffer().writeBytes(value); 37 | } 38 | 39 | public static Unmarshaller byteArrayUnmarshaller() { 40 | return value -> { 41 | byte[] b = new byte[value.readableBytes()]; 42 | value.writeBytes(b); 43 | return b; 44 | }; 45 | } 46 | 47 | public static Marshaller byteBufMarshaller() { 48 | return byteBuf -> byteBuf; 49 | } 50 | 51 | public static Unmarshaller byteBufUnmarshaller() { 52 | return byteBuf -> byteBuf; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/tracing/ImmutableTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.tracing; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | import io.micrometer.core.lang.Nullable; 21 | import java.util.Objects; 22 | 23 | class ImmutableTag implements Tag { 24 | private String key; 25 | private String value; 26 | 27 | public ImmutableTag(String key, String value) { 28 | requireNonNull(key); 29 | requireNonNull(value); 30 | this.key = key; 31 | this.value = value; 32 | } 33 | 34 | @Override 35 | public String getKey() { 36 | return key; 37 | } 38 | 39 | @Override 40 | public String getValue() { 41 | return value; 42 | } 43 | 44 | @Override 45 | public boolean equals(@Nullable Object o) { 46 | if (this == o) return true; 47 | if (o == null || getClass() != o.getClass()) return false; 48 | Tag that = (Tag) o; 49 | return Objects.equals(key, that.getKey()) && Objects.equals(value, that.getValue()); 50 | } 51 | 52 | @Override 53 | public int hashCode() { 54 | return Objects.hash(key, value); 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return "ImmutableTag{" + "key='" + key + '\'' + ", value='" + value + '\'' + '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCRequestStreamFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.Functions; 20 | import io.rsocket.ipc.Marshaller; 21 | import io.rsocket.ipc.MetadataDecoder; 22 | import io.rsocket.ipc.Unmarshaller; 23 | import io.rsocket.util.ByteBufPayload; 24 | import reactor.core.publisher.Flux; 25 | 26 | @SuppressWarnings("rawtypes") 27 | public class IPCRequestStreamFunction implements IPCFunction> { 28 | 29 | final String route; 30 | final Unmarshaller unmarshaller; 31 | final Marshaller marshaller; 32 | final Functions.RequestStream rs; 33 | 34 | public IPCRequestStreamFunction( 35 | String route, Unmarshaller unmarshaller, Marshaller marshaller, Functions.RequestStream rs) { 36 | this.route = route; 37 | this.unmarshaller = unmarshaller; 38 | this.marshaller = marshaller; 39 | this.rs = rs; 40 | } 41 | 42 | @Override 43 | @SuppressWarnings("unchecked") 44 | public Flux apply(Payload payload, MetadataDecoder.Metadata metadata) { 45 | Object input = unmarshaller.apply(payload.sliceData()); 46 | return rs.apply(input, metadata.metadata()) 47 | .map(o -> ByteBufPayload.create(marshaller.apply(o))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSocket RPC - Java 2 | [![Build Status](https://travis-ci.org/rsocket/rsocket-rpc-java.svg?branch=master)](https://travis-ci.org/rsocket/rsocket-rpc-java) 3 | 4 | The standard [RSocket](http://rsocket.io) RPC Java implementation. 5 | 6 | ## Build from Source 7 | 8 | 1. Building rsocket-rpc-java requires installation of the [Protobuf](https://github.com/google/protobuf) compiler. RSocket RPC requires Protobuf 3.6.x or higher. 9 | 10 | For Mac users you can easily install the Protobuf compiler using Homebrew: 11 | 12 | $ brew install protobuf 13 | 14 | For other operating systems you can install the Protobuf compiler using the pre-built packages hosted on the [Protobuf Releases](https://github.com/google/protobuf/releases) page. 15 | 16 | 2. Run the following Gradle command to build the project: 17 | 18 | $ ./gradlew clean build 19 | 20 | ## What Next? 21 | 22 | * [Motivation](./docs/motivation.md) 23 | * [Get Started](./docs/get-started.md) 24 | 25 | ## Release Notes 26 | 27 | Please find release notes at [https://github.com/rsocket/rsocket-rpc-java/releases](https://github.com/rsocket/rsocket-rpc-java/releases). 28 | 29 | ## Bugs and Feedback 30 | 31 | For bugs, questions, and discussions please use the [Github Issues](https://github.com/netifi/rsocket-rpc-java/issues). 32 | 33 | ## License 34 | Copyright 2019 [Netifi Inc.](https://www.netifi.com) 35 | 36 | Licensed under the Apache License, Version 2.0 (the "License"); 37 | you may not use this file except in compliance with the License. 38 | You may obtain a copy of the License at 39 | 40 | http://www.apache.org/licenses/LICENSE-2.0 41 | 42 | Unless required by applicable law or agreed to in writing, software 43 | distributed under the License is distributed on an "AS IS" BASIS, 44 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 45 | See the License for the specific language governing permissions and 46 | limitations under the License. 47 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCRequestResponseFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.Functions; 20 | import io.rsocket.ipc.Marshaller; 21 | import io.rsocket.ipc.MetadataDecoder; 22 | import io.rsocket.ipc.Unmarshaller; 23 | import io.rsocket.util.ByteBufPayload; 24 | import reactor.core.publisher.Mono; 25 | 26 | @SuppressWarnings("rawtypes") 27 | public class IPCRequestResponseFunction implements IPCFunction> { 28 | 29 | final String route; 30 | final Unmarshaller unmarshaller; 31 | final Marshaller marshaller; 32 | final Functions.RequestResponse rr; 33 | 34 | public IPCRequestResponseFunction( 35 | String route, 36 | Unmarshaller unmarshaller, 37 | Marshaller marshaller, 38 | Functions.RequestResponse rr) { 39 | this.route = route; 40 | this.unmarshaller = unmarshaller; 41 | this.marshaller = marshaller; 42 | this.rr = rr; 43 | } 44 | 45 | @Override 46 | @SuppressWarnings("unchecked") 47 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 48 | Object input = unmarshaller.apply(payload.sliceData()); 49 | return rr.apply(input, metadata.metadata()) 50 | .map(o -> ByteBufPayload.create(marshaller.apply(o))); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/encoders/CompositeMetadataEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.encoders; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufAllocator; 20 | import io.opentracing.SpanContext; 21 | import io.rsocket.ipc.MetadataEncoder; 22 | import java.util.Objects; 23 | 24 | public class CompositeMetadataEncoder implements MetadataEncoder { 25 | 26 | final ByteBufAllocator allocator; 27 | 28 | public CompositeMetadataEncoder() { 29 | this.allocator = ByteBufAllocator.DEFAULT; 30 | } 31 | 32 | public CompositeMetadataEncoder(ByteBufAllocator allocator) { 33 | this.allocator = Objects.requireNonNull(allocator); 34 | } 35 | 36 | @Override 37 | public ByteBuf encode( 38 | ByteBuf metadata, SpanContext spanContext, String baseRoute, String... parts) { 39 | throw new UnsupportedOperationException("unsupported"); 40 | 41 | // if (!(metadata instanceof CompositeByteBuf)) { 42 | // throw new IllegalArgumentException("Users metadata must be of type 43 | // CompositeByteBuf"); 44 | // } 45 | // 46 | // final CompositeByteBuf compositeByteBuf = (CompositeByteBuf) metadata; 47 | // final ByteBuf route = ByteBufAllocator.DEFAULT.buffer(); 48 | // 49 | // return CompositeMetadataFlyweight.encodeAndAddMetadata(compositeByteBuf, allocator, 50 | // WellKnownMimeType.MESSAGE_RSOCKET_ROUTING, ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/encoders/DefaultMetadataEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.encoders; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufAllocator; 20 | import io.opentracing.SpanContext; 21 | import io.rsocket.ipc.MetadataEncoder; 22 | import io.rsocket.ipc.frames.Metadata; 23 | import io.rsocket.ipc.tracing.Tracing; 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | public class DefaultMetadataEncoder implements MetadataEncoder { 28 | 29 | final ByteBufAllocator allocator; 30 | 31 | public DefaultMetadataEncoder(ByteBufAllocator allocator) { 32 | this.allocator = allocator; 33 | } 34 | 35 | @Override 36 | public ByteBuf encode(ByteBuf metadata, SpanContext context, String baseRoute, String... parts) { 37 | 38 | if (parts.length != 1) { 39 | throw new IllegalArgumentException( 40 | "Number of parts should be strictly equal to 1 but given [" + parts.length + "]"); 41 | } 42 | 43 | if (context != null) { 44 | final HashMap spanMap = new HashMap<>(); 45 | for (Map.Entry item : context.baggageItems()) { 46 | spanMap.put(item.getKey(), item.getValue()); 47 | } 48 | 49 | ByteBuf tracingMetadata = Tracing.mapToByteBuf(allocator, spanMap); 50 | return Metadata.encode(allocator, baseRoute, parts[0], tracingMetadata, metadata); 51 | } 52 | 53 | return Metadata.encode(allocator, baseRoute, parts[0], metadata); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCMetricsAwareFireAndForgetFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.ipc.metrics.Metrics; 25 | import reactor.core.publisher.Mono; 26 | 27 | @SuppressWarnings("rawtypes") 28 | public class IPCMetricsAwareFireAndForgetFunction implements IPCFunction> { 29 | 30 | final String route; 31 | final Unmarshaller unmarshaller; 32 | final Marshaller marshaller; 33 | final Functions.FireAndForget fnf; 34 | final MeterRegistry meterRegistry; 35 | 36 | public IPCMetricsAwareFireAndForgetFunction( 37 | String route, 38 | Unmarshaller unmarshaller, 39 | Marshaller marshaller, 40 | Functions.FireAndForget fnf, 41 | MeterRegistry meterRegistry) { 42 | this.route = route; 43 | this.unmarshaller = unmarshaller; 44 | this.marshaller = marshaller; 45 | this.fnf = fnf; 46 | this.meterRegistry = meterRegistry; 47 | } 48 | 49 | @Override 50 | @SuppressWarnings("unchecked") 51 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadatat) { 52 | Object input = unmarshaller.apply(payload.sliceData()); 53 | return fnf.apply(input, metadatat.metadata()) 54 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/test/java/io/rsocket/rpc/frames/MetadataTest.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.frames; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.ByteBufAllocator; 5 | import io.netty.buffer.Unpooled; 6 | import java.util.concurrent.ThreadLocalRandom; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | public class MetadataTest { 11 | @Test 12 | public void testEncodeAndDecodeNoTracingData() { 13 | byte[] bytes = new byte[20]; 14 | ThreadLocalRandom.current().nextBytes(bytes); 15 | String service = "foo"; 16 | String method = "bar"; 17 | ByteBuf tracing = Unpooled.EMPTY_BUFFER; 18 | ByteBuf metadata = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(bytes)); 19 | 20 | ByteBuf encode = Metadata.encode(ByteBufAllocator.DEFAULT, service, method, tracing, metadata); 21 | 22 | String method1 = Metadata.getMethod(encode); 23 | String service1 = Metadata.getService(encode); 24 | 25 | Assert.assertEquals(method, method1); 26 | Assert.assertEquals(service, service1); 27 | 28 | ByteBuf tracing1 = Metadata.getTracing(encode); 29 | ByteBuf metadata1 = Metadata.getMetadata(encode); 30 | 31 | Assert.assertEquals(0, tracing1.readableBytes()); 32 | Assert.assertEquals(20, metadata1.readableBytes()); 33 | } 34 | 35 | @Test 36 | public void testEcodeAndDecodeWithTracingData() { 37 | byte[] bytes = new byte[20]; 38 | ThreadLocalRandom.current().nextBytes(bytes); 39 | String service = "foo"; 40 | String method = "bar"; 41 | 42 | ByteBuf tracing = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(bytes)); 43 | ByteBuf metadata = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(bytes)); 44 | 45 | ByteBuf encode = Metadata.encode(ByteBufAllocator.DEFAULT, service, method, tracing, metadata); 46 | 47 | String method1 = Metadata.getMethod(encode); 48 | String service1 = Metadata.getService(encode); 49 | 50 | Assert.assertEquals(method, method1); 51 | Assert.assertEquals(service, service1); 52 | 53 | ByteBuf tracing1 = Metadata.getTracing(encode); 54 | ByteBuf metadata1 = Metadata.getMetadata(encode); 55 | 56 | Assert.assertEquals(20, tracing1.readableBytes()); 57 | Assert.assertEquals(20, metadata1.readableBytes()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCMetricsAwareRequestStreamFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.ipc.metrics.Metrics; 25 | import io.rsocket.util.ByteBufPayload; 26 | import reactor.core.publisher.Flux; 27 | 28 | @SuppressWarnings("rawtypes") 29 | public class IPCMetricsAwareRequestStreamFunction implements IPCFunction> { 30 | 31 | final String route; 32 | final Unmarshaller unmarshaller; 33 | final Marshaller marshaller; 34 | final Functions.RequestStream rs; 35 | final MeterRegistry meterRegistry; 36 | 37 | public IPCMetricsAwareRequestStreamFunction( 38 | String route, 39 | Unmarshaller unmarshaller, 40 | Marshaller marshaller, 41 | Functions.RequestStream rs, 42 | MeterRegistry meterRegistry) { 43 | this.route = route; 44 | this.unmarshaller = unmarshaller; 45 | this.marshaller = marshaller; 46 | this.rs = rs; 47 | this.meterRegistry = meterRegistry; 48 | } 49 | 50 | @Override 51 | @SuppressWarnings("unchecked") 52 | public Flux apply(Payload payload, MetadataDecoder.Metadata metadata) { 53 | Object input = unmarshaller.apply(payload.sliceData()); 54 | return rs.apply(input, metadata.metadata()) 55 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 56 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCMetricsAwareRequestResponseFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.ipc.metrics.Metrics; 25 | import io.rsocket.util.ByteBufPayload; 26 | import reactor.core.publisher.Mono; 27 | 28 | @SuppressWarnings("rawtypes") 29 | public class IPCMetricsAwareRequestResponseFunction implements IPCFunction> { 30 | 31 | final String route; 32 | final Unmarshaller unmarshaller; 33 | final Marshaller marshaller; 34 | final Functions.RequestResponse rr; 35 | final MeterRegistry meterRegistry; 36 | 37 | public IPCMetricsAwareRequestResponseFunction( 38 | String route, 39 | Unmarshaller unmarshaller, 40 | Marshaller marshaller, 41 | Functions.RequestResponse rr, 42 | MeterRegistry meterRegistry) { 43 | this.route = route; 44 | this.unmarshaller = unmarshaller; 45 | this.marshaller = marshaller; 46 | this.rr = rr; 47 | this.meterRegistry = meterRegistry; 48 | } 49 | 50 | @Override 51 | @SuppressWarnings("unchecked") 52 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 53 | Object input = unmarshaller.apply(payload.sliceData()); 54 | return rr.apply(input, metadata.metadata()) 55 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 56 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/main/java/io/rsocket/graphql/GraphQLServerRequestResponse.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import graphql.ExecutionResult; 4 | import graphql.GraphQLError; 5 | import graphql.execution.instrumentation.Instrumentation; 6 | import graphql.schema.GraphQLSchema; 7 | import io.netty.buffer.ByteBuf; 8 | import io.rsocket.ipc.Functions; 9 | import java.util.List; 10 | import java.util.concurrent.CompletableFuture; 11 | import org.dataloader.DataLoaderRegistry; 12 | import org.reactivestreams.Publisher; 13 | import reactor.core.publisher.Mono; 14 | 15 | @SuppressWarnings("unchecked") 16 | class GraphQLServerRequestResponse implements Functions.RequestResponse { 17 | private final DataLoaderRegistry registry; 18 | private final Instrumentation instrumentation; 19 | private final GraphQLSchema graphQLSchema; 20 | 21 | GraphQLServerRequestResponse( 22 | DataLoaderRegistry registry, Instrumentation instrumentation, GraphQLSchema graphQLSchema) { 23 | this.registry = registry; 24 | this.instrumentation = instrumentation; 25 | this.graphQLSchema = graphQLSchema; 26 | } 27 | 28 | @Override 29 | public Mono apply(GraphQLRequest request, ByteBuf byteBuf) { 30 | try { 31 | CompletableFuture result = 32 | Util.executeGraphQLRequest(request, byteBuf, registry, graphQLSchema, instrumentation); 33 | 34 | return Mono.fromFuture(result) 35 | .flatMap( 36 | executionResult -> { 37 | List errors = executionResult.getErrors(); 38 | 39 | if (!errors.isEmpty()) { 40 | return Mono.error(GraphQLErrorException.from(errors)); 41 | } 42 | 43 | if (!executionResult.isDataPresent()) { 44 | return Mono.empty(); 45 | } 46 | 47 | Object r = executionResult.getData(); 48 | 49 | if (r == null) { 50 | return Mono.error(new NullPointerException("result data was null")); 51 | } 52 | 53 | if (r instanceof Publisher) { 54 | return Mono.from((Publisher) r); 55 | } else { 56 | return Mono.just(r); 57 | } 58 | }); 59 | 60 | } catch (Throwable t) { 61 | return Mono.error(t); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/main/java/io/rsocket/graphql/GraphQLServerRequestStream.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import graphql.ExecutionResult; 4 | import graphql.GraphQLError; 5 | import graphql.execution.instrumentation.Instrumentation; 6 | import graphql.schema.GraphQLSchema; 7 | import io.netty.buffer.ByteBuf; 8 | import io.rsocket.ipc.Functions; 9 | import java.util.List; 10 | import java.util.concurrent.CompletableFuture; 11 | import org.dataloader.DataLoaderRegistry; 12 | import org.reactivestreams.Publisher; 13 | import reactor.core.publisher.Flux; 14 | import reactor.core.publisher.Mono; 15 | 16 | @SuppressWarnings("unchecked") 17 | class GraphQLServerRequestStream implements Functions.RequestStream { 18 | private final DataLoaderRegistry registry; 19 | private final Instrumentation instrumentation; 20 | private final GraphQLSchema graphQLSchema; 21 | 22 | GraphQLServerRequestStream( 23 | DataLoaderRegistry registry, Instrumentation instrumentation, GraphQLSchema graphQLSchema) { 24 | this.registry = registry; 25 | this.instrumentation = instrumentation; 26 | this.graphQLSchema = graphQLSchema; 27 | } 28 | 29 | @Override 30 | public Flux apply(GraphQLRequest request, ByteBuf byteBuf) { 31 | try { 32 | 33 | CompletableFuture result = 34 | Util.executeGraphQLRequest(request, byteBuf, registry, graphQLSchema, instrumentation); 35 | 36 | return Mono.fromFuture(result) 37 | .flatMapMany( 38 | executionResult -> { 39 | List errors = executionResult.getErrors(); 40 | 41 | if (!errors.isEmpty()) { 42 | return Mono.error(GraphQLErrorException.from(errors)); 43 | } 44 | 45 | if (!executionResult.isDataPresent()) { 46 | return Mono.empty(); 47 | } 48 | 49 | Object r = executionResult.getData(); 50 | 51 | if (r == null) { 52 | return Mono.error(new NullPointerException("result data was null")); 53 | } 54 | 55 | if (r instanceof Publisher) { 56 | return (Publisher) r; 57 | } else { 58 | return Mono.just(r); 59 | } 60 | }); 61 | 62 | } catch (Throwable t) { 63 | return Flux.error(t); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAwareFireAndForgetFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.opentracing.Tracer; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.ipc.tracing.Tag; 25 | import io.rsocket.ipc.tracing.Tracing; 26 | import reactor.core.publisher.Mono; 27 | 28 | @SuppressWarnings("rawtypes") 29 | public class IPCTracingAwareFireAndForgetFunction implements IPCFunction> { 30 | 31 | final String route; 32 | final Unmarshaller unmarshaller; 33 | final Marshaller marshaller; 34 | final Functions.FireAndForget fnf; 35 | final Tracer tracer; 36 | 37 | public IPCTracingAwareFireAndForgetFunction( 38 | String route, 39 | Unmarshaller unmarshaller, 40 | Marshaller marshaller, 41 | Functions.FireAndForget fnf, 42 | Tracer tracer) { 43 | this.route = route; 44 | this.unmarshaller = unmarshaller; 45 | this.marshaller = marshaller; 46 | this.fnf = fnf; 47 | this.tracer = tracer; 48 | } 49 | 50 | @Override 51 | @SuppressWarnings("unchecked") 52 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 53 | Object input = unmarshaller.apply(payload.sliceData()); 54 | return fnf.apply(input, metadata.metadata()) 55 | .transform( 56 | Tracing.traceAsChild( 57 | tracer, 58 | route, 59 | Tag.of("rsocket.route", route), 60 | Tag.of("rsocket.ipc.role", "server"), 61 | Tag.of("rsocket.ipc.version", "ipc")) 62 | .apply(metadata.spanContext())); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/IPCServerRSocket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.opentracing.Tracer; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.routing.SimpleRouter; 21 | import reactor.core.publisher.Flux; 22 | 23 | @SuppressWarnings("unchecked") 24 | class IPCServerRSocket extends RoutingServerRSocket implements IPCRSocket, SelfRegistrable { 25 | 26 | private final String service; 27 | private final SimpleRouter simpleRouter; 28 | 29 | public IPCServerRSocket(String service, SimpleRouter simpleRouter) { 30 | super(simpleRouter); 31 | this.service = service; 32 | this.simpleRouter = simpleRouter; 33 | } 34 | 35 | public IPCServerRSocket(String service, Tracer tracer, SimpleRouter simpleRouter) { 36 | super(tracer, simpleRouter); 37 | this.service = service; 38 | this.simpleRouter = simpleRouter; 39 | } 40 | 41 | public IPCServerRSocket(String service, MetadataDecoder decoder, SimpleRouter simpleRouter) { 42 | super(decoder, simpleRouter); 43 | this.service = service; 44 | this.simpleRouter = simpleRouter; 45 | } 46 | 47 | @Override 48 | public String getService() { 49 | return service; 50 | } 51 | 52 | @Override 53 | public void selfRegister(MutableRouter mutableRouter) { 54 | simpleRouter.getFireAndForgetRegistry().forEach(mutableRouter::withFireAndForgetRoute); 55 | simpleRouter.getRequestResponseRegistry().forEach(mutableRouter::withRequestResponseRoute); 56 | simpleRouter.getRequestStreamRegistry().forEach(mutableRouter::withRequestStreamRoute); 57 | simpleRouter.getRequestChannelRegistry().forEach(mutableRouter::withRequestChannelRoute); 58 | } 59 | 60 | @Override 61 | public Flux requestChannel(Payload payload, Flux payloads) { 62 | return super.requestChannel(payloads); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/metrics/MetricsSubscriber.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.metrics; 2 | 3 | import io.micrometer.core.instrument.Counter; 4 | import io.micrometer.core.instrument.Timer; 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | import org.reactivestreams.Subscription; 8 | import reactor.core.CoreSubscriber; 9 | import reactor.core.publisher.Operators; 10 | import reactor.util.context.Context; 11 | 12 | @Deprecated 13 | public class MetricsSubscriber extends AtomicBoolean implements Subscription, CoreSubscriber { 14 | private final CoreSubscriber actual; 15 | private final Counter next, complete, error, cancelled; 16 | private final Timer timer; 17 | 18 | private Subscription s; 19 | private long start; 20 | 21 | MetricsSubscriber( 22 | CoreSubscriber actual, 23 | Counter next, 24 | Counter complete, 25 | Counter error, 26 | Counter cancelled, 27 | Timer timer) { 28 | this.actual = actual; 29 | this.next = next; 30 | this.complete = complete; 31 | this.error = error; 32 | this.cancelled = cancelled; 33 | this.timer = timer; 34 | } 35 | 36 | @Override 37 | public void onSubscribe(Subscription s) { 38 | if (Operators.validate(this.s, s)) { 39 | this.s = s; 40 | this.start = System.nanoTime(); 41 | 42 | actual.onSubscribe(this); 43 | } 44 | } 45 | 46 | @Override 47 | public void onNext(T t) { 48 | next.increment(); 49 | actual.onNext(t); 50 | } 51 | 52 | @Override 53 | public void onError(Throwable t) { 54 | if (compareAndSet(false, true)) { 55 | error.increment(); 56 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 57 | } 58 | actual.onError(t); 59 | } 60 | 61 | @Override 62 | public void onComplete() { 63 | if (compareAndSet(false, true)) { 64 | complete.increment(); 65 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 66 | } 67 | actual.onComplete(); 68 | } 69 | 70 | @Override 71 | public void request(long n) { 72 | s.request(n); 73 | } 74 | 75 | @Override 76 | public void cancel() { 77 | if (compareAndSet(false, true)) { 78 | cancelled.increment(); 79 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 80 | } 81 | s.cancel(); 82 | } 83 | 84 | @Override 85 | public Context currentContext() { 86 | return actual.currentContext(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /rsocket-rpc-protobuf/src/java_plugin/cpp/blocking_java_generator.h: -------------------------------------------------------------------------------- 1 | #ifndef RSOCKET_RPC_COMPILER_BLOCKING_JAVA_GENERATOR_H_ 2 | #define RSOCKET_RPC_COMPILER_BLOCKING_JAVA_GENERATOR_H_ 3 | 4 | #include // for abort() 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | // Abort the program after logging the mesage if the given condition is not 13 | // true. Otherwise, do nothing. 14 | #define RSOCKET_RPC_CODEGEN_CHECK(x) !(x) && LogHelper(&std::cerr).get_os() \ 15 | << "CHECK FAILED: " << __FILE__ << ":" \ 16 | << __LINE__ << ": " 17 | 18 | // Abort the program after logging the mesage. 19 | #define RSOCKET_RPC_CODEGEN_FAIL RSOCKET_RPC_CODEGEN_CHECK(false) 20 | 21 | using namespace std; 22 | 23 | namespace blocking_java_rsocket_rpc_generator { 24 | 25 | enum ProtoFlavor { 26 | NORMAL, LITE 27 | }; 28 | 29 | // Returns the package name of the RSocket RPC services defined in the given file. 30 | string ServiceJavaPackage(const google::protobuf::FileDescriptor* file); 31 | 32 | // Returns the name of the client class for the given service. 33 | string ClientClassName(const google::protobuf::ServiceDescriptor* service); 34 | 35 | // Returns the name of the client class for the given service. 36 | string ServerClassName(const google::protobuf::ServiceDescriptor* service); 37 | 38 | // Writes the generated interface into the given ZeroCopyOutputStream 39 | void GenerateInterface(const google::protobuf::ServiceDescriptor* service, 40 | google::protobuf::io::ZeroCopyOutputStream* out, 41 | ProtoFlavor flavor, 42 | bool disable_version); 43 | 44 | // Writes the generated client into the given ZeroCopyOutputStream 45 | void GenerateClient(const google::protobuf::ServiceDescriptor* service, 46 | google::protobuf::io::ZeroCopyOutputStream* out, 47 | ProtoFlavor flavor, 48 | bool disable_version); 49 | 50 | // Writes the generated server into the given ZeroCopyOutputStream 51 | void GenerateServer(const google::protobuf::ServiceDescriptor* service, 52 | google::protobuf::io::ZeroCopyOutputStream* out, 53 | ProtoFlavor flavor, 54 | bool disable_version); 55 | 56 | } // namespace java_rsocket_rpc_generator 57 | 58 | #endif // RSOCKET_RPC_COMPILER_BLOCKING_JAVA_GENERATOR_H_ 59 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCRequestChannelFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.util.ByteBufPayload; 25 | import reactor.core.Exceptions; 26 | import reactor.core.publisher.Flux; 27 | 28 | @SuppressWarnings("rawtypes") 29 | public class IPCRequestChannelFunction implements IPCChannelFunction { 30 | 31 | final String route; 32 | final Unmarshaller unmarshaller; 33 | final Marshaller marshaller; 34 | final Functions.HandleRequestHandle rc; 35 | 36 | public IPCRequestChannelFunction( 37 | String route, 38 | Unmarshaller unmarshaller, 39 | Marshaller marshaller, 40 | Functions.HandleRequestHandle rc) { 41 | this.route = route; 42 | this.unmarshaller = unmarshaller; 43 | this.marshaller = marshaller; 44 | this.rc = rc; 45 | } 46 | 47 | @Override 48 | @SuppressWarnings("unchecked") 49 | public Flux apply( 50 | Flux source, Payload payload, MetadataDecoder.Metadata metadata) { 51 | return rc.apply( 52 | unmarshaller.apply(payload.sliceData()), 53 | source.map( 54 | p -> { 55 | try { 56 | ByteBuf dd = p.sliceData(); 57 | Object result = unmarshaller.apply(dd); 58 | p.release(); 59 | return result; 60 | } catch (Throwable t) { 61 | p.release(); 62 | throw Exceptions.propagate(t); 63 | } 64 | }), 65 | metadata.metadata()) 66 | .map(o -> ByteBufPayload.create(marshaller.apply(o))); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /bintray.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | if (project.hasProperty('bintrayUser') && project.hasProperty('bintrayKey') && 18 | project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { 19 | 20 | subprojects { 21 | plugins.withId('com.jfrog.bintray') { 22 | bintray { 23 | user = project.property('bintrayUser') 24 | key = project.property('bintrayKey') 25 | 26 | publications = ['maven'] 27 | publish = true 28 | override = true 29 | 30 | pkg { 31 | repo = 'RSocket' 32 | name = 'rsocket-rpc-java' 33 | licenses = ['Apache-2.0'] 34 | 35 | issueTrackerUrl = 'https://github.com/rsocket/rsocket-rpc-java/issues' 36 | websiteUrl = 'https://github.com/rsocket/rsocket-rpc-java' 37 | vcsUrl = 'https://github.com/rsocket/rsocket-rpc-java.git' 38 | 39 | githubRepo = 'rsocket/rsocket-rpc-java' //Optional Github repository 40 | githubReleaseNotesFile = 'README.md' //Optional Github readme file 41 | 42 | version { 43 | name = project.version 44 | released = new Date() 45 | vcsTag = project.version 46 | 47 | gpg { 48 | sign = true 49 | } 50 | 51 | mavenCentralSync { 52 | user = project.property('sonatypeUsername') 53 | password = project.property('sonatypePassword') 54 | close = project.findProperty('stage') == 'Deploy' ? '1' : '0' 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAwareRequestStreamFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.opentracing.Tracer; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.ipc.tracing.Tag; 25 | import io.rsocket.ipc.tracing.Tracing; 26 | import io.rsocket.util.ByteBufPayload; 27 | import reactor.core.publisher.Flux; 28 | 29 | @SuppressWarnings("rawtypes") 30 | public class IPCTracingAwareRequestStreamFunction implements IPCFunction> { 31 | 32 | final String route; 33 | final Unmarshaller unmarshaller; 34 | final Marshaller marshaller; 35 | final Functions.RequestStream rs; 36 | final Tracer tracer; 37 | 38 | public IPCTracingAwareRequestStreamFunction( 39 | String route, 40 | Unmarshaller unmarshaller, 41 | Marshaller marshaller, 42 | Functions.RequestStream rs, 43 | Tracer tracer) { 44 | this.route = route; 45 | this.unmarshaller = unmarshaller; 46 | this.marshaller = marshaller; 47 | this.rs = rs; 48 | this.tracer = tracer; 49 | } 50 | 51 | @Override 52 | @SuppressWarnings("unchecked") 53 | public Flux apply(Payload payload, MetadataDecoder.Metadata metadata) { 54 | Object input = unmarshaller.apply(payload.sliceData()); 55 | return rs.apply(input, metadata.metadata()) 56 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 57 | .transform( 58 | Tracing.traceAsChild( 59 | tracer, 60 | route, 61 | Tag.of("rsocket.route", route), 62 | Tag.of("rsocket.ipc.role", "server"), 63 | Tag.of("rsocket.ipc.version", "ipc")) 64 | .apply(metadata.spanContext())); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAwareRequestResponseFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.opentracing.Tracer; 19 | import io.rsocket.Payload; 20 | import io.rsocket.ipc.Functions; 21 | import io.rsocket.ipc.Marshaller; 22 | import io.rsocket.ipc.MetadataDecoder; 23 | import io.rsocket.ipc.Unmarshaller; 24 | import io.rsocket.ipc.tracing.Tag; 25 | import io.rsocket.ipc.tracing.Tracing; 26 | import io.rsocket.util.ByteBufPayload; 27 | import reactor.core.publisher.Mono; 28 | 29 | @SuppressWarnings("rawtypes") 30 | public class IPCTracingAwareRequestResponseFunction implements IPCFunction> { 31 | 32 | final String route; 33 | final Unmarshaller unmarshaller; 34 | final Marshaller marshaller; 35 | final Functions.RequestResponse rr; 36 | final Tracer tracer; 37 | 38 | public IPCTracingAwareRequestResponseFunction( 39 | String route, 40 | Unmarshaller unmarshaller, 41 | Marshaller marshaller, 42 | Functions.RequestResponse rr, 43 | Tracer tracer) { 44 | this.route = route; 45 | this.unmarshaller = unmarshaller; 46 | this.marshaller = marshaller; 47 | this.rr = rr; 48 | this.tracer = tracer; 49 | } 50 | 51 | @Override 52 | @SuppressWarnings("unchecked") 53 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 54 | Object input = unmarshaller.apply(payload.sliceData()); 55 | return rr.apply(input, metadata.metadata()) 56 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 57 | .transform( 58 | Tracing.traceAsChild( 59 | tracer, 60 | route, 61 | Tag.of("rsocket.route", route), 62 | Tag.of("rsocket.ipc.role", "server"), 63 | Tag.of("rsocket.ipc.version", "ipc")) 64 | .apply(metadata.spanContext())); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /publication.gradle: -------------------------------------------------------------------------------- 1 | configure(subprojects.findAll {it.name != 'rsocket-rpc-protobuf'}) { 2 | plugins.withType(JavaPlugin) { 3 | compileJava { 4 | sourceCompatibility = 1.8 5 | 6 | // TODO: Cleanup warnings so no need to exclude 7 | options.compilerArgs << '-Xlint:all,-overloads,-rawtypes,-unchecked' 8 | } 9 | 10 | javadoc { 11 | options.with { 12 | links 'https://docs.oracle.com/javase/8/docs/api/' 13 | links 'https://projectreactor.io/docs/core/release/api/' 14 | } 15 | } 16 | 17 | test { 18 | useJUnitPlatform() 19 | 20 | systemProperty "io.netty.leakDetection.level", "ADVANCED" 21 | } 22 | } 23 | 24 | plugins.withType(JavaLibraryPlugin) { 25 | task sourcesJar(type: Jar) { 26 | classifier 'sources' 27 | from sourceSets.main.allJava 28 | } 29 | 30 | task javadocJar(type: Jar, dependsOn: javadoc) { 31 | classifier 'javadoc' 32 | from javadoc.destinationDir 33 | } 34 | } 35 | 36 | plugins.withType(MavenPublishPlugin) { 37 | publishing { 38 | publications { 39 | maven(MavenPublication) { 40 | from components.java 41 | 42 | artifact sourcesJar 43 | artifact javadocJar 44 | 45 | versionMapping { 46 | usage('java-api') { 47 | fromResolutionOf('runtimeClasspath') 48 | } 49 | usage('java-runtime') { 50 | fromResolutionResult() 51 | } 52 | } 53 | 54 | pom { 55 | name = project.name 56 | groupId = project.group 57 | afterEvaluate { 58 | description = project.description 59 | } 60 | resolveStrategy = DELEGATE_FIRST 61 | 62 | url = 'http://rsocket.io' 63 | 64 | licenses { 65 | license { 66 | name = 'The Apache Software License, Version 2.0' 67 | url = 'http://www.apache.org/license/LICENSE-2.0.txt' 68 | } 69 | } 70 | 71 | developers { 72 | developer { 73 | id = 'robertroeser' 74 | name = 'Robert Roeser' 75 | email = 'robert@netifi.com' 76 | } 77 | developer { 78 | id = 'rdegnan' 79 | name = 'Ryland Degnan' 80 | email = 'ryland@netifi.com' 81 | } 82 | developer { 83 | id = 'OlegDokuka' 84 | name = 'Oleh Dokuka' 85 | email = 'oleh@netifi.com' 86 | } 87 | } 88 | 89 | scm { 90 | connection = 'scm:git:https://github.com/rsocket/rsocket-rpc-java.git' 91 | developerConnection = 'scm:git:https://github.com/rsocket/rsocket-rpc-java.git' 92 | url = 'https://github.com/rsocket/rsocket-rpc-java' 93 | } 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/metrics/MetricsConditionalSubscriber.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.metrics; 2 | 3 | import io.micrometer.core.instrument.Counter; 4 | import io.micrometer.core.instrument.Timer; 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | import org.reactivestreams.Subscription; 8 | import reactor.core.Fuseable.ConditionalSubscriber; 9 | import reactor.core.publisher.Operators; 10 | import reactor.util.context.Context; 11 | 12 | @Deprecated 13 | public class MetricsConditionalSubscriber extends AtomicBoolean 14 | implements Subscription, ConditionalSubscriber { 15 | private final ConditionalSubscriber actual; 16 | private final Counter next, complete, error, cancelled; 17 | private final Timer timer; 18 | 19 | private Subscription s; 20 | private long start; 21 | 22 | MetricsConditionalSubscriber( 23 | ConditionalSubscriber actual, 24 | Counter next, 25 | Counter complete, 26 | Counter error, 27 | Counter cancelled, 28 | Timer timer) { 29 | this.actual = actual; 30 | this.next = next; 31 | this.complete = complete; 32 | this.error = error; 33 | this.cancelled = cancelled; 34 | this.timer = timer; 35 | } 36 | 37 | @Override 38 | public void onSubscribe(Subscription s) { 39 | if (Operators.validate(this.s, s)) { 40 | this.s = s; 41 | this.start = System.nanoTime(); 42 | 43 | actual.onSubscribe(this); 44 | } 45 | } 46 | 47 | @Override 48 | public void onNext(T t) { 49 | next.increment(); 50 | actual.onNext(t); 51 | } 52 | 53 | @Override 54 | public boolean tryOnNext(T t) { 55 | next.increment(); 56 | return actual.tryOnNext(t); 57 | } 58 | 59 | @Override 60 | public void onError(Throwable t) { 61 | if (compareAndSet(false, true)) { 62 | error.increment(); 63 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 64 | } 65 | actual.onError(t); 66 | } 67 | 68 | @Override 69 | public void onComplete() { 70 | if (compareAndSet(false, true)) { 71 | complete.increment(); 72 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 73 | } 74 | actual.onComplete(); 75 | } 76 | 77 | @Override 78 | public void request(long n) { 79 | s.request(n); 80 | } 81 | 82 | @Override 83 | public void cancel() { 84 | if (compareAndSet(false, true)) { 85 | cancelled.increment(); 86 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 87 | } 88 | s.cancel(); 89 | } 90 | 91 | @Override 92 | public Context currentContext() { 93 | return actual.currentContext(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/Functions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.Unpooled; 20 | import io.rsocket.ipc.util.TriFunction; 21 | import java.util.function.BiFunction; 22 | import org.reactivestreams.Publisher; 23 | import reactor.core.publisher.Flux; 24 | import reactor.core.publisher.Mono; 25 | 26 | public final class Functions { 27 | private Functions() {} 28 | 29 | @FunctionalInterface 30 | public interface RequestResponse extends BiFunction> { 31 | @Override 32 | Mono apply(I i, ByteBuf byteBuf); 33 | 34 | default Mono apply(I i) { 35 | return apply(i, Unpooled.EMPTY_BUFFER); 36 | } 37 | } 38 | 39 | @FunctionalInterface 40 | public interface RequestStream extends BiFunction> { 41 | @Override 42 | Flux apply(I i, ByteBuf byteBuf); 43 | 44 | default Flux apply(I i) { 45 | return apply(i, Unpooled.EMPTY_BUFFER); 46 | } 47 | } 48 | 49 | @FunctionalInterface 50 | public interface HandleRequestHandle 51 | extends TriFunction, ByteBuf, Flux> { 52 | @Override 53 | Flux apply(I i, Publisher publisher, ByteBuf byteBuf); 54 | 55 | default Flux apply(I i, Publisher publisher) { 56 | return apply(i, publisher, Unpooled.EMPTY_BUFFER); 57 | } 58 | } 59 | 60 | @FunctionalInterface 61 | public interface RequestChannel extends BiFunction, ByteBuf, Flux> { 62 | @Override 63 | Flux apply(Publisher publisher, ByteBuf byteBuf); 64 | 65 | default Flux apply(Publisher publisher) { 66 | return apply(publisher, Unpooled.EMPTY_BUFFER); 67 | } 68 | } 69 | 70 | @FunctionalInterface 71 | public interface FireAndForget extends BiFunction> { 72 | @Override 73 | Mono apply(I i, ByteBuf byteBuf); 74 | 75 | default Mono apply(I i) { 76 | return apply(i, Unpooled.EMPTY_BUFFER); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /rsocket-rpc-protobuf/src/java_plugin/cpp/java_generator.h: -------------------------------------------------------------------------------- 1 | #ifndef RSOCKET_RPC_COMPILER_JAVA_GENERATOR_H_ 2 | #define RSOCKET_RPC_COMPILER_JAVA_GENERATOR_H_ 3 | 4 | #include // for abort() 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class LogHelper { 12 | std::ostream* os; 13 | 14 | public: 15 | LogHelper(std::ostream* os) : os(os) {} 16 | ~LogHelper() { 17 | *os << std::endl; 18 | ::abort(); 19 | } 20 | std::ostream& get_os() { 21 | return *os; 22 | } 23 | }; 24 | 25 | // Abort the program after logging the mesage if the given condition is not 26 | // true. Otherwise, do nothing. 27 | #define RSOCKET_RPC_CODEGEN_CHECK(x) !(x) && LogHelper(&std::cerr).get_os() \ 28 | << "CHECK FAILED: " << __FILE__ << ":" \ 29 | << __LINE__ << ": " 30 | 31 | // Abort the program after logging the mesage. 32 | #define RSOCKET_RPC_CODEGEN_FAIL RSOCKET_RPC_CODEGEN_CHECK(false) 33 | 34 | using namespace std; 35 | 36 | namespace java_rsocket_rpc_generator { 37 | 38 | enum ProtoFlavor { 39 | NORMAL, LITE 40 | }; 41 | 42 | // Returns the package name of the RSocket RPC services defined in the given file. 43 | string ServiceJavaPackage(const google::protobuf::FileDescriptor* file); 44 | 45 | // Returns the name of the client class for the given service. 46 | string ClientClassName(const google::protobuf::ServiceDescriptor* service); 47 | 48 | // Returns the name of the client class for the given service. 49 | string ServerClassName(const google::protobuf::ServiceDescriptor* service); 50 | 51 | // Writes the generated interface into the given ZeroCopyOutputStream 52 | void GenerateInterface(const google::protobuf::ServiceDescriptor* service, 53 | google::protobuf::io::ZeroCopyOutputStream* out, 54 | ProtoFlavor flavor, 55 | bool disable_version); 56 | 57 | // Writes the generated client into the given ZeroCopyOutputStream 58 | void GenerateClient(const google::protobuf::ServiceDescriptor* service, 59 | google::protobuf::io::ZeroCopyOutputStream* out, 60 | ProtoFlavor flavor, 61 | bool disable_version); 62 | 63 | // Writes the generated server into the given ZeroCopyOutputStream 64 | void GenerateServer(const google::protobuf::ServiceDescriptor* service, 65 | google::protobuf::io::ZeroCopyOutputStream* out, 66 | ProtoFlavor flavor, 67 | bool disable_version); 68 | 69 | } // namespace java_rsocket_rpc_generator 70 | 71 | #endif // RSOCKET_RPC_COMPILER_JAVA_GENERATOR_H_ 72 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/metrics/Metrics.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.metrics; 2 | 3 | import io.micrometer.core.instrument.*; 4 | import java.util.function.Function; 5 | import org.reactivestreams.Publisher; 6 | import reactor.core.Fuseable; 7 | import reactor.core.publisher.Operators; 8 | 9 | @Deprecated 10 | public class Metrics { 11 | Metrics() {} 12 | 13 | public static Function, ? extends Publisher> timed( 14 | MeterRegistry registry, String name, String... keyValues) { 15 | return timed(registry, name, Tags.of(keyValues)); 16 | } 17 | 18 | @SuppressWarnings("unchecked") 19 | public static Function, ? extends Publisher> timed( 20 | MeterRegistry registry, String name, Iterable tags) { 21 | Counter next = 22 | Counter.builder(name + ".request").tags("status", "next").tags(tags).register(registry); 23 | Counter complete = 24 | Counter.builder(name + ".request").tags("status", "complete").tags(tags).register(registry); 25 | Counter error = 26 | Counter.builder(name + ".request").tags("status", "error").tags(tags).register(registry); 27 | Counter cancelled = 28 | Counter.builder(name + ".request") 29 | .tags("status", "cancelled") 30 | .tags(tags) 31 | .register(registry); 32 | Timer timer = 33 | Timer.builder(name + ".latency") 34 | .publishPercentiles(0.5, 0.9, 0.95, 0.99) 35 | .tags(tags) 36 | .register(registry); 37 | return Operators.lift( 38 | (scannable, subscriber) -> { 39 | if (scannable instanceof Fuseable) { 40 | if (subscriber instanceof Fuseable.ConditionalSubscriber) { 41 | return new MetricsFuseableConditionalSubscriber<>( 42 | (Fuseable.ConditionalSubscriber) subscriber, 43 | next, 44 | complete, 45 | error, 46 | cancelled, 47 | timer); 48 | } else { 49 | return new MetricsFuseableSubscriber<>( 50 | subscriber, next, complete, error, cancelled, timer); 51 | } 52 | } else { 53 | if (subscriber instanceof Fuseable.ConditionalSubscriber) { 54 | return new MetricsConditionalSubscriber<>( 55 | (Fuseable.ConditionalSubscriber) subscriber, 56 | next, 57 | complete, 58 | error, 59 | cancelled, 60 | timer); 61 | } else { 62 | return new MetricsSubscriber<>(subscriber, next, complete, error, cancelled, timer); 63 | } 64 | } 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /rsocket-rpc-core/build.gradle: -------------------------------------------------------------------------------- 1 | import static org.apache.tools.ant.taskdefs.condition.Os.* 2 | 3 | plugins { 4 | id 'com.google.protobuf' 5 | } 6 | 7 | description = 'RSocket RPC Library' 8 | 9 | dependencies { 10 | compile project(':rsocket-ipc-core') 11 | implementation 'com.google.protobuf:protobuf-java' 12 | implementation 'org.slf4j:slf4j-api' 13 | 14 | api 'io.opentracing:opentracing-api' 15 | api 'javax.inject:javax.inject' 16 | api 'javax.annotation:javax.annotation-api' 17 | api 'io.rsocket:rsocket-core' 18 | api 'io.micrometer:micrometer-core' 19 | 20 | protobuf project(':rsocket-rpc-metrics-idl') 21 | 22 | testImplementation 'io.opentracing.brave:brave-opentracing' 23 | testImplementation 'junit:junit' 24 | testImplementation 'org.junit.jupiter:junit-jupiter-engine' 25 | testImplementation 'org.junit.vintage:junit-vintage-engine' 26 | 27 | testImplementation 'javax.inject:javax.inject' 28 | testImplementation 'io.projectreactor:reactor-test' 29 | testImplementation 'com.google.protobuf:protobuf-java' 30 | testImplementation 'org.hdrhistogram:HdrHistogram' 31 | testImplementation 'org.apache.logging.log4j:log4j-api' 32 | testImplementation 'org.apache.logging.log4j:log4j-core' 33 | testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl' 34 | testImplementation 'io.rsocket:rsocket-transport-netty' 35 | testImplementation 'io.rsocket:rsocket-transport-local' 36 | testImplementation 'org.mockito:mockito-core' 37 | testImplementation 'io.zipkin.reporter2:zipkin-sender-okhttp3' 38 | } 39 | 40 | def protocPluginBaseName = "rsocket-rpc-protobuf-${osdetector.os}-${osdetector.arch}" 41 | def javaPluginPath = "$rootDir/rsocket-rpc-protobuf/build/exe/java_plugin/$protocPluginBaseName" 42 | 43 | if(isFamily(FAMILY_WINDOWS)){ 44 | javaPluginPath = javaPluginPath + ".exe" 45 | } 46 | 47 | protobuf { 48 | generatedFilesBaseDir = "${projectDir}/src/generated" 49 | 50 | protoc { 51 | artifact = "com.google.protobuf:protoc" 52 | } 53 | plugins { 54 | rsocketRpc { 55 | path = javaPluginPath 56 | } 57 | } 58 | generateProtoTasks { 59 | all().each { task -> 60 | task.dependsOn ':rsocket-rpc-protobuf:java_pluginExecutable' 61 | // Recompile protos when the codegen has been changed 62 | task.inputs.file javaPluginPath 63 | // Recompile protos when build.gradle has been changed, because 64 | // it's possible the version of protoc has been changed. 65 | task.inputs.file "${rootProject.projectDir}/build.gradle" 66 | task.plugins { 67 | rsocketRpc {} 68 | } 69 | } 70 | } 71 | } 72 | 73 | clean { 74 | delete protobuf.generatedFilesBaseDir 75 | } 76 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/marshallers/Primitives.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.marshallers; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufAllocator; 20 | import io.rsocket.ipc.Marshaller; 21 | import io.rsocket.ipc.Unmarshaller; 22 | 23 | public final class Primitives { 24 | private Primitives() {} 25 | 26 | public static Marshaller byteMarshaller() { 27 | return value -> ByteBufAllocator.DEFAULT.buffer().writeByte(value); 28 | } 29 | 30 | public static Unmarshaller byteUnmarshaller() { 31 | return ByteBuf::readByte; 32 | } 33 | 34 | public static Marshaller shortMarshaller() { 35 | return value -> ByteBufAllocator.DEFAULT.buffer().writeShort(value); 36 | } 37 | 38 | public static Unmarshaller shortUnmarshaller() { 39 | return ByteBuf::readShort; 40 | } 41 | 42 | public static Marshaller intMarshaller() { 43 | return value -> ByteBufAllocator.DEFAULT.buffer().writeInt(value); 44 | } 45 | 46 | public static Unmarshaller intUnmarshaller() { 47 | return ByteBuf::readInt; 48 | } 49 | 50 | public static Marshaller charMarshaller() { 51 | return value -> ByteBufAllocator.DEFAULT.buffer().writeChar(value); 52 | } 53 | 54 | public static Unmarshaller charUnmarshaller() { 55 | return ByteBuf::readChar; 56 | } 57 | 58 | public static Marshaller longMarshaller() { 59 | return value -> ByteBufAllocator.DEFAULT.buffer().writeLong(value); 60 | } 61 | 62 | public static Unmarshaller longUnmarshaller() { 63 | return ByteBuf::readLong; 64 | } 65 | 66 | public static Marshaller floatMarshaller() { 67 | return value -> ByteBufAllocator.DEFAULT.buffer().writeFloat(value); 68 | } 69 | 70 | public static Unmarshaller floatUnmarshaller() { 71 | return ByteBuf::readFloat; 72 | } 73 | 74 | public static Marshaller doubleMarshaller() { 75 | return value -> ByteBufAllocator.DEFAULT.buffer().writeDouble(value); 76 | } 77 | 78 | public static Unmarshaller doubleUnmarshaller() { 79 | return ByteBuf::readDouble; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAndMetricsAwareFireAndForgetFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.opentracing.Tracer; 20 | import io.rsocket.Payload; 21 | import io.rsocket.ipc.Functions; 22 | import io.rsocket.ipc.Marshaller; 23 | import io.rsocket.ipc.MetadataDecoder; 24 | import io.rsocket.ipc.Unmarshaller; 25 | import io.rsocket.ipc.metrics.Metrics; 26 | import io.rsocket.ipc.tracing.Tag; 27 | import io.rsocket.ipc.tracing.Tracing; 28 | import io.rsocket.util.ByteBufPayload; 29 | import reactor.core.publisher.Mono; 30 | 31 | @SuppressWarnings("rawtypes") 32 | public class IPCTracingAndMetricsAwareFireAndForgetFunction implements IPCFunction> { 33 | 34 | final String route; 35 | final Unmarshaller unmarshaller; 36 | final Marshaller marshaller; 37 | final Functions.FireAndForget fnf; 38 | final Tracer tracer; 39 | final MeterRegistry meterRegistry; 40 | 41 | public IPCTracingAndMetricsAwareFireAndForgetFunction( 42 | String route, 43 | Unmarshaller unmarshaller, 44 | Marshaller marshaller, 45 | Functions.FireAndForget fnf, 46 | Tracer tracer, 47 | MeterRegistry meterRegistry) { 48 | this.route = route; 49 | this.unmarshaller = unmarshaller; 50 | this.marshaller = marshaller; 51 | this.fnf = fnf; 52 | this.tracer = tracer; 53 | this.meterRegistry = meterRegistry; 54 | } 55 | 56 | @Override 57 | @SuppressWarnings("unchecked") 58 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 59 | Object input = unmarshaller.apply(payload.sliceData()); 60 | return fnf.apply(input, metadata.metadata()) 61 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 62 | .transform( 63 | Tracing.traceAsChild( 64 | tracer, 65 | route, 66 | Tag.of("rsocket.route", route), 67 | Tag.of("rsocket.ipc.role", "server"), 68 | Tag.of("rsocket.ipc.version", "ipc")) 69 | .apply(metadata.spanContext())) 70 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAndMetricsAwareRequestStreamFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.opentracing.Tracer; 20 | import io.rsocket.Payload; 21 | import io.rsocket.ipc.Functions; 22 | import io.rsocket.ipc.Marshaller; 23 | import io.rsocket.ipc.MetadataDecoder; 24 | import io.rsocket.ipc.Unmarshaller; 25 | import io.rsocket.ipc.metrics.Metrics; 26 | import io.rsocket.ipc.tracing.Tag; 27 | import io.rsocket.ipc.tracing.Tracing; 28 | import io.rsocket.util.ByteBufPayload; 29 | import reactor.core.publisher.Flux; 30 | 31 | @SuppressWarnings("rawtypes") 32 | public class IPCTracingAndMetricsAwareRequestStreamFunction implements IPCFunction> { 33 | 34 | final String route; 35 | final Unmarshaller unmarshaller; 36 | final Marshaller marshaller; 37 | final Functions.RequestStream rs; 38 | final Tracer tracer; 39 | final MeterRegistry meterRegistry; 40 | 41 | public IPCTracingAndMetricsAwareRequestStreamFunction( 42 | String route, 43 | Unmarshaller unmarshaller, 44 | Marshaller marshaller, 45 | Functions.RequestStream rs, 46 | Tracer tracer, 47 | MeterRegistry meterRegistry) { 48 | this.route = route; 49 | this.unmarshaller = unmarshaller; 50 | this.marshaller = marshaller; 51 | this.rs = rs; 52 | this.tracer = tracer; 53 | this.meterRegistry = meterRegistry; 54 | } 55 | 56 | @Override 57 | @SuppressWarnings("unchecked") 58 | public Flux apply(Payload payload, MetadataDecoder.Metadata metadata) { 59 | Object input = unmarshaller.apply(payload.sliceData()); 60 | return rs.apply(input, metadata.metadata()) 61 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 62 | .transform( 63 | Tracing.traceAsChild( 64 | tracer, 65 | route, 66 | Tag.of("rsocket.route", route), 67 | Tag.of("rsocket.ipc.role", "server"), 68 | Tag.of("rsocket.ipc.version", "ipc")) 69 | .apply(metadata.spanContext())) 70 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCMetricsAwareRequestChannelFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.netty.buffer.ByteBuf; 20 | import io.rsocket.Payload; 21 | import io.rsocket.ipc.Functions; 22 | import io.rsocket.ipc.Marshaller; 23 | import io.rsocket.ipc.MetadataDecoder; 24 | import io.rsocket.ipc.Unmarshaller; 25 | import io.rsocket.ipc.metrics.Metrics; 26 | import io.rsocket.util.ByteBufPayload; 27 | import reactor.core.Exceptions; 28 | import reactor.core.publisher.Flux; 29 | 30 | @SuppressWarnings("rawtypes") 31 | public class IPCMetricsAwareRequestChannelFunction implements IPCChannelFunction { 32 | 33 | final String route; 34 | final Unmarshaller unmarshaller; 35 | final Marshaller marshaller; 36 | final Functions.HandleRequestHandle rc; 37 | final MeterRegistry meterRegistry; 38 | 39 | public IPCMetricsAwareRequestChannelFunction( 40 | String route, 41 | Unmarshaller unmarshaller, 42 | Marshaller marshaller, 43 | Functions.HandleRequestHandle rc, 44 | MeterRegistry meterRegistry) { 45 | this.route = route; 46 | this.unmarshaller = unmarshaller; 47 | this.marshaller = marshaller; 48 | this.rc = rc; 49 | this.meterRegistry = meterRegistry; 50 | } 51 | 52 | @Override 53 | @SuppressWarnings("unchecked") 54 | public Flux apply( 55 | Flux source, Payload payload, MetadataDecoder.Metadata decodedMetadata) { 56 | return rc.apply( 57 | unmarshaller.apply(payload.sliceData()), 58 | source.map( 59 | p -> { 60 | try { 61 | ByteBuf dd = p.sliceData(); 62 | Object result = unmarshaller.apply(dd); 63 | p.release(); 64 | return result; 65 | } catch (Throwable t) { 66 | p.release(); 67 | throw Exceptions.propagate(t); 68 | } 69 | }), 70 | decodedMetadata.metadata()) 71 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 72 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAndMetricsAwareRequestResponseFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.opentracing.Tracer; 20 | import io.rsocket.Payload; 21 | import io.rsocket.ipc.Functions; 22 | import io.rsocket.ipc.Marshaller; 23 | import io.rsocket.ipc.MetadataDecoder; 24 | import io.rsocket.ipc.Unmarshaller; 25 | import io.rsocket.ipc.metrics.Metrics; 26 | import io.rsocket.ipc.tracing.Tag; 27 | import io.rsocket.ipc.tracing.Tracing; 28 | import io.rsocket.util.ByteBufPayload; 29 | import reactor.core.publisher.Mono; 30 | 31 | @SuppressWarnings("rawtypes") 32 | public class IPCTracingAndMetricsAwareRequestResponseFunction 33 | implements IPCFunction> { 34 | 35 | final String route; 36 | final Unmarshaller unmarshaller; 37 | final Marshaller marshaller; 38 | final Functions.RequestResponse rr; 39 | final Tracer tracer; 40 | final MeterRegistry meterRegistry; 41 | 42 | public IPCTracingAndMetricsAwareRequestResponseFunction( 43 | String route, 44 | Unmarshaller unmarshaller, 45 | Marshaller marshaller, 46 | Functions.RequestResponse rr, 47 | Tracer tracer, 48 | MeterRegistry meterRegistry) { 49 | this.route = route; 50 | this.unmarshaller = unmarshaller; 51 | this.marshaller = marshaller; 52 | this.rr = rr; 53 | this.tracer = tracer; 54 | this.meterRegistry = meterRegistry; 55 | } 56 | 57 | @Override 58 | @SuppressWarnings("unchecked") 59 | public Mono apply(Payload payload, MetadataDecoder.Metadata metadata) { 60 | Object input = unmarshaller.apply(payload.sliceData()); 61 | return rr.apply(input, metadata.metadata()) 62 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 63 | .transform( 64 | Tracing.traceAsChild( 65 | tracer, 66 | route, 67 | Tag.of("rsocket.route", route), 68 | Tag.of("rsocket.ipc.role", "server"), 69 | Tag.of("rsocket.ipc.version", "ipc")) 70 | .apply(metadata.spanContext())) 71 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ci/travis.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then 4 | 5 | echo -e "Building PR #$TRAVIS_PULL_REQUEST [$TRAVIS_PULL_REQUEST_SLUG/$TRAVIS_PULL_REQUEST_BRANCH => $TRAVIS_REPO_SLUG/$TRAVIS_BRANCH]" 6 | ./gradlew \ 7 | -PversionSuffix="-SNAPSHOT" \ 8 | -PvcProtobufLibs="/c/Program Files/protobuf/lib" \ 9 | -PvcProtobufInclude="/c/Program Files/protobuf/include" \ 10 | build 11 | 12 | elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ] && [ "$bintrayUser" != "" ] && [ "$TRAVIS_BRANCH" == "master" ] ; then 13 | 14 | echo -e "Building Master Snapshot $TRAVIS_REPO_SLUG/$TRAVIS_BRANCH/$TRAVIS_BUILD_NUMBER" 15 | ./gradlew \ 16 | -PversionSuffix="-SNAPSHOT" \ 17 | -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" \ 18 | -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" \ 19 | -PvcProtobufLibs="/c/Program Files/protobuf/lib" -PvcProtobufInclude="/c/Program Files/protobuf/include" \ 20 | -PbuildInfo.build.number="$TRAVIS_BUILD_NUMBER" \ 21 | -PbuildInfo.build.timestamp="$(git show -s --format=%ct HEAD)000" \ 22 | build artifactoryPublish --stacktrace 23 | 24 | elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ] && [ "$bintrayUser" != "" ] ; then 25 | 26 | echo -e "Building Branch Snapshot $TRAVIS_REPO_SLUG/$TRAVIS_BRANCH/$TRAVIS_BUILD_NUMBER/$TRAVIS_BUILD_NUMBER" 27 | ./gradlew \ 28 | -PversionSuffix="-${TRAVIS_BRANCH//\//-}-SNAPSHOT" \ 29 | -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" \ 30 | -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" \ 31 | -PvcProtobufLibs="/c/Program Files/protobuf/lib" -PvcProtobufInclude="/c/Program Files/protobuf/include" \ 32 | -PbuildInfo.build.number="$TRAVIS_BUILD_NUMBER" \ 33 | -PbuildInfo.build.timestamp="$(git show -s --format=%ct HEAD)000" \ 34 | build artifactoryPublish --stacktrace 35 | 36 | elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" != "" ] && [ "$bintrayUser" != "" ] ; then 37 | 38 | echo -e "Building Tag $TRAVIS_REPO_SLUG/$TRAVIS_TAG" 39 | ./gradlew \ 40 | -Pversion="$TRAVIS_TAG" -Pstage="$TRAVIS_BUILD_STAGE_NAME" \ 41 | -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" \ 42 | -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" \ 43 | -PvcProtobufLibs="/c/Program Files/protobuf/lib" -PvcProtobufInclude="/c/Program Files/protobuf/include" \ 44 | -PbuildInfo.build.number="$TRAVIS_BUILD_NUMBER" \ 45 | -PbuildInfo.build.timestamp="$(git show -s --format=%ct HEAD)000" \ 46 | build bintrayUpload --stacktrace 47 | 48 | else 49 | 50 | echo -e "Building $TRAVIS_REPO_SLUG/$TRAVIS_BRANCH" 51 | ./gradlew \ 52 | -PversionSuffix="-SNAPSHOT" \ 53 | -PvcProtobufLibs="/c/Program Files/protobuf/lib" -PvcProtobufInclude="/c/Program Files/protobuf/include" \ 54 | build 55 | 56 | fi 57 | 58 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAwareRequestChannelFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.opentracing.Tracer; 20 | import io.rsocket.Payload; 21 | import io.rsocket.ipc.Functions; 22 | import io.rsocket.ipc.Marshaller; 23 | import io.rsocket.ipc.MetadataDecoder; 24 | import io.rsocket.ipc.Unmarshaller; 25 | import io.rsocket.ipc.tracing.Tag; 26 | import io.rsocket.ipc.tracing.Tracing; 27 | import io.rsocket.util.ByteBufPayload; 28 | import reactor.core.Exceptions; 29 | import reactor.core.publisher.Flux; 30 | 31 | @SuppressWarnings("rawtypes") 32 | public class IPCTracingAwareRequestChannelFunction implements IPCChannelFunction { 33 | 34 | final String route; 35 | final Unmarshaller unmarshaller; 36 | final Marshaller marshaller; 37 | final Functions.HandleRequestHandle rs; 38 | final Tracer tracer; 39 | 40 | public IPCTracingAwareRequestChannelFunction( 41 | String route, 42 | Unmarshaller unmarshaller, 43 | Marshaller marshaller, 44 | Functions.HandleRequestHandle rs, 45 | Tracer tracer) { 46 | this.route = route; 47 | this.unmarshaller = unmarshaller; 48 | this.marshaller = marshaller; 49 | this.rs = rs; 50 | this.tracer = tracer; 51 | } 52 | 53 | @Override 54 | @SuppressWarnings("unchecked") 55 | public Flux apply( 56 | Flux source, Payload payload, MetadataDecoder.Metadata metadata) { 57 | return rs.apply( 58 | unmarshaller.apply(payload.sliceData()), 59 | source.map( 60 | p -> { 61 | try { 62 | ByteBuf dd = p.sliceData(); 63 | Object result = unmarshaller.apply(dd); 64 | p.release(); 65 | return result; 66 | } catch (Throwable t) { 67 | p.release(); 68 | throw Exceptions.propagate(t); 69 | } 70 | }), 71 | metadata.metadata()) 72 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 73 | .transform( 74 | Tracing.traceAsChild( 75 | tracer, 76 | route, 77 | Tag.of("rsocket.route", route), 78 | Tag.of("rsocket.ipc.role", "server"), 79 | Tag.of("rsocket.ipc.version", "ipc")) 80 | .apply(metadata.spanContext())); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/metrics/MetricsSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.metrics; 17 | 18 | import io.micrometer.core.instrument.Counter; 19 | import io.micrometer.core.instrument.Timer; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.concurrent.atomic.AtomicBoolean; 22 | import org.reactivestreams.Subscription; 23 | import reactor.core.CoreSubscriber; 24 | import reactor.core.publisher.Operators; 25 | import reactor.util.context.Context; 26 | 27 | public class MetricsSubscriber extends AtomicBoolean implements Subscription, CoreSubscriber { 28 | private final CoreSubscriber actual; 29 | private final Counter next, complete, error, cancelled; 30 | private final Timer timer; 31 | 32 | private Subscription s; 33 | private long start; 34 | 35 | MetricsSubscriber( 36 | CoreSubscriber actual, 37 | Counter next, 38 | Counter complete, 39 | Counter error, 40 | Counter cancelled, 41 | Timer timer) { 42 | this.actual = actual; 43 | this.next = next; 44 | this.complete = complete; 45 | this.error = error; 46 | this.cancelled = cancelled; 47 | this.timer = timer; 48 | } 49 | 50 | @Override 51 | public void onSubscribe(Subscription s) { 52 | if (Operators.validate(this.s, s)) { 53 | this.s = s; 54 | this.start = System.nanoTime(); 55 | 56 | actual.onSubscribe(this); 57 | } 58 | } 59 | 60 | @Override 61 | public void onNext(T t) { 62 | next.increment(); 63 | actual.onNext(t); 64 | } 65 | 66 | @Override 67 | public void onError(Throwable t) { 68 | if (compareAndSet(false, true)) { 69 | error.increment(); 70 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 71 | } 72 | actual.onError(t); 73 | } 74 | 75 | @Override 76 | public void onComplete() { 77 | if (compareAndSet(false, true)) { 78 | complete.increment(); 79 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 80 | } 81 | actual.onComplete(); 82 | } 83 | 84 | @Override 85 | public void request(long n) { 86 | s.request(n); 87 | } 88 | 89 | @Override 90 | public void cancel() { 91 | if (compareAndSet(false, true)) { 92 | cancelled.increment(); 93 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 94 | } 95 | s.cancel(); 96 | } 97 | 98 | @Override 99 | public Context currentContext() { 100 | return actual.currentContext(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/metrics/MetricsConditionalSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.metrics; 17 | 18 | import io.micrometer.core.instrument.Counter; 19 | import io.micrometer.core.instrument.Timer; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.concurrent.atomic.AtomicBoolean; 22 | import org.reactivestreams.Subscription; 23 | import reactor.core.Fuseable.ConditionalSubscriber; 24 | import reactor.core.publisher.Operators; 25 | import reactor.util.context.Context; 26 | 27 | public class MetricsConditionalSubscriber extends AtomicBoolean 28 | implements Subscription, ConditionalSubscriber { 29 | private final ConditionalSubscriber actual; 30 | private final Counter next, complete, error, cancelled; 31 | private final Timer timer; 32 | 33 | private Subscription s; 34 | private long start; 35 | 36 | MetricsConditionalSubscriber( 37 | ConditionalSubscriber actual, 38 | Counter next, 39 | Counter complete, 40 | Counter error, 41 | Counter cancelled, 42 | Timer timer) { 43 | this.actual = actual; 44 | this.next = next; 45 | this.complete = complete; 46 | this.error = error; 47 | this.cancelled = cancelled; 48 | this.timer = timer; 49 | } 50 | 51 | @Override 52 | public void onSubscribe(Subscription s) { 53 | if (Operators.validate(this.s, s)) { 54 | this.s = s; 55 | this.start = System.nanoTime(); 56 | 57 | actual.onSubscribe(this); 58 | } 59 | } 60 | 61 | @Override 62 | public void onNext(T t) { 63 | next.increment(); 64 | actual.onNext(t); 65 | } 66 | 67 | @Override 68 | public boolean tryOnNext(T t) { 69 | next.increment(); 70 | return actual.tryOnNext(t); 71 | } 72 | 73 | @Override 74 | public void onError(Throwable t) { 75 | if (compareAndSet(false, true)) { 76 | error.increment(); 77 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 78 | } 79 | actual.onError(t); 80 | } 81 | 82 | @Override 83 | public void onComplete() { 84 | if (compareAndSet(false, true)) { 85 | complete.increment(); 86 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 87 | } 88 | actual.onComplete(); 89 | } 90 | 91 | @Override 92 | public void request(long n) { 93 | s.request(n); 94 | } 95 | 96 | @Override 97 | public void cancel() { 98 | if (compareAndSet(false, true)) { 99 | cancelled.increment(); 100 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 101 | } 102 | s.cancel(); 103 | } 104 | 105 | @Override 106 | public Context currentContext() { 107 | return actual.currentContext(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/util/IPCTracingAndMetricsAwareRequestChannelFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.util; 17 | 18 | import io.micrometer.core.instrument.MeterRegistry; 19 | import io.netty.buffer.ByteBuf; 20 | import io.opentracing.Tracer; 21 | import io.rsocket.Payload; 22 | import io.rsocket.ipc.Functions; 23 | import io.rsocket.ipc.Marshaller; 24 | import io.rsocket.ipc.MetadataDecoder; 25 | import io.rsocket.ipc.Unmarshaller; 26 | import io.rsocket.ipc.metrics.Metrics; 27 | import io.rsocket.ipc.tracing.Tag; 28 | import io.rsocket.ipc.tracing.Tracing; 29 | import io.rsocket.util.ByteBufPayload; 30 | import reactor.core.Exceptions; 31 | import reactor.core.publisher.Flux; 32 | 33 | @SuppressWarnings("rawtypes") 34 | public class IPCTracingAndMetricsAwareRequestChannelFunction implements IPCChannelFunction { 35 | 36 | final String route; 37 | final Unmarshaller unmarshaller; 38 | final Marshaller marshaller; 39 | final Functions.HandleRequestHandle rc; 40 | final Tracer tracer; 41 | final MeterRegistry meterRegistry; 42 | 43 | public IPCTracingAndMetricsAwareRequestChannelFunction( 44 | String route, 45 | Unmarshaller unmarshaller, 46 | Marshaller marshaller, 47 | Functions.HandleRequestHandle rc, 48 | Tracer tracer, 49 | MeterRegistry meterRegistry) { 50 | this.route = route; 51 | this.unmarshaller = unmarshaller; 52 | this.marshaller = marshaller; 53 | this.rc = rc; 54 | this.tracer = tracer; 55 | this.meterRegistry = meterRegistry; 56 | } 57 | 58 | @Override 59 | @SuppressWarnings("unchecked") 60 | public Flux apply( 61 | Flux source, Payload payload, MetadataDecoder.Metadata metadata) { 62 | return rc.apply( 63 | unmarshaller.apply(payload.sliceData()), 64 | source.map( 65 | p -> { 66 | try { 67 | ByteBuf dd = p.sliceData(); 68 | Object result = unmarshaller.apply(dd); 69 | p.release(); 70 | return result; 71 | } catch (Throwable t) { 72 | p.release(); 73 | throw Exceptions.propagate(t); 74 | } 75 | }), 76 | metadata.metadata()) 77 | .map(o -> ByteBufPayload.create(marshaller.apply(o))) 78 | .transform( 79 | Tracing.traceAsChild( 80 | tracer, 81 | route, 82 | Tag.of("rsocket.route", route), 83 | Tag.of("rsocket.ipc.role", "server"), 84 | Tag.of("rsocket.ipc.version", "ipc")) 85 | .apply(metadata.spanContext())) 86 | .transform(Metrics.timed(meterRegistry, "rsocket.server", "route", route)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/frames/Metadata.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.frames; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.ByteBufAllocator; 5 | import io.netty.buffer.ByteBufUtil; 6 | import io.netty.buffer.Unpooled; 7 | import io.rsocket.util.NumberUtils; 8 | import java.nio.charset.StandardCharsets; 9 | 10 | @Deprecated 11 | public class Metadata { 12 | // Version 13 | public static final short VERSION = 1; 14 | 15 | public static ByteBuf encode( 16 | ByteBufAllocator allocator, String service, String method, ByteBuf metadata) { 17 | return encode(allocator, service, method, Unpooled.EMPTY_BUFFER, metadata); 18 | } 19 | 20 | public static ByteBuf encode( 21 | ByteBufAllocator allocator, 22 | String service, 23 | String method, 24 | ByteBuf tracing, 25 | ByteBuf metadata) { 26 | ByteBuf byteBuf = allocator.buffer().writeShort(VERSION); 27 | 28 | int serviceLength = NumberUtils.requireUnsignedShort(ByteBufUtil.utf8Bytes(service)); 29 | byteBuf.writeShort(serviceLength); 30 | ByteBufUtil.reserveAndWriteUtf8(byteBuf, service, serviceLength); 31 | 32 | int methodLength = NumberUtils.requireUnsignedShort(ByteBufUtil.utf8Bytes(method)); 33 | byteBuf.writeShort(methodLength); 34 | ByteBufUtil.reserveAndWriteUtf8(byteBuf, method, methodLength); 35 | 36 | byteBuf.writeShort(tracing.readableBytes()); 37 | byteBuf.writeBytes(tracing, tracing.readerIndex(), tracing.readableBytes()); 38 | 39 | byteBuf.writeBytes(metadata, metadata.readerIndex(), metadata.readableBytes()); 40 | 41 | return byteBuf; 42 | } 43 | 44 | public static int getVersion(ByteBuf byteBuf) { 45 | return byteBuf.getShort(0) & 0x7FFF; 46 | } 47 | 48 | public static String getService(ByteBuf byteBuf) { 49 | int offset = Short.BYTES; 50 | 51 | int serviceLength = byteBuf.getShort(offset); 52 | offset += Short.BYTES; 53 | 54 | return byteBuf.toString(offset, serviceLength, StandardCharsets.UTF_8); 55 | } 56 | 57 | public static String getMethod(ByteBuf byteBuf) { 58 | int offset = Short.BYTES; 59 | 60 | int serviceLength = byteBuf.getShort(offset); 61 | offset += Short.BYTES + serviceLength; 62 | 63 | int methodLength = byteBuf.getShort(offset); 64 | offset += Short.BYTES; 65 | 66 | return byteBuf.toString(offset, methodLength, StandardCharsets.UTF_8); 67 | } 68 | 69 | public static ByteBuf getTracing(ByteBuf byteBuf) { 70 | int offset = Short.BYTES; 71 | 72 | int serviceLength = byteBuf.getShort(offset); 73 | offset += Short.BYTES + serviceLength; 74 | 75 | int methodLength = byteBuf.getShort(offset); 76 | offset += Short.BYTES + methodLength; 77 | 78 | int tracingLength = byteBuf.getShort(offset); 79 | offset += Short.BYTES; 80 | 81 | return tracingLength > 0 ? byteBuf.slice(offset, tracingLength) : Unpooled.EMPTY_BUFFER; 82 | } 83 | 84 | public static ByteBuf getMetadata(ByteBuf byteBuf) { 85 | int offset = Short.BYTES; 86 | 87 | int serviceLength = byteBuf.getShort(offset); 88 | offset += Short.BYTES + serviceLength; 89 | 90 | int methodLength = byteBuf.getShort(offset); 91 | offset += Short.BYTES + methodLength; 92 | 93 | int tracingLength = byteBuf.getShort(offset); 94 | offset += Short.BYTES + tracingLength; 95 | 96 | int metadataLength = byteBuf.readableBytes() - offset; 97 | return metadataLength > 0 ? byteBuf.slice(offset, metadataLength) : Unpooled.EMPTY_BUFFER; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/metrics/Metrics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.metrics; 17 | 18 | import io.micrometer.core.instrument.Counter; 19 | import io.micrometer.core.instrument.MeterRegistry; 20 | import io.micrometer.core.instrument.Tag; 21 | import io.micrometer.core.instrument.Tags; 22 | import io.micrometer.core.instrument.Timer; 23 | import java.util.function.Function; 24 | import org.reactivestreams.Publisher; 25 | import reactor.core.Fuseable; 26 | import reactor.core.publisher.Operators; 27 | 28 | public class Metrics { 29 | Metrics() {} 30 | 31 | public static Function, ? extends Publisher> timed( 32 | MeterRegistry registry, String name, String... keyValues) { 33 | return timed(registry, name, Tags.of(keyValues)); 34 | } 35 | 36 | @SuppressWarnings("unchecked") 37 | public static Function, ? extends Publisher> timed( 38 | MeterRegistry registry, String name, Iterable tags) { 39 | Counter next = 40 | Counter.builder(name + ".request").tags("status", "next").tags(tags).register(registry); 41 | Counter complete = 42 | Counter.builder(name + ".request").tags("status", "complete").tags(tags).register(registry); 43 | Counter error = 44 | Counter.builder(name + ".request").tags("status", "error").tags(tags).register(registry); 45 | Counter cancelled = 46 | Counter.builder(name + ".request") 47 | .tags("status", "cancelled") 48 | .tags(tags) 49 | .register(registry); 50 | Timer timer = 51 | Timer.builder(name + ".latency") 52 | .publishPercentiles(0.5, 0.9, 0.95, 0.99) 53 | .tags(tags) 54 | .register(registry); 55 | return Operators.lift( 56 | (scannable, subscriber) -> { 57 | if (scannable instanceof Fuseable) { 58 | if (subscriber instanceof Fuseable.ConditionalSubscriber) { 59 | return new MetricsFuseableConditionalSubscriber<>( 60 | (Fuseable.ConditionalSubscriber) subscriber, 61 | next, 62 | complete, 63 | error, 64 | cancelled, 65 | timer); 66 | } else { 67 | return new MetricsFuseableSubscriber<>( 68 | subscriber, next, complete, error, cancelled, timer); 69 | } 70 | } else { 71 | if (subscriber instanceof Fuseable.ConditionalSubscriber) { 72 | return new MetricsConditionalSubscriber<>( 73 | (Fuseable.ConditionalSubscriber) subscriber, 74 | next, 75 | complete, 76 | error, 77 | cancelled, 78 | timer); 79 | } else { 80 | return new MetricsSubscriber<>(subscriber, next, complete, error, cancelled, timer); 81 | } 82 | } 83 | }); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/routing/SimpleRouter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.routing; 17 | 18 | import io.rsocket.Payload; 19 | import io.rsocket.ipc.MutableRouter; 20 | import io.rsocket.ipc.util.IPCChannelFunction; 21 | import io.rsocket.ipc.util.IPCFunction; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | import reactor.core.publisher.Flux; 25 | import reactor.core.publisher.Mono; 26 | 27 | public class SimpleRouter implements MutableRouter { 28 | final Map>> fireAndForgetRegistry; 29 | final Map>> requestResponseRegistry; 30 | final Map>> requestStreamRegistry; 31 | final Map requestChannelRegistry; 32 | 33 | public SimpleRouter() { 34 | this.fireAndForgetRegistry = new HashMap<>(); 35 | this.requestResponseRegistry = new HashMap<>(); 36 | this.requestStreamRegistry = new HashMap<>(); 37 | this.requestChannelRegistry = new HashMap<>(); 38 | } 39 | 40 | @Override 41 | public IPCFunction> routeFireAndForget(String route) { 42 | return fireAndForgetRegistry.get(route); 43 | } 44 | 45 | @Override 46 | public IPCFunction> routeRequestResponse(String route) { 47 | return requestResponseRegistry.get(route); 48 | } 49 | 50 | @Override 51 | public IPCFunction> routeRequestStream(String route) { 52 | return requestStreamRegistry.get(route); 53 | } 54 | 55 | @Override 56 | public IPCChannelFunction routeRequestChannel(String route) { 57 | return requestChannelRegistry.get(route); 58 | } 59 | 60 | @Override 61 | public SimpleRouter withFireAndForgetRoute(String route, IPCFunction> function) { 62 | fireAndForgetRegistry.put(route, function); 63 | return this; 64 | } 65 | 66 | @Override 67 | public SimpleRouter withRequestResponseRoute(String route, IPCFunction> function) { 68 | requestResponseRegistry.put(route, function); 69 | return this; 70 | } 71 | 72 | @Override 73 | public SimpleRouter withRequestStreamRoute(String route, IPCFunction> function) { 74 | requestStreamRegistry.put(route, function); 75 | return this; 76 | } 77 | 78 | @Override 79 | public SimpleRouter withRequestChannelRoute(String route, IPCChannelFunction function) { 80 | requestChannelRegistry.put(route, function); 81 | return this; 82 | } 83 | 84 | public Map>> getFireAndForgetRegistry() { 85 | return fireAndForgetRegistry; 86 | } 87 | 88 | public Map>> getRequestResponseRegistry() { 89 | return requestResponseRegistry; 90 | } 91 | 92 | public Map>> getRequestStreamRegistry() { 93 | return requestStreamRegistry; 94 | } 95 | 96 | public Map getRequestChannelRegistry() { 97 | return requestChannelRegistry; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/metrics/MetricsFuseableSubscriber.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.metrics; 2 | 3 | import static reactor.core.Fuseable.ASYNC; 4 | 5 | import io.micrometer.core.instrument.Counter; 6 | import io.micrometer.core.instrument.Timer; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | import org.reactivestreams.Subscription; 10 | import reactor.core.CoreSubscriber; 11 | import reactor.core.Fuseable; 12 | import reactor.core.Fuseable.QueueSubscription; 13 | import reactor.core.publisher.Operators; 14 | import reactor.util.annotation.Nullable; 15 | import reactor.util.context.Context; 16 | 17 | @Deprecated 18 | public class MetricsFuseableSubscriber extends AtomicBoolean 19 | implements QueueSubscription, CoreSubscriber { 20 | private final CoreSubscriber actual; 21 | private final Counter next, complete, error, cancelled; 22 | private final Timer timer; 23 | 24 | private QueueSubscription s; 25 | private int sourceMode; 26 | 27 | private long start; 28 | 29 | MetricsFuseableSubscriber( 30 | CoreSubscriber actual, 31 | Counter next, 32 | Counter complete, 33 | Counter error, 34 | Counter cancelled, 35 | Timer timer) { 36 | this.actual = actual; 37 | this.next = next; 38 | this.complete = complete; 39 | this.error = error; 40 | this.cancelled = cancelled; 41 | this.timer = timer; 42 | } 43 | 44 | @Override 45 | @SuppressWarnings("unchecked") 46 | public void onSubscribe(Subscription s) { 47 | if (Operators.validate(this.s, s)) { 48 | this.s = (QueueSubscription) s; 49 | this.start = System.nanoTime(); 50 | 51 | actual.onSubscribe(this); 52 | } 53 | } 54 | 55 | @Override 56 | public void onNext(T t) { 57 | if (sourceMode == ASYNC) { 58 | actual.onNext(null); 59 | } else { 60 | next.increment(); 61 | actual.onNext(t); 62 | } 63 | } 64 | 65 | @Override 66 | public void onError(Throwable t) { 67 | if (compareAndSet(false, true)) { 68 | error.increment(); 69 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 70 | } 71 | actual.onError(t); 72 | } 73 | 74 | @Override 75 | public void onComplete() { 76 | if (compareAndSet(false, true)) { 77 | complete.increment(); 78 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 79 | } 80 | actual.onComplete(); 81 | } 82 | 83 | @Override 84 | public void request(long n) { 85 | s.request(n); 86 | } 87 | 88 | @Override 89 | public void cancel() { 90 | if (compareAndSet(false, true)) { 91 | cancelled.increment(); 92 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 93 | } 94 | s.cancel(); 95 | } 96 | 97 | @Override 98 | public Context currentContext() { 99 | return actual.currentContext(); 100 | } 101 | 102 | @Override 103 | public int requestFusion(int requestedMode) { 104 | int m; 105 | if ((requestedMode & Fuseable.THREAD_BARRIER) != 0) { 106 | return Fuseable.NONE; 107 | } else { 108 | m = s.requestFusion(requestedMode); 109 | } 110 | sourceMode = m; 111 | return m; 112 | } 113 | 114 | @Override 115 | @Nullable 116 | public T poll() { 117 | T v = s.poll(); 118 | if (v != null) { 119 | next.increment(); 120 | return v; 121 | } 122 | return null; 123 | } 124 | 125 | @Override 126 | public boolean isEmpty() { 127 | return s.isEmpty(); 128 | } 129 | 130 | @Override 131 | public void clear() { 132 | s.clear(); 133 | } 134 | 135 | @Override 136 | public int size() { 137 | return s.size(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/metrics/MetricsFuseableConditionalSubscriber.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.metrics; 2 | 3 | import static reactor.core.Fuseable.ASYNC; 4 | 5 | import io.micrometer.core.instrument.Counter; 6 | import io.micrometer.core.instrument.Timer; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | import org.reactivestreams.Subscription; 10 | import reactor.core.Fuseable; 11 | import reactor.core.Fuseable.ConditionalSubscriber; 12 | import reactor.core.Fuseable.QueueSubscription; 13 | import reactor.core.publisher.Operators; 14 | import reactor.util.annotation.Nullable; 15 | import reactor.util.context.Context; 16 | 17 | @Deprecated 18 | public class MetricsFuseableConditionalSubscriber extends AtomicBoolean 19 | implements QueueSubscription, ConditionalSubscriber { 20 | private final ConditionalSubscriber actual; 21 | private final Counter next, complete, error, cancelled; 22 | private final Timer timer; 23 | 24 | private QueueSubscription s; 25 | private int sourceMode; 26 | 27 | private long start; 28 | 29 | MetricsFuseableConditionalSubscriber( 30 | ConditionalSubscriber actual, 31 | Counter next, 32 | Counter complete, 33 | Counter error, 34 | Counter cancelled, 35 | Timer timer) { 36 | this.actual = actual; 37 | this.next = next; 38 | this.complete = complete; 39 | this.error = error; 40 | this.cancelled = cancelled; 41 | this.timer = timer; 42 | } 43 | 44 | @Override 45 | @SuppressWarnings("unchecked") 46 | public void onSubscribe(Subscription s) { 47 | if (Operators.validate(this.s, s)) { 48 | this.s = (QueueSubscription) s; 49 | this.start = System.nanoTime(); 50 | 51 | actual.onSubscribe(this); 52 | } 53 | } 54 | 55 | @Override 56 | public void onNext(T t) { 57 | if (sourceMode == ASYNC) { 58 | actual.onNext(null); 59 | } else { 60 | next.increment(); 61 | actual.onNext(t); 62 | } 63 | } 64 | 65 | @Override 66 | public boolean tryOnNext(T t) { 67 | next.increment(); 68 | return actual.tryOnNext(t); 69 | } 70 | 71 | @Override 72 | public void onError(Throwable t) { 73 | if (compareAndSet(false, true)) { 74 | error.increment(); 75 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 76 | } 77 | actual.onError(t); 78 | } 79 | 80 | @Override 81 | public void onComplete() { 82 | if (compareAndSet(false, true)) { 83 | complete.increment(); 84 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 85 | } 86 | actual.onComplete(); 87 | } 88 | 89 | @Override 90 | public void request(long n) { 91 | s.request(n); 92 | } 93 | 94 | @Override 95 | public void cancel() { 96 | if (compareAndSet(false, true)) { 97 | cancelled.increment(); 98 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 99 | } 100 | s.cancel(); 101 | } 102 | 103 | @Override 104 | public Context currentContext() { 105 | return actual.currentContext(); 106 | } 107 | 108 | @Override 109 | public int requestFusion(int requestedMode) { 110 | int m; 111 | if ((requestedMode & Fuseable.THREAD_BARRIER) != 0) { 112 | return Fuseable.NONE; 113 | } else { 114 | m = s.requestFusion(requestedMode); 115 | } 116 | sourceMode = m; 117 | return m; 118 | } 119 | 120 | @Override 121 | @Nullable 122 | public T poll() { 123 | T v = s.poll(); 124 | if (v != null) { 125 | next.increment(); 126 | return v; 127 | } 128 | return null; 129 | } 130 | 131 | @Override 132 | public boolean isEmpty() { 133 | return s.isEmpty(); 134 | } 135 | 136 | @Override 137 | public void clear() { 138 | s.clear(); 139 | } 140 | 141 | @Override 142 | public int size() { 143 | return s.size(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/metrics/MetricsFuseableSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.metrics; 17 | 18 | import static reactor.core.Fuseable.ASYNC; 19 | 20 | import io.micrometer.core.instrument.Counter; 21 | import io.micrometer.core.instrument.Timer; 22 | import java.util.concurrent.TimeUnit; 23 | import java.util.concurrent.atomic.AtomicBoolean; 24 | import org.reactivestreams.Subscription; 25 | import reactor.core.CoreSubscriber; 26 | import reactor.core.Fuseable; 27 | import reactor.core.Fuseable.QueueSubscription; 28 | import reactor.core.publisher.Operators; 29 | import reactor.util.annotation.Nullable; 30 | import reactor.util.context.Context; 31 | 32 | public class MetricsFuseableSubscriber extends AtomicBoolean 33 | implements QueueSubscription, CoreSubscriber { 34 | private final CoreSubscriber actual; 35 | private final Counter next, complete, error, cancelled; 36 | private final Timer timer; 37 | 38 | private QueueSubscription s; 39 | private int sourceMode; 40 | 41 | private long start; 42 | 43 | MetricsFuseableSubscriber( 44 | CoreSubscriber actual, 45 | Counter next, 46 | Counter complete, 47 | Counter error, 48 | Counter cancelled, 49 | Timer timer) { 50 | this.actual = actual; 51 | this.next = next; 52 | this.complete = complete; 53 | this.error = error; 54 | this.cancelled = cancelled; 55 | this.timer = timer; 56 | } 57 | 58 | @Override 59 | @SuppressWarnings("unchecked") 60 | public void onSubscribe(Subscription s) { 61 | if (Operators.validate(this.s, s)) { 62 | this.s = (QueueSubscription) s; 63 | this.start = System.nanoTime(); 64 | 65 | actual.onSubscribe(this); 66 | } 67 | } 68 | 69 | @Override 70 | public void onNext(T t) { 71 | if (sourceMode == ASYNC) { 72 | actual.onNext(null); 73 | } else { 74 | next.increment(); 75 | actual.onNext(t); 76 | } 77 | } 78 | 79 | @Override 80 | public void onError(Throwable t) { 81 | if (compareAndSet(false, true)) { 82 | error.increment(); 83 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 84 | } 85 | actual.onError(t); 86 | } 87 | 88 | @Override 89 | public void onComplete() { 90 | if (compareAndSet(false, true)) { 91 | complete.increment(); 92 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 93 | } 94 | actual.onComplete(); 95 | } 96 | 97 | @Override 98 | public void request(long n) { 99 | s.request(n); 100 | } 101 | 102 | @Override 103 | public void cancel() { 104 | if (compareAndSet(false, true)) { 105 | cancelled.increment(); 106 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 107 | } 108 | s.cancel(); 109 | } 110 | 111 | @Override 112 | public Context currentContext() { 113 | return actual.currentContext(); 114 | } 115 | 116 | @Override 117 | public int requestFusion(int requestedMode) { 118 | int m; 119 | if ((requestedMode & Fuseable.THREAD_BARRIER) != 0) { 120 | return Fuseable.NONE; 121 | } else { 122 | m = s.requestFusion(requestedMode); 123 | } 124 | sourceMode = m; 125 | return m; 126 | } 127 | 128 | @Override 129 | @Nullable 130 | public T poll() { 131 | T v = s.poll(); 132 | if (v != null) { 133 | next.increment(); 134 | return v; 135 | } 136 | return null; 137 | } 138 | 139 | @Override 140 | public boolean isEmpty() { 141 | return s.isEmpty(); 142 | } 143 | 144 | @Override 145 | public void clear() { 146 | s.clear(); 147 | } 148 | 149 | @Override 150 | public int size() { 151 | return s.size(); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /rsocket-ipc-graphql/src/test/java/io/rsocket/graphql/GraphQLDataFetchers.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.graphql; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import graphql.schema.DataFetcher; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class GraphQLDataFetchers { 9 | 10 | private static final Map authors; 11 | 12 | private static final Map books; 13 | 14 | static { 15 | authors = new HashMap<>(); 16 | authors.put("author-1", new Author("author-1", "Joanne", "Rowling")); 17 | authors.put("author-2", new Author("author-2", "Herman", "Melville")); 18 | authors.put("author-3", new Author("author-3", "Anne", "Rice")); 19 | 20 | books = new HashMap<>(); 21 | books.put( 22 | "book-1", 23 | new Book( 24 | "book-1", "Harry Potter and the Philosopher's Stone", 223, authors.get("author-1"))); 25 | books.put("book-2", new Book("book-2", "Moby Dick", 635, authors.get("author-2"))); 26 | books.put( 27 | "book-3", new Book("book-3", "Interview with the vampire", 371, authors.get("author-3"))); 28 | } 29 | 30 | public static DataFetcher getBookByIdDataFetcher() { 31 | return dataFetchingEnvironment -> { 32 | String bookId = dataFetchingEnvironment.getArgument("id"); 33 | System.out.println("looking for book id " + bookId); 34 | Book book = books.get(bookId); 35 | 36 | return book; 37 | }; 38 | } 39 | 40 | public static DataFetcher getAuthorDataFetcher() { 41 | return dataFetchingEnvironment -> { 42 | Book book = dataFetchingEnvironment.getSource(); 43 | String authorId = book.getAuthor().getId(); 44 | System.out.println("looking for author id " + authorId); 45 | return authors.get(authorId); 46 | }; 47 | } 48 | 49 | @JsonIgnoreProperties(ignoreUnknown = true) 50 | public static class Book { 51 | String id; 52 | String name; 53 | int pageCount; 54 | Author author; 55 | 56 | public Book() {} 57 | 58 | public Book(String id, String name, int pageCount, Author author) { 59 | this.id = id; 60 | this.name = name; 61 | this.pageCount = pageCount; 62 | this.author = author; 63 | } 64 | 65 | public String getId() { 66 | return id; 67 | } 68 | 69 | public void setId(String id) { 70 | this.id = id; 71 | } 72 | 73 | public String getName() { 74 | return name; 75 | } 76 | 77 | public void setName(String name) { 78 | this.name = name; 79 | } 80 | 81 | public int getPageCount() { 82 | return pageCount; 83 | } 84 | 85 | public void setPageCount(int pageCount) { 86 | this.pageCount = pageCount; 87 | } 88 | 89 | public Author getAuthor() { 90 | return author; 91 | } 92 | 93 | public void setAuthor(Author author) { 94 | this.author = author; 95 | } 96 | 97 | @Override 98 | public String toString() { 99 | return "Book{" 100 | + "id='" 101 | + id 102 | + '\'' 103 | + ", name='" 104 | + name 105 | + '\'' 106 | + ", pageCount=" 107 | + pageCount 108 | + ", author=" 109 | + author 110 | + '}'; 111 | } 112 | } 113 | 114 | @JsonIgnoreProperties(ignoreUnknown = true) 115 | public static class Author { 116 | String id; 117 | String firstName; 118 | String lastName; 119 | 120 | public Author() {} 121 | 122 | public Author(String id, String firstName, String lastName) { 123 | this.id = id; 124 | this.firstName = firstName; 125 | this.lastName = lastName; 126 | } 127 | 128 | public String getId() { 129 | return id; 130 | } 131 | 132 | public void setId(String id) { 133 | this.id = id; 134 | } 135 | 136 | public String getFirstName() { 137 | return firstName; 138 | } 139 | 140 | public void setFirstName(String firstName) { 141 | this.firstName = firstName; 142 | } 143 | 144 | public String getLastName() { 145 | return lastName; 146 | } 147 | 148 | public void setLastName(String lastName) { 149 | this.lastName = lastName; 150 | } 151 | 152 | @Override 153 | public String toString() { 154 | return "Author{" 155 | + "id='" 156 | + id 157 | + '\'' 158 | + ", firstName='" 159 | + firstName 160 | + '\'' 161 | + ", lastName='" 162 | + lastName 163 | + '\'' 164 | + '}'; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/metrics/MetricsFuseableConditionalSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.metrics; 17 | 18 | import static reactor.core.Fuseable.ASYNC; 19 | 20 | import io.micrometer.core.instrument.Counter; 21 | import io.micrometer.core.instrument.Timer; 22 | import java.util.concurrent.TimeUnit; 23 | import java.util.concurrent.atomic.AtomicBoolean; 24 | import org.reactivestreams.Subscription; 25 | import reactor.core.Fuseable; 26 | import reactor.core.Fuseable.ConditionalSubscriber; 27 | import reactor.core.Fuseable.QueueSubscription; 28 | import reactor.core.publisher.Operators; 29 | import reactor.util.annotation.Nullable; 30 | import reactor.util.context.Context; 31 | 32 | public class MetricsFuseableConditionalSubscriber extends AtomicBoolean 33 | implements QueueSubscription, ConditionalSubscriber { 34 | private final ConditionalSubscriber actual; 35 | private final Counter next, complete, error, cancelled; 36 | private final Timer timer; 37 | 38 | private QueueSubscription s; 39 | private int sourceMode; 40 | 41 | private long start; 42 | 43 | MetricsFuseableConditionalSubscriber( 44 | ConditionalSubscriber actual, 45 | Counter next, 46 | Counter complete, 47 | Counter error, 48 | Counter cancelled, 49 | Timer timer) { 50 | this.actual = actual; 51 | this.next = next; 52 | this.complete = complete; 53 | this.error = error; 54 | this.cancelled = cancelled; 55 | this.timer = timer; 56 | } 57 | 58 | @Override 59 | @SuppressWarnings("unchecked") 60 | public void onSubscribe(Subscription s) { 61 | if (Operators.validate(this.s, s)) { 62 | this.s = (QueueSubscription) s; 63 | this.start = System.nanoTime(); 64 | 65 | actual.onSubscribe(this); 66 | } 67 | } 68 | 69 | @Override 70 | public void onNext(T t) { 71 | if (sourceMode == ASYNC) { 72 | actual.onNext(null); 73 | } else { 74 | next.increment(); 75 | actual.onNext(t); 76 | } 77 | } 78 | 79 | @Override 80 | public boolean tryOnNext(T t) { 81 | next.increment(); 82 | return actual.tryOnNext(t); 83 | } 84 | 85 | @Override 86 | public void onError(Throwable t) { 87 | if (compareAndSet(false, true)) { 88 | error.increment(); 89 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 90 | } 91 | actual.onError(t); 92 | } 93 | 94 | @Override 95 | public void onComplete() { 96 | if (compareAndSet(false, true)) { 97 | complete.increment(); 98 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 99 | } 100 | actual.onComplete(); 101 | } 102 | 103 | @Override 104 | public void request(long n) { 105 | s.request(n); 106 | } 107 | 108 | @Override 109 | public void cancel() { 110 | if (compareAndSet(false, true)) { 111 | cancelled.increment(); 112 | timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS); 113 | } 114 | s.cancel(); 115 | } 116 | 117 | @Override 118 | public Context currentContext() { 119 | return actual.currentContext(); 120 | } 121 | 122 | @Override 123 | public int requestFusion(int requestedMode) { 124 | int m; 125 | if ((requestedMode & Fuseable.THREAD_BARRIER) != 0) { 126 | return Fuseable.NONE; 127 | } else { 128 | m = s.requestFusion(requestedMode); 129 | } 130 | sourceMode = m; 131 | return m; 132 | } 133 | 134 | @Override 135 | @Nullable 136 | public T poll() { 137 | T v = s.poll(); 138 | if (v != null) { 139 | next.increment(); 140 | return v; 141 | } 142 | return null; 143 | } 144 | 145 | @Override 146 | public boolean isEmpty() { 147 | return s.isEmpty(); 148 | } 149 | 150 | @Override 151 | public void clear() { 152 | s.clear(); 153 | } 154 | 155 | @Override 156 | public int size() { 157 | return s.size(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /rsocket-rpc-core/src/main/java/io/rsocket/rpc/tracing/Tracing.java: -------------------------------------------------------------------------------- 1 | package io.rsocket.rpc.tracing; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.ByteBufAllocator; 5 | import io.netty.buffer.ByteBufUtil; 6 | import io.netty.buffer.Unpooled; 7 | import io.opentracing.SpanContext; 8 | import io.opentracing.Tracer; 9 | import io.opentracing.propagation.Format; 10 | import io.opentracing.propagation.TextMapExtractAdapter; 11 | import io.rsocket.rpc.frames.Metadata; 12 | import io.rsocket.util.NumberUtils; 13 | import java.nio.charset.StandardCharsets; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.function.Function; 17 | import org.reactivestreams.Publisher; 18 | import reactor.core.publisher.Operators; 19 | 20 | @Deprecated 21 | public class Tracing { 22 | private Tracing() {} 23 | 24 | public static SpanContext deserializeTracingMetadata(Tracer tracer, ByteBuf metadata) { 25 | if (tracer == null) { 26 | return null; 27 | } 28 | 29 | ByteBuf tracing = Metadata.getTracing(metadata); 30 | 31 | if (tracing.readableBytes() < 0) { 32 | return null; 33 | } 34 | 35 | Map metadataMap = byteBufToMap(tracing); 36 | if (metadataMap.isEmpty()) { 37 | return null; 38 | } 39 | 40 | return deserializeTracingMetadata(tracer, metadataMap); 41 | } 42 | 43 | public static SpanContext deserializeTracingMetadata( 44 | Tracer tracer, Map metadata) { 45 | TextMapExtractAdapter adapter = new TextMapExtractAdapter(metadata); 46 | return tracer.extract(Format.Builtin.TEXT_MAP, adapter); 47 | } 48 | 49 | public static ByteBuf mapToByteBuf(ByteBufAllocator allocator, Map map) { 50 | if (map == null || map.isEmpty()) { 51 | return Unpooled.EMPTY_BUFFER; 52 | } 53 | 54 | ByteBuf byteBuf = allocator.buffer(); 55 | 56 | for (Map.Entry entry : map.entrySet()) { 57 | String key = entry.getKey(); 58 | int keyLength = NumberUtils.requireUnsignedShort(ByteBufUtil.utf8Bytes(key)); 59 | byteBuf.writeShort(keyLength); 60 | ByteBufUtil.reserveAndWriteUtf8(byteBuf, key, keyLength); 61 | 62 | String value = entry.getValue(); 63 | int valueLength = NumberUtils.requireUnsignedShort(ByteBufUtil.utf8Bytes(value)); 64 | byteBuf.writeShort(valueLength); 65 | ByteBufUtil.reserveAndWriteUtf8(byteBuf, value, keyLength); 66 | } 67 | 68 | return byteBuf; 69 | } 70 | 71 | public static Map byteBufToMap(ByteBuf byteBuf) { 72 | Map map = new HashMap<>(); 73 | 74 | while (byteBuf.readableBytes() > 0) { 75 | int keyLength = byteBuf.readShort(); 76 | String key = (String) byteBuf.readCharSequence(keyLength, StandardCharsets.UTF_8); 77 | 78 | int valueLength = byteBuf.readShort(); 79 | String value = (String) byteBuf.readCharSequence(valueLength, StandardCharsets.UTF_8); 80 | 81 | map.put(key, value); 82 | } 83 | 84 | return map; 85 | } 86 | 87 | public static 88 | Function, Function, ? extends Publisher>> trace( 89 | Tracer tracer, String name, Tag... tags) { 90 | return map -> 91 | Operators.lift( 92 | (scannable, subscriber) -> 93 | new SpanSubscriber( 94 | subscriber, subscriber.currentContext(), tracer, map, name, tags)); 95 | } 96 | 97 | public static 98 | Function, Function, ? extends Publisher>> 99 | trace() { 100 | return map -> publisher -> publisher; 101 | } 102 | 103 | public static 104 | Function, ? extends Publisher>> traceAsChild() { 105 | return (spanContext) -> publisher -> publisher; 106 | } 107 | 108 | public static 109 | Function, ? extends Publisher>> traceAsChild( 110 | Tracer tracer, String name, Tag... tags) { 111 | return (spanContext) -> { 112 | if (spanContext == null) { 113 | return Operators.lift( 114 | (scannable, subscriber) -> 115 | new SpanSubscriber( 116 | subscriber, subscriber.currentContext(), tracer, null, name, tags)); 117 | } else { 118 | return Operators.lift( 119 | (scannable, subscriber) -> 120 | new SpanSubscriber( 121 | subscriber, 122 | subscriber.currentContext(), 123 | tracer, 124 | null, 125 | spanContext, 126 | name, 127 | tags)); 128 | } 129 | }; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/frames/Metadata.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc.frames; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.ByteBufAllocator; 20 | import io.netty.buffer.ByteBufUtil; 21 | import io.netty.buffer.Unpooled; 22 | import io.rsocket.util.NumberUtils; 23 | import java.nio.charset.StandardCharsets; 24 | 25 | public class Metadata { 26 | // Version 27 | public static final short VERSION = 1; 28 | 29 | public static ByteBuf encode( 30 | ByteBufAllocator allocator, String service, String method, ByteBuf metadata) { 31 | return encode(allocator, service, method, Unpooled.EMPTY_BUFFER, metadata); 32 | } 33 | 34 | public static ByteBuf encode( 35 | ByteBufAllocator allocator, 36 | String service, 37 | String method, 38 | ByteBuf tracing, 39 | ByteBuf metadata) { 40 | ByteBuf byteBuf = allocator.buffer().writeShort(VERSION); 41 | 42 | int serviceLength = NumberUtils.requireUnsignedShort(ByteBufUtil.utf8Bytes(service)); 43 | byteBuf.writeShort(serviceLength); 44 | ByteBufUtil.reserveAndWriteUtf8(byteBuf, service, serviceLength); 45 | 46 | int methodLength = NumberUtils.requireUnsignedShort(ByteBufUtil.utf8Bytes(method)); 47 | byteBuf.writeShort(methodLength); 48 | ByteBufUtil.reserveAndWriteUtf8(byteBuf, method, methodLength); 49 | 50 | byteBuf.writeShort(tracing.readableBytes()); 51 | byteBuf.writeBytes(tracing, tracing.readerIndex(), tracing.readableBytes()); 52 | 53 | byteBuf.writeBytes(metadata, metadata.readerIndex(), metadata.readableBytes()); 54 | 55 | return byteBuf; 56 | } 57 | 58 | public static boolean canDecode(ByteBuf byteBuf) { 59 | int offset = Short.BYTES; 60 | 61 | if (byteBuf.readableBytes() < offset + Short.BYTES) { 62 | return false; 63 | } 64 | int serviceLength = byteBuf.getShort(offset); 65 | offset += Short.BYTES + serviceLength; 66 | 67 | if (byteBuf.readableBytes() < offset + Short.BYTES) { 68 | return false; 69 | } 70 | int methodLength = byteBuf.getShort(offset); 71 | offset += Short.BYTES + methodLength; 72 | 73 | if (byteBuf.readableBytes() < offset + Short.BYTES) { 74 | return false; 75 | } 76 | int tracingLength = byteBuf.getShort(offset); 77 | offset += Short.BYTES + tracingLength; 78 | 79 | return byteBuf.readableBytes() >= offset; 80 | } 81 | 82 | public static int getVersion(ByteBuf byteBuf) { 83 | return byteBuf.getShort(0) & 0x7FFF; 84 | } 85 | 86 | public static String getService(ByteBuf byteBuf) { 87 | int offset = Short.BYTES; 88 | 89 | int serviceLength = byteBuf.getShort(offset); 90 | offset += Short.BYTES; 91 | 92 | return byteBuf.toString(offset, serviceLength, StandardCharsets.UTF_8); 93 | } 94 | 95 | public static String getMethod(ByteBuf byteBuf) { 96 | int offset = Short.BYTES; 97 | 98 | int serviceLength = byteBuf.getShort(offset); 99 | offset += Short.BYTES + serviceLength; 100 | 101 | int methodLength = byteBuf.getShort(offset); 102 | offset += Short.BYTES; 103 | 104 | return byteBuf.toString(offset, methodLength, StandardCharsets.UTF_8); 105 | } 106 | 107 | public static ByteBuf getTracing(ByteBuf byteBuf) { 108 | int offset = Short.BYTES; 109 | 110 | int serviceLength = byteBuf.getShort(offset); 111 | offset += Short.BYTES + serviceLength; 112 | 113 | int methodLength = byteBuf.getShort(offset); 114 | offset += Short.BYTES + methodLength; 115 | 116 | int tracingLength = byteBuf.getShort(offset); 117 | offset += Short.BYTES; 118 | 119 | return tracingLength > 0 ? byteBuf.slice(offset, tracingLength) : Unpooled.EMPTY_BUFFER; 120 | } 121 | 122 | public static ByteBuf getMetadata(ByteBuf byteBuf) { 123 | int offset = Short.BYTES; 124 | 125 | int serviceLength = byteBuf.getShort(offset); 126 | offset += Short.BYTES + serviceLength; 127 | 128 | int methodLength = byteBuf.getShort(offset); 129 | offset += Short.BYTES + methodLength; 130 | 131 | int tracingLength = byteBuf.getShort(offset); 132 | offset += Short.BYTES + tracingLength; 133 | 134 | int metadataLength = byteBuf.readableBytes() - offset; 135 | return metadataLength > 0 ? byteBuf.slice(offset, metadataLength) : Unpooled.EMPTY_BUFFER; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/main/java/io/rsocket/ipc/RoutingServerRSocket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.opentracing.Tracer; 19 | import io.rsocket.Payload; 20 | import io.rsocket.RSocket; 21 | import io.rsocket.ipc.decoders.CompositeMetadataDecoder; 22 | import io.rsocket.ipc.exception.RouteNotFound; 23 | import io.rsocket.ipc.util.IPCChannelFunction; 24 | import io.rsocket.ipc.util.IPCFunction; 25 | import org.reactivestreams.Publisher; 26 | import reactor.core.publisher.Flux; 27 | import reactor.core.publisher.Mono; 28 | 29 | public class RoutingServerRSocket implements RSocket { 30 | 31 | final Router router; 32 | final MetadataDecoder decoder; 33 | 34 | public RoutingServerRSocket(Router router) { 35 | this(new CompositeMetadataDecoder(), router); 36 | } 37 | 38 | public RoutingServerRSocket(Tracer tracer, Router router) { 39 | this(new CompositeMetadataDecoder(tracer), router); 40 | } 41 | 42 | public RoutingServerRSocket(MetadataDecoder decoder, Router router) { 43 | this.decoder = decoder; 44 | this.router = router; 45 | } 46 | 47 | @Override 48 | public Mono fireAndForget(Payload payload) { 49 | try { 50 | final MetadataDecoder.Metadata decodedMetadata = this.decoder.decode(payload.sliceMetadata()); 51 | 52 | final String route = decodedMetadata.route(); 53 | final IPCFunction> monoIPCFunction = this.router.routeFireAndForget(route); 54 | 55 | if (monoIPCFunction == null) { 56 | return Mono.error(new RouteNotFound("Nothing found for route " + route)); 57 | } 58 | 59 | final Mono response = monoIPCFunction.apply(payload, decodedMetadata); 60 | 61 | payload.release(); 62 | 63 | return response; 64 | } catch (Throwable t) { 65 | payload.release(); 66 | return Mono.error(t); 67 | } 68 | } 69 | 70 | @Override 71 | public Mono requestResponse(Payload payload) { 72 | try { 73 | final MetadataDecoder.Metadata decodedMetadata = this.decoder.decode(payload.sliceMetadata()); 74 | 75 | final String route = decodedMetadata.route(); 76 | final IPCFunction> monoIPCFunction = this.router.routeRequestResponse(route); 77 | 78 | if (monoIPCFunction == null) { 79 | return Mono.error(new NullPointerException("nothing found for route " + route)); 80 | } 81 | 82 | final Mono response = monoIPCFunction.apply(payload, decodedMetadata); 83 | 84 | payload.release(); 85 | 86 | return response; 87 | } catch (Throwable t) { 88 | payload.release(); 89 | return Mono.error(t); 90 | } 91 | } 92 | 93 | @Override 94 | public Flux requestStream(Payload payload) { 95 | try { 96 | final MetadataDecoder.Metadata decodedMetadata = this.decoder.decode(payload.sliceMetadata()); 97 | 98 | final String route = decodedMetadata.route(); 99 | final IPCFunction> ffContext = this.router.routeRequestStream(route); 100 | 101 | if (ffContext == null) { 102 | return Flux.error(new NullPointerException("nothing found for route " + route)); 103 | } 104 | 105 | final Flux response = ffContext.apply(payload, decodedMetadata); 106 | 107 | payload.release(); 108 | 109 | return response; 110 | } catch (Throwable t) { 111 | payload.release(); 112 | return Flux.error(t); 113 | } 114 | } 115 | 116 | @Override 117 | public Flux requestChannel(Publisher payloads) { 118 | return Flux.from(payloads) 119 | .switchOnFirst( 120 | (firstSignal, flux) -> { 121 | final Payload payload = firstSignal.get(); 122 | 123 | if (payload != null) { 124 | return doRequestChannel(payload, flux); 125 | } 126 | 127 | return flux; 128 | }); 129 | } 130 | 131 | private Flux doRequestChannel(Payload payload, Flux payloadFlux) { 132 | try { 133 | final MetadataDecoder.Metadata decodedMetadata = this.decoder.decode(payload.sliceMetadata()); 134 | 135 | final String route = decodedMetadata.route(); 136 | final IPCChannelFunction ffContext = this.router.routeRequestChannel(route); 137 | 138 | if (ffContext == null) { 139 | payload.release(); 140 | return Flux.error(new NullPointerException("nothing found for route " + route)); 141 | } 142 | 143 | return ffContext.apply(payloadFlux, payload, decodedMetadata); 144 | } catch (Throwable t) { 145 | payload.release(); 146 | return Flux.error(t); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | jobs: 4 | include: 5 | - stage: build 6 | language: cpp 7 | os: linux 8 | jdk: oraclejdk8 9 | before_install: 10 | - pushd $HOME 11 | - ls 12 | - ls ./protobuf-3.6.1 13 | - bash ./build/rsocket/rsocket-rpc-java/ci/install_protobuf.sh 14 | - popd 15 | - java -version 16 | - protoc --version 17 | script: "./ci/travis.sh" 18 | - stage: build 19 | language: cpp 20 | os: osx 21 | osx_image: xcode11.2 22 | compiler: clang 23 | before_install: 24 | - sudo rm -rf /Library/Java/JavaVirtualMachines/* 25 | - curl -OLJ https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u252-b09.1/OpenJDK8U-jdk_x64_mac_hotspot_8u252b09.tar.gz 26 | - tar -xzf OpenJDK8U-jdk_x64_mac_hotspot*.tar.gz 27 | - sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-8.jdk 28 | - sudo mv jdk8*/* /Library/Java/JavaVirtualMachines/openjdk-8.jdk/ 29 | - ls /Library/Java/JavaVirtualMachines/openjdk-8.jdk 30 | - export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-8.jdk/Contents/Home 31 | - java -version 32 | - brew uninstall --ignore-dependencies protobuf 33 | - pushd $HOME 34 | - ls 35 | - ls ./protobuf-3.6.1 36 | - bash ./build/rsocket/rsocket-rpc-java/ci/install_protobuf.sh 37 | - popd 38 | - protoc --version 39 | script: "./ci/travis.sh" 40 | - stage: deploy 41 | language: cpp 42 | os: windows 43 | filter_secrets: false 44 | env: 45 | - GRADLE_OPTS="-Dorg.gradle.daemon=false" 46 | before_install: 47 | - rm -r "/c/Program Files (x86)/Microsoft Visual Studio 14.0" 48 | - export PATH=$PATH:"/c/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Tools/MSVC/14.16.27023/bin/HostX86/x64" 49 | - choco install -y adoptopenjdk8 --version 8.232.9 50 | - export PATH=$PATH:"/c/Program Files/AdoptOpenJDK/jdk-8.0.232.09-hotspot/bin" 51 | - wget https://github.com/google/protobuf/releases/download/v3.6.1/protobuf-cpp-3.6.1.tar.gz 52 | - tar -xzf protobuf-cpp-3.6.1.tar.gz 53 | - pushd protobuf-3.6.1/cmake 54 | - mkdir build && cd build 55 | - cmake -A x64 -DCMAKE_INSTALL_PREFIX="/c/Program Files/protobuf" -DCMAKE_CXX_FLAGS="-std=c++11 -EHsc" -Dprotobuf_BUILD_TESTS=OFF .. 56 | - cmake --build . --config Release --target install 57 | - popd 58 | script: "./ci/travis.sh" 59 | before_cache: 60 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 61 | notifications: 62 | email: false 63 | cache: 64 | directories: 65 | - "$HOME/protobuf-3.6.1/" 66 | - "$HOME/.gradle/caches/" 67 | - "$HOME/.gradle/wrapper/" 68 | - "$HOME/.m2" 69 | env: 70 | global: 71 | - secure: "ErthuwJHqk8MPlGQcwaSV1mk6DI1z6YHg+XnNUE9yx/EXUqVMyazu5u9VqlZhMMQQm6II8Y8oBF1uK4JdNVKa44xCt8OM3d/HbG5WhYyigNuKaOgK19FGfA7hciY4gzcMsix/lOryqu8JlYqABAIJFwZIJFtnEdylxUO46/PLP01TOHVOrnaUXpTNm6esaXfmgv1ToQCtwALSgo/xy2KYFA6vpzcTYnMii9eMaOZdy3162t8M6equ2WHhqiKvxCX1+M8D76/WoRF1v45dekAV3UKSBf5b3UcK1W1V/NxtwMufD7tXLGxDsBo2JWQOLjx+AyiKGwhVkZBbvfECDKKjq3x5NMjvjqleprYNEKQYibCNvhXVpZPZgKt899RHOXMjt+fr+iq1aHpHU98iFWXyp+MgYbe9Fez/xcWDH9rri+LKsCgZd1PtpDjTjUsZWesAsXYQatTGOZ0w0cOkURbVhUKltnf/AzuhOlj3XqJmO30vKiBhtwzyfvrURc+0GqWlRoU0C1qskmtmI10PJRR1Qv3eMKvvi6XIQfit9J01V/0sJ+WoG6980hJy0N421qr1+LNg3WmDGtMp6UyoAvjUbDFaW3xzGdbsNmLzWqfaFY1kM7ry6WaVVbGEYz0uHKEvMnqLrM3t18qO4wQsaskGCYEaYSmFp4oMT4pDRgCzvU=" 72 | - secure: "sQYup+Bn5NeIKRa1EWMcgWyfP4kHmD5WZ0slTIjZjGRBqqAR7SdRv1XklkEoUE2BXKxEmhKn5bPA3itmn0ix3N4y9km0q9DRQ0RJF+MFJcSg0CYpSlfjGUEUGoIdYQjreZ+AETAyniLGDVE28tWBQ+GliwfKViiE0LESDihfcqUe/7lcDuc/UMP9h7ecazLjwCmmVNYM94ZfTVoPrbC3Jdtb1sPd65/yZPj7pgBzk/vh82E5tmo0JYr81Rq8CKiYoQ2W7qiTmKL/X33mVxvC9lRRNoqgfAyofgnv5zMbvj1krCcKrkuOJ+A/wTOnkZ1MEL/YK0ilNw0g9oxY0MRXEq9jvms4M2bvGyj0jdKB+ctsXMf9l7ZvWdj1kTEHguQxpjg6hhxrwjRwKk5y0LPJFi3Nqxet00+aB2Wqg1AJ5KwBZ9s2e6nhfAOMnWFVct8mxnFfb/8cu1XfyET5ABBK7PozpcY8VQUVqpoSheKuGdFYRXXgA4o42t+Uxt8G/XX5TRJpaD2FtPa9YwtsrCx6HtCEVetSFZ6X0JeHPdzLBn3XTqyPBoc4bD28VFnEs1NKj+Sbj09sDKH93HQ+PafcJnFiPC7Pdk7NedHCqmEXtppvA+L4pL0V9zDNn93pKLgXsCovcrX7nCnfWk2IjGnDMgZaxWPnW0r0AWsl0BwbqjM=" 73 | - secure: "eV4F5Jp3n8Qi79ATwAUvQdhhZzg/jxKVpTe1ovF0paSWtETe5Whuqb+52nLF4um8NrXDLuTM2Ms12o2rUThaqnEgKWR9HSgwXaBNyYs1zWL3J5+nhrX4/jMKtZ+VY3pH+Sk5KiDgf/jModLrXk6k7uN330PKA3hVLlzA0qc+4QXtnwZNZOQ9sjQsScVxAJ6hBJ8TpUZy4ragg07LTa87p679YFXmsClIQcLdY2eTAIXgNuv0HAe1Eyog3Q5m/ObOdQD0fO3M9Qj9QHWWeh6Rc7dcDA8Nvd6peN+dLaG7DK7Gj+lLyx3K6iXrnHzBHHg1sKKcMeejxxD/0d/auzaqP2ORudSYrblo26AU9fHEUKkdcGS0m5NwOYF9slB1U8KXbIFPPNT+W48h8OgTKPErDvnliujirPBpF9pAC8vRhRORMMbKWQIr14HrxhJ9EBhfJ6iDVBM+xEjVzAOxjRuXia8o5Bzo3rmQwDO+Wvb1bJOZ0u7gPwNkMJF7Nj7ScEx1JLaw2RW1/xhQADxoh74NnNr3XJlicoyLZx+mDNOu0wkW0Q/F04FDlCy78VhSMgoiGPNWDtrjCWWFUhSSCbZFL5sjqFXjz24v0raqKqT12oOUwX9ueeIb0gQsMVj8zSnb7F7oZJpbKaPdofS5eEuNMSKzoJ7Imx5mkryMoL0Czic=" 74 | - secure: "re/ISO0n8AqNiM3IuAIJ6toh6HCx7pCZk55FXGPfAYxUOy4qmcLRKyfjW1WwfkHhEaVbr9SnNK0KgUEmG61ueBzRTXh/LQc2bKd1aTR4Q/wocUKd7h5SmASf//nqh1AXicgvPxi+NJxHhmalceNfDwxHlgUdYPvUsWu0WBCxE9DZQMZe6wh7zmWBhlfHA1s+ijdmtx6BlUmR9USx5B0XVZtbd+LA0dNqLiy+WOVAmegr4IzDDFDFEPyKTjEiiztL2b5ohti8vofxpbf4V7N5Ho2l5vUn8+b4IdH3TuPw4a91g9sN+WEJg/7Wm0TbU7WqNanQAXFyfPvPrP4GNZpo7qEr8eDTnI5VvyQrYKOxr00HNF5DxTlysHdCa3oyvNTYZJYgTSK1mGHQHfGrPMqhVNyFSrP5XnKFZ3mVf7lrm+kosZqE2DteSaPXUF4Bjx3CY50qxifxi6i0KH4WsfnOP8LUZsvx/PUBf3Grw/rxQjtW3stRCUbeBnhfDH4VQJvawPcqx5A26SLZelkoq2Q3e9nf5jf9/ISBhnE5YnixsVfir9NL/Y5CEPK9DvWXaMCiJzro5TFnUSVPkmG/AC1y05Ci961ICxSgK7JmnbmGRl8yeoJE0pWK4zc3ySl5to9yGSvSeiIpPMiQ2Tio2gkSRpAAPrCjBQjBF3Z0ywovowk=" 75 | 76 | -------------------------------------------------------------------------------- /rsocket-ipc-core/src/test/java/io/rsocket/ipc/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.rsocket.ipc; 17 | 18 | import io.netty.buffer.ByteBufAllocator; 19 | import io.rsocket.RSocket; 20 | import io.rsocket.core.RSocketConnector; 21 | import io.rsocket.core.RSocketServer; 22 | import io.rsocket.ipc.decoders.CompositeMetadataDecoder; 23 | import io.rsocket.ipc.encoders.DefaultMetadataEncoder; 24 | import io.rsocket.ipc.marshallers.Primitives; 25 | import io.rsocket.ipc.marshallers.Strings; 26 | import io.rsocket.transport.local.LocalClientTransport; 27 | import io.rsocket.transport.local.LocalServerTransport; 28 | import java.util.concurrent.atomic.AtomicBoolean; 29 | import org.junit.Assert; 30 | import org.junit.Test; 31 | import reactor.core.publisher.Flux; 32 | import reactor.core.publisher.Mono; 33 | import reactor.test.StepVerifier; 34 | 35 | public class IntegrationTest { 36 | @Test 37 | public void test() { 38 | RequestHandlingRSocket requestHandler = 39 | new RequestHandlingRSocket(new CompositeMetadataDecoder()); 40 | 41 | RSocketServer.create() 42 | .acceptor((setup, sendingSocket) -> Mono.just(requestHandler)) 43 | .bind(LocalServerTransport.create("test-local-server")) 44 | .block(); 45 | 46 | RSocket rsocket = 47 | RSocketConnector.connectWith(LocalClientTransport.create("test-local-server")).block(); 48 | 49 | AtomicBoolean ff = new AtomicBoolean(); 50 | 51 | IPCRSocket service = 52 | Server.service("HelloService") 53 | .noMeterRegistry() 54 | .noTracer() 55 | .marshall(Strings.marshaller()) 56 | .unmarshall(Strings.unmarshaller()) 57 | .requestResponse("hello", (s, byteBuf) -> Mono.just("Hello -> " + s)) 58 | .requestResponse("goodbye", (s, byteBuf) -> Mono.just("Goodbye -> " + s)) 59 | .requestResponse( 60 | "count", 61 | Primitives.intMarshaller(), 62 | (charSequence, byteBuf) -> Mono.just(charSequence.length())) 63 | .requestResponse( 64 | "increment", 65 | Primitives.intUnmarshaller(), 66 | Primitives.intMarshaller(), 67 | (integer, byteBuf) -> Mono.just(integer + 1)) 68 | .requestStream( 69 | "helloStream", (s, byteBuf) -> Flux.range(1, 10).map(i -> i + " - Hello -> " + s)) 70 | .requestStream( 71 | "toString", 72 | Primitives.longUnmarshaller(), 73 | (aLong, byteBuf) -> Flux.just(String.valueOf(aLong))) 74 | .fireAndForget( 75 | "ff", 76 | (s, byteBuf) -> { 77 | ff.set(true); 78 | return Mono.empty(); 79 | }) 80 | .requestChannel("helloChannel", (s, publisher, byteBuf) -> Flux.just("Hello -> " + s)) 81 | .toIPCRSocket(); 82 | 83 | requestHandler.withEndpoint(service); 84 | 85 | Client helloService = 86 | Client.service("HelloService") 87 | .rsocket(rsocket) 88 | .customMetadataEncoder(new DefaultMetadataEncoder(ByteBufAllocator.DEFAULT)) 89 | .noMeterRegistry() 90 | .noTracer() 91 | .marshall(Strings.marshaller()) 92 | .unmarshall(Strings.unmarshaller()); 93 | 94 | String r1 = helloService.requestResponse("hello").apply("Alice").block(); 95 | Assert.assertEquals("Hello -> Alice", r1); 96 | 97 | String r2 = helloService.requestResponse("goodbye").apply("Bob").block(); 98 | Assert.assertEquals("Goodbye -> Bob", r2); 99 | 100 | StepVerifier.create(helloService.requestStream("helloStream").apply("Carol")) 101 | .expectNextCount(10) 102 | .expectComplete() 103 | .verify(); 104 | 105 | helloService.fireAndForget("ff").apply("boom").block(); 106 | Assert.assertTrue(ff.get()); 107 | 108 | String r3 = helloService.requestChannel("helloChannel").apply(Mono.just("Eve")).blockLast(); 109 | Assert.assertEquals("Hello -> Eve", r3); 110 | 111 | int count = 112 | helloService.requestResponse("count", Primitives.intUnmarshaller()).apply("hello").block(); 113 | Assert.assertEquals(5, count); 114 | 115 | long l = System.currentTimeMillis(); 116 | String toString = 117 | helloService.requestStream("toString", Primitives.longMarshaller()).apply(l).blockLast(); 118 | Assert.assertEquals(String.valueOf(l), toString); 119 | 120 | Integer increment = 121 | helloService 122 | .requestResponse("increment", Primitives.intMarshaller(), Primitives.intUnmarshaller()) 123 | .apply(1) 124 | .block(); 125 | Assert.assertEquals(2, increment.intValue()); 126 | } 127 | } 128 | --------------------------------------------------------------------------------