├── webflux-vs-rsocket ├── src │ ├── main │ │ ├── resources │ │ │ └── application.properties │ │ └── java │ │ │ └── com │ │ │ └── vinsguru │ │ │ └── webfluxvsrsocket │ │ │ └── WebfluxVsRsocketApplication.java │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── webfluxvsrsocket │ │ └── WebfluxVsRsocketApplicationTests.java ├── rest-square-service │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── com │ │ │ └── vinsguru │ │ │ └── rest │ │ │ ├── RestSquareApplication.java │ │ │ └── SquareController.java │ ├── Dockerfile │ └── pom.xml ├── rsocket-square-service │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── com │ │ │ └── vinsguru │ │ │ └── rsocket │ │ │ ├── RSocketSquareApplication.java │ │ │ └── SquareController.java │ ├── Dockerfile │ └── pom.xml ├── aggregate-service │ ├── Dockerfile │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── com │ │ │ └── vinsguru │ │ │ └── aggregate │ │ │ ├── AggregateSquareApplication.java │ │ │ ├── controller │ │ │ └── AggregateController.java │ │ │ └── service │ │ │ ├── RestService.java │ │ │ └── RSocketService.java │ └── pom.xml ├── .gitignore ├── docker-compose.yaml └── pom.xml ├── README.md ├── stock-service ├── src │ ├── main │ │ ├── resources │ │ │ └── application.properties │ │ └── java │ │ │ └── com │ │ │ └── vinsguru │ │ │ └── stockservice │ │ │ ├── dto │ │ │ └── StockTickDto.java │ │ │ ├── StockServiceApplication.java │ │ │ ├── controller │ │ │ └── StockController.java │ │ │ └── service │ │ │ ├── StockService.java │ │ │ └── Stock.java │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── stockservice │ │ └── StockServiceApplicationTests.java ├── .gitignore └── pom.xml ├── ssl-tls ├── cert.pem ├── client.truststore └── rsocket-server.p12 ├── trading-service ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── vinsguru │ │ │ │ └── tradingservice │ │ │ │ ├── dto │ │ │ │ ├── TradeType.java │ │ │ │ ├── TradeStatus.java │ │ │ │ ├── TransactionType.java │ │ │ │ ├── TransactionStatus.java │ │ │ │ ├── UserDto.java │ │ │ │ ├── UserStockDto.java │ │ │ │ ├── StockTradeRequest.java │ │ │ │ ├── TransactionResponse.java │ │ │ │ ├── StockTickDto.java │ │ │ │ ├── StockTradeResponse.java │ │ │ │ └── TransactionRequest.java │ │ │ │ ├── entity │ │ │ │ └── UserStock.java │ │ │ │ ├── TradingServiceApplication.java │ │ │ │ ├── repository │ │ │ │ └── UserStockRepository.java │ │ │ │ ├── config │ │ │ │ └── RSocketClientConfig.java │ │ │ │ ├── controller │ │ │ │ ├── UserController.java │ │ │ │ └── TradeController.java │ │ │ │ ├── client │ │ │ │ ├── UserClient.java │ │ │ │ └── StockClient.java │ │ │ │ ├── util │ │ │ │ └── EntityDtoUtil.java │ │ │ │ └── service │ │ │ │ ├── UserStockService.java │ │ │ │ └── TradeService.java │ │ └── resources │ │ │ └── application.properties │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── tradingservice │ │ └── TradingServiceApplicationTests.java ├── .gitignore └── pom.xml ├── user-service ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── vinsguru │ │ │ │ └── userservice │ │ │ │ ├── dto │ │ │ │ ├── TransactionType.java │ │ │ │ ├── TransactionStatus.java │ │ │ │ ├── OperationType.java │ │ │ │ ├── UserDto.java │ │ │ │ ├── TransactionResponse.java │ │ │ │ └── TransactionRequest.java │ │ │ │ ├── repository │ │ │ │ └── UserRepository.java │ │ │ │ ├── UserServiceApplication.java │ │ │ │ ├── entity │ │ │ │ └── User.java │ │ │ │ ├── config │ │ │ │ └── RSocketServerConfig.java │ │ │ │ ├── controller │ │ │ │ ├── UserTransactionController.java │ │ │ │ └── UserController.java │ │ │ │ ├── service │ │ │ │ ├── DataSetupService.java │ │ │ │ ├── UserService.java │ │ │ │ └── UserTransactionService.java │ │ │ │ └── util │ │ │ │ └── EntityDtoUtil.java │ │ └── resources │ │ │ └── application.properties │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── userservice │ │ ├── UserTransactionTest.java │ │ └── UserCrudTest.java ├── .gitignore └── pom.xml ├── spring-rsocket ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── vinsguru │ │ │ │ └── springrsocket │ │ │ │ ├── assignment │ │ │ │ ├── GuessNumberResponse.java │ │ │ │ ├── GuessNumberController.java │ │ │ │ └── GuessNumberService.java │ │ │ │ ├── dto │ │ │ │ ├── ClientConnectionRequest.java │ │ │ │ ├── ComputationRequestDto.java │ │ │ │ ├── ComputationResponseDto.java │ │ │ │ ├── error │ │ │ │ │ ├── StatusCode.java │ │ │ │ │ └── ErrorEvent.java │ │ │ │ ├── ChartResponseDto.java │ │ │ │ └── Response.java │ │ │ │ ├── SpringRsocketApplication.java │ │ │ │ ├── controller │ │ │ │ ├── MathVariableController.java │ │ │ │ ├── BatchJobController.java │ │ │ │ ├── ConnectionHandler.java │ │ │ │ ├── MathController.java │ │ │ │ └── InputValidationController.java │ │ │ │ ├── config │ │ │ │ └── RSocketServerConfig.java │ │ │ │ ├── security │ │ │ │ ├── TestMain.java │ │ │ │ ├── UserDetailsServiceImpl.java │ │ │ │ ├── UserRepository.java │ │ │ │ ├── SecuredMathController.java │ │ │ │ └── RSocketSecurityConfig.java │ │ │ │ └── service │ │ │ │ ├── MathClientManager.java │ │ │ │ └── MathService.java │ │ └── resources │ │ │ └── application.properties │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── springrsocket │ │ ├── client │ │ ├── serviceregistry │ │ │ ├── RSocketServerInstance.java │ │ │ └── ServiceRegistryClient.java │ │ ├── controller │ │ │ └── BatchJobResponseController.java │ │ └── config │ │ │ └── LoadBalanceTargetConfig.java │ │ ├── Lec02DestinationVariableTest.java │ │ ├── Lec04CallbackTest.java │ │ ├── Lec07ConnectionManagerTest.java │ │ ├── Lec10ServerSideLoadBalancingTest.java │ │ ├── Lec11ClientSideLoadBalancingTest.java │ │ ├── assignment │ │ └── Player.java │ │ ├── Lec05AssignmentTest.java │ │ ├── Lec12SslTest.java │ │ ├── Lec06ConnectionSetupTest.java │ │ ├── Lec08ConnectionRetryTest.java │ │ ├── Lec03InputValidationTest.java │ │ ├── Lec09SessionResumptionTest.java │ │ ├── Lec01RSocketTest.java │ │ └── Lec13SecurityTest.java ├── .gitignore └── pom.xml ├── nginx ├── docker-compose.yaml └── conf │ └── nginx.conf ├── simple-rsocket ├── src │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── vinsguru │ │ │ └── rsocket │ │ │ ├── client │ │ │ └── CallbackService.java │ │ │ ├── Lec03BackpressureTest.java │ │ │ ├── Lec02CallbackTest.java │ │ │ ├── Lec05ConnectionSetupTest.java │ │ │ ├── Lec04PersistentConnectionTest.java │ │ │ └── Lec01RSocketTest.java │ └── main │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── rsocket │ │ ├── dto │ │ ├── RequestDto.java │ │ ├── ChartResponseDto.java │ │ └── ResponseDto.java │ │ ├── service │ │ ├── FastProducerService.java │ │ ├── FreeService.java │ │ ├── SocketAcceptorImpl.java │ │ ├── BatchJobService.java │ │ └── MathService.java │ │ ├── Server.java │ │ └── util │ │ └── ObjectUtil.java └── pom.xml └── .gitignore /webflux-vs-rsocket/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## This project contains the source code for my RSocket course. 2 | -------------------------------------------------------------------------------- /stock-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7070 -------------------------------------------------------------------------------- /ssl-tls/cert.pem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/rsocket-course/HEAD/ssl-tls/cert.pem -------------------------------------------------------------------------------- /webflux-vs-rsocket/rest-square-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=6566 -------------------------------------------------------------------------------- /ssl-tls/client.truststore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/rsocket-course/HEAD/ssl-tls/client.truststore -------------------------------------------------------------------------------- /ssl-tls/rsocket-server.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/rsocket-course/HEAD/ssl-tls/rsocket-server.p12 -------------------------------------------------------------------------------- /webflux-vs-rsocket/rsocket-square-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=6565 -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.6-jre-slim 2 | 3 | WORKDIR /usr/app 4 | 5 | ADD target/*jar app.jar 6 | 7 | CMD java -jar app.jar -------------------------------------------------------------------------------- /webflux-vs-rsocket/rest-square-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.6-jre-slim 2 | 3 | WORKDIR /usr/app 4 | 5 | ADD target/*jar app.jar 6 | 7 | CMD java -jar app.jar -------------------------------------------------------------------------------- /webflux-vs-rsocket/rsocket-square-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.6-jre-slim 2 | 3 | WORKDIR /usr/app 4 | 5 | ADD target/*jar app.jar 6 | 7 | CMD java -jar app.jar -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/TradeType.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | public enum TradeType { 4 | BUY, 5 | SELL; 6 | } 7 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/TradeStatus.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | public enum TradeStatus { 4 | COMPLETED, 5 | FAILED; 6 | } 7 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/dto/TransactionType.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.dto; 2 | 3 | public enum TransactionType { 4 | 5 | CREDIT, 6 | DEBIT; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | rest.service.url=http://localhost:6566/rest-service/rest/square/ 2 | rsocket.service.host=localhost 3 | rsocket.service.port=6565 -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/TransactionType.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | public enum TransactionType { 4 | 5 | CREDIT, 6 | DEBIT; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/dto/TransactionStatus.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.dto; 2 | 3 | public enum TransactionStatus { 4 | 5 | COMPLETED, 6 | FAILED; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/dto/OperationType.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.dto; 2 | 3 | public enum OperationType { 4 | GET, 5 | POST, 6 | PUT, 7 | DELETE; 8 | } 9 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/TransactionStatus.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | public enum TransactionStatus { 4 | 5 | COMPLETED, 6 | FAILED; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /trading-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | stock.service.host=localhost 2 | stock.service.port=7070 3 | user.service.host=localhost 4 | user.service.port=7071 5 | de.flapdoodle.mongodb.embedded.version=4.4.1 6 | -------------------------------------------------------------------------------- /user-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7071 2 | #spring.rsocket.server.transport=websocket 3 | #spring.rsocket.server.mapping-path=/user-service 4 | de.flapdoodle.mongodb.embedded.version=4.4.1 -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/assignment/GuessNumberResponse.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.assignment; 2 | 3 | public enum GuessNumberResponse { 4 | LESSER, 5 | GREATER, 6 | EQUAL; 7 | } 8 | -------------------------------------------------------------------------------- /nginx/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | nginx: 4 | image: nginx:1.15-alpine 5 | volumes: 6 | - ./conf:/etc/nginx/conf.d 7 | ports: 8 | - 6566:6566 9 | command: "nginx -c /etc/nginx/conf.d/nginx.conf" 10 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/dto/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class UserDto { 9 | 10 | private String id; 11 | private String name; 12 | private int balance; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class UserDto { 9 | 10 | private String id; 11 | private String name; 12 | private int balance; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/ClientConnectionRequest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class ClientConnectionRequest { 9 | 10 | private String clientId; 11 | private String secretKey; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /trading-service/src/test/java/com/vinsguru/tradingservice/TradingServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class TradingServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/src/test/java/com/vinsguru/webfluxvsrsocket/WebfluxVsRsocketApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.webfluxvsrsocket; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class WebfluxVsRsocketApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/UserStockDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class UserStockDto { 9 | 10 | private String id; 11 | private String userId; 12 | private String stockSymbol; 13 | private Integer quantity; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/StockTradeRequest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class StockTradeRequest { 9 | 10 | private String userId; 11 | private String stockSymbol; 12 | private int quantity; 13 | private TradeType tradeType; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/dto/TransactionResponse.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class TransactionResponse { 9 | 10 | private String userId; 11 | private int amount; 12 | private TransactionType type; 13 | private TransactionStatus status; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=6565 2 | #spring.rsocket.server.ssl.enabled=true 3 | #spring.rsocket.server.ssl.key-store-type=PKCS12 4 | #spring.rsocket.server.ssl.key-store=/home/vins/Documents/workspace/github/vins-courses/rsocket/ssl-tls/rsocket-server.p12 5 | #spring.rsocket.server.ssl.key-store-password=password 6 | #spring.rsocket.server.ssl.key-alias=rsocket -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/ComputationRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class ComputationRequestDto { 13 | private int input; 14 | } 15 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/TransactionResponse.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class TransactionResponse { 9 | 10 | private String userId; 11 | private int amount; 12 | private TransactionType type; 13 | private TransactionStatus status; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.repository; 2 | 3 | import com.vinsguru.userservice.entity.User; 4 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface UserRepository extends ReactiveMongoRepository { 9 | } 10 | -------------------------------------------------------------------------------- /stock-service/src/main/java/com/vinsguru/stockservice/dto/StockTickDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.stockservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class StockTickDto { 13 | 14 | private String code; 15 | private int price; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/ComputationResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class ComputationResponseDto { 13 | private int input; 14 | private int output; 15 | } 16 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/StockTickDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class StockTickDto { 13 | 14 | private String code; 15 | private int price; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/entity/UserStock.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.entity; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | import org.springframework.data.annotation.Id; 6 | 7 | @Data 8 | @ToString 9 | public class UserStock { 10 | 11 | @Id 12 | private String id; 13 | private String userId; 14 | private String stockSymbol; 15 | private Integer quantity; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/UserServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /stock-service/src/main/java/com/vinsguru/stockservice/StockServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.stockservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StockServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(StockServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/TradingServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TradingServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TradingServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/StockTradeResponse.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | @Data 7 | @ToString 8 | public class StockTradeResponse { 9 | 10 | private String userId; 11 | private String stockSymbol; 12 | private int quantity; 13 | private TradeType tradeType; 14 | private TradeStatus tradeStatus; 15 | private int price; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/rest-square-service/src/main/java/com/vinsguru/rest/RestSquareApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rest; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestSquareApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestSquareApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/dto/TransactionRequest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class TransactionRequest { 13 | 14 | private String userId; 15 | private int amount; 16 | private TransactionType type; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/src/main/java/com/vinsguru/webfluxvsrsocket/WebfluxVsRsocketApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.webfluxvsrsocket; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class WebfluxVsRsocketApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(WebfluxVsRsocketApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/client/serviceregistry/RSocketServerInstance.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.client.serviceregistry; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class RSocketServerInstance { 13 | 14 | private String host; 15 | private int port; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/dto/TransactionRequest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class TransactionRequest { 13 | 14 | private String userId; 15 | private int amount; 16 | private TransactionType type; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/rsocket-square-service/src/main/java/com/vinsguru/rsocket/RSocketSquareApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RSocketSquareApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RSocketSquareApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/src/main/java/com/vinsguru/aggregate/AggregateSquareApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregate; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AggregateSquareApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AggregateSquareApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 1; 3 | 4 | error_log /var/log/nginx/error.log warn; 5 | pid /var/run/nginx.pid; 6 | 7 | daemon off; 8 | 9 | 10 | events { 11 | worker_connections 1024; 12 | } 13 | 14 | stream { 15 | 16 | upstream rsocket-servers { 17 | server 172.31.0.1:7070; 18 | server 172.31.0.1:7071; 19 | server 172.31.0.1:7072; 20 | } 21 | 22 | server { 23 | 24 | listen 6566; 25 | proxy_pass rsocket-servers; 26 | 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/error/StatusCode.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto.error; 2 | 3 | public enum StatusCode { 4 | 5 | EC001 ("given number is not within range"), 6 | EC002 ("your usage limit exceeded"); 7 | 8 | private final String description; 9 | 10 | StatusCode(String description) { 11 | this.description = description; 12 | } 13 | 14 | public String getDescription() { 15 | return description; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/error/ErrorEvent.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto.error; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @ToString 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class ErrorEvent { 15 | 16 | private StatusCode statusCode; 17 | private final LocalDate date = LocalDate.now(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/SpringRsocketApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @SpringBootApplication 8 | public class SpringRsocketApplication { 9 | 10 | public static void main(String[] args) { 11 | SpringApplication.run(SpringRsocketApplication.class, args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /spring-rsocket/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /stock-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /trading-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /user-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.ToString; 6 | import org.springframework.data.annotation.Id; 7 | 8 | @Data 9 | @ToString 10 | @NoArgsConstructor 11 | public class User { 12 | 13 | @Id 14 | private String id; 15 | private String name; 16 | private int balance; 17 | 18 | public User(String name, int balance) { 19 | this.name = name; 20 | this.balance = balance; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | rest-service: 4 | build: ./rest-square-service 5 | image: vinsdocker/rest-square-service 6 | rsocket-service: 7 | build: ./rsocket-square-service 8 | image: vinsdocker/rsocket-square-service 9 | aggregate-service: 10 | build: ./aggregate-service 11 | image: vinsdocker/aggregate-service 12 | environment: 13 | - REST_SERVICE_URL=http://rest-service:6566/rest-service/rest/square/ 14 | - RSOCKET_SERVICE_HOST=rsocket-service 15 | - RSOCKET_SERVICE_PORT=6565 16 | ports: 17 | - 8080:8080 -------------------------------------------------------------------------------- /simple-rsocket/src/test/java/com/vinsguru/rsocket/client/CallbackService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.client; 2 | 3 | import com.vinsguru.rsocket.dto.ResponseDto; 4 | import com.vinsguru.rsocket.util.ObjectUtil; 5 | import io.rsocket.Payload; 6 | import io.rsocket.RSocket; 7 | import reactor.core.publisher.Mono; 8 | 9 | public class CallbackService implements RSocket { 10 | 11 | @Override 12 | public Mono fireAndForget(Payload payload) { 13 | System.out.println("Client received : " + ObjectUtil.toObject(payload, ResponseDto.class)); 14 | return Mono.empty(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/rest-square-service/src/main/java/com/vinsguru/rest/SquareController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rest; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.PathVariable; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequestMapping("rest-service") 10 | public class SquareController { 11 | 12 | @GetMapping("rest/square/{input}") 13 | public Integer findSquare(@PathVariable int input){ 14 | return input * input; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/dto/RequestDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.dto; 2 | 3 | public class RequestDto { 4 | 5 | private int input; 6 | 7 | public RequestDto() { 8 | } 9 | 10 | public RequestDto(int input) { 11 | this.input = input; 12 | } 13 | 14 | public int getInput() { 15 | return input; 16 | } 17 | 18 | public void setInput(int input) { 19 | this.input = input; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "RequestDto{" + 25 | "input=" + input + 26 | '}'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/repository/UserStockRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.repository; 2 | 3 | import com.vinsguru.tradingservice.entity.UserStock; 4 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.publisher.Mono; 8 | 9 | @Repository 10 | public interface UserStockRepository extends ReactiveMongoRepository { 11 | Mono findByUserIdAndStockSymbol(String userId, String stockSymbol); 12 | Flux findByUserId(String userId); 13 | } 14 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/service/FastProducerService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.service; 2 | 3 | import io.rsocket.Payload; 4 | import io.rsocket.RSocket; 5 | import io.rsocket.util.DefaultPayload; 6 | import reactor.core.publisher.Flux; 7 | 8 | public class FastProducerService implements RSocket { 9 | 10 | @Override 11 | public Flux requestStream(Payload payload) { 12 | return Flux.range(1, 1000) 13 | .map(i -> i + "") 14 | .doOnNext(System.out::println) 15 | .doFinally(System.out::println) 16 | .map(DefaultPayload::create); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/client/controller/BatchJobResponseController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.client.controller; 2 | 3 | import org.springframework.messaging.handler.annotation.MessageMapping; 4 | import org.springframework.stereotype.Controller; 5 | import reactor.core.publisher.Mono; 6 | 7 | @Controller 8 | public class BatchJobResponseController { 9 | 10 | @MessageMapping("batch.job.response") 11 | public Mono response(Mono integerMono){ 12 | return integerMono 13 | .doOnNext(i -> System.out.println("Client received : " + i)) 14 | .then(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/assignment/GuessNumberController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.assignment; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.messaging.handler.annotation.MessageMapping; 5 | import org.springframework.stereotype.Controller; 6 | import reactor.core.publisher.Flux; 7 | 8 | @Controller 9 | public class GuessNumberController { 10 | 11 | @Autowired 12 | private GuessNumberService service; 13 | 14 | @MessageMapping("guess.a.number") 15 | public Flux play(Flux flux){ 16 | return this.service.play(flux); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/controller/MathVariableController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.controller; 2 | 3 | import org.springframework.messaging.handler.annotation.DestinationVariable; 4 | import org.springframework.messaging.handler.annotation.MessageMapping; 5 | import org.springframework.stereotype.Controller; 6 | import reactor.core.publisher.Mono; 7 | 8 | @Controller 9 | @MessageMapping("math.service") 10 | public class MathVariableController { 11 | 12 | @MessageMapping("print.{input}") 13 | public Mono print(@DestinationVariable int input){ 14 | System.out.println("Received : " + input); 15 | return Mono.empty(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/Server.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import com.vinsguru.rsocket.service.SocketAcceptorImpl; 4 | import io.rsocket.core.RSocketServer; 5 | import io.rsocket.transport.netty.server.CloseableChannel; 6 | import io.rsocket.transport.netty.server.TcpServerTransport; 7 | 8 | public class Server { 9 | 10 | public static void main(String[] args) { 11 | 12 | RSocketServer socketServer = RSocketServer.create(new SocketAcceptorImpl()); 13 | CloseableChannel closeableChannel = socketServer.bindNow(TcpServerTransport.create(6565)); 14 | 15 | // keep listening 16 | closeableChannel.onClose().block(); 17 | 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/rsocket-square-service/src/main/java/com/vinsguru/rsocket/SquareController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import org.springframework.messaging.handler.annotation.MessageMapping; 4 | import org.springframework.stereotype.Controller; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.publisher.Mono; 7 | 8 | @Controller 9 | public class SquareController { 10 | 11 | @MessageMapping("rr.square") 12 | public Mono findSquare(Mono integerMono){ 13 | return integerMono.map(i -> i * i); 14 | } 15 | 16 | @MessageMapping("rc.square") 17 | public Flux findSquare(Flux integerFlux){ 18 | return integerFlux.map(i -> i * i); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/config/RSocketServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.config; 2 | 3 | import io.rsocket.core.Resume; 4 | import org.springframework.boot.rsocket.server.RSocketServerCustomizer; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import java.time.Duration; 9 | 10 | @Configuration 11 | public class RSocketServerConfig { 12 | 13 | @Bean 14 | public RSocketServerCustomizer customizer(){ 15 | return c -> c.resume(resumeStrategy()); 16 | } 17 | 18 | private Resume resumeStrategy(){ 19 | return new Resume() 20 | .sessionDuration(Duration.ofMinutes(5)); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/security/TestMain.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.security; 2 | 3 | import org.springframework.util.RouteMatcher; 4 | import org.springframework.web.util.pattern.PathPatternRouteMatcher; 5 | 6 | import java.util.Map; 7 | 8 | public class TestMain { 9 | 10 | public static void main(String[] args) { 11 | PathPatternRouteMatcher matcher = new PathPatternRouteMatcher(); 12 | Map map = matcher.matchAndExtract("**\\.table", new RouteMatcher.Route() { 13 | @Override 14 | public String value() { 15 | return "math.service.secured.table"; 16 | } 17 | }); 18 | 19 | System.out.println(map); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /stock-service/src/main/java/com/vinsguru/stockservice/controller/StockController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.stockservice.controller; 2 | 3 | import com.vinsguru.stockservice.dto.StockTickDto; 4 | import com.vinsguru.stockservice.service.StockService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.messaging.handler.annotation.MessageMapping; 7 | import org.springframework.stereotype.Controller; 8 | import reactor.core.publisher.Flux; 9 | 10 | @Controller 11 | public class StockController { 12 | 13 | @Autowired 14 | private StockService stockService; 15 | 16 | @MessageMapping("stock.ticks") 17 | public Flux stockPrice(){ 18 | return this.stockService.getStockPrice(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/security/UserDetailsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.security; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.core.userdetails.ReactiveUserDetailsService; 5 | import org.springframework.security.core.userdetails.UserDetails; 6 | import org.springframework.stereotype.Service; 7 | import reactor.core.publisher.Mono; 8 | 9 | @Service 10 | public class UserDetailsServiceImpl implements ReactiveUserDetailsService { 11 | 12 | @Autowired 13 | private UserRepository repository; 14 | 15 | @Override 16 | public Mono findByUsername(String username) { 17 | return Mono.fromSupplier(() -> this.repository.findByUsername(username)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/client/serviceregistry/ServiceRegistryClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.client.serviceregistry; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | @Service 9 | public class ServiceRegistryClient { 10 | 11 | private List instances; 12 | 13 | public ServiceRegistryClient() { 14 | this.instances = Arrays.asList( 15 | new RSocketServerInstance("localhost", 7070), 16 | new RSocketServerInstance("localhost", 7071), 17 | new RSocketServerInstance("localhost", 7072) 18 | ); 19 | } 20 | 21 | public List getInstances(){ 22 | return this.instances; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/rsocket-square-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | webflux-vs-rsocket 7 | com.vinsguru 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | rsocket-square-service 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-rsocket 18 | 19 | 20 | -------------------------------------------------------------------------------- /stock-service/src/main/java/com/vinsguru/stockservice/service/StockService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.stockservice.service; 2 | 3 | import com.vinsguru.stockservice.dto.StockTickDto; 4 | import org.springframework.stereotype.Service; 5 | import reactor.core.publisher.Flux; 6 | 7 | import java.time.Duration; 8 | 9 | @Service 10 | public class StockService { 11 | 12 | private static final Stock AMZN = new Stock(1000, "AMZN", 20); 13 | private static final Stock AAPL = new Stock(100, "AAPL", 3); 14 | private static final Stock MSFT = new Stock(200, "MSFT", 5); 15 | 16 | public Flux getStockPrice(){ 17 | return Flux.interval(Duration.ofSeconds(2)) 18 | .flatMap(i -> Flux.just(AMZN, AAPL, MSFT)) 19 | .map(s -> new StockTickDto(s.getCode(), s.getPrice())); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/rest-square-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | webflux-vs-rsocket 7 | com.vinsguru 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | rest-square-service 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-webflux 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/dto/ChartResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.dto; 2 | 3 | public class ChartResponseDto { 4 | 5 | private int input; 6 | private int output; 7 | 8 | public ChartResponseDto() { 9 | } 10 | 11 | public ChartResponseDto(int input, int output) { 12 | this.input = input; 13 | this.output = output; 14 | } 15 | 16 | public int getInput() { 17 | return input; 18 | } 19 | 20 | public int getOutput() { 21 | return output; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | String graphFormat = getFormat(this.output); 27 | return String.format(graphFormat, this.input, "X"); 28 | } 29 | 30 | private String getFormat(int value){ 31 | return "%3s|%" + value + "s"; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/ChartResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto; 2 | 3 | public class ChartResponseDto { 4 | 5 | private int input; 6 | private int output; 7 | 8 | public ChartResponseDto() { 9 | } 10 | 11 | public ChartResponseDto(int input, int output) { 12 | this.input = input; 13 | this.output = output; 14 | } 15 | 16 | public int getInput() { 17 | return input; 18 | } 19 | 20 | public int getOutput() { 21 | return output; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | String graphFormat = getFormat(this.output); 27 | return String.format(graphFormat, this.input, "X"); 28 | } 29 | 30 | private String getFormat(int value){ 31 | return "%3s|%" + value + "s"; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/config/RSocketClientConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.messaging.rsocket.RSocketConnectorConfigurer; 6 | import reactor.util.retry.Retry; 7 | 8 | import java.time.Duration; 9 | 10 | @Configuration 11 | public class RSocketClientConfig { 12 | 13 | @Bean 14 | public RSocketConnectorConfigurer connectorConfigurer(){ 15 | return c -> c.reconnect(retryStrategy()); 16 | } 17 | 18 | private Retry retryStrategy(){ 19 | return Retry.fixedDelay(Long.MAX_VALUE, Duration.ofSeconds(2)) 20 | .doBeforeRetry(s -> System.out.println("Lost connection. Retry : " + s.totalRetriesInARow())); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/service/FreeService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.service; 2 | 3 | import io.rsocket.Payload; 4 | import org.reactivestreams.Publisher; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.publisher.Mono; 7 | 8 | public class FreeService extends MathService { 9 | 10 | @Override 11 | public Mono fireAndForget(Payload payload) { 12 | return Mono.empty(); 13 | } 14 | 15 | @Override 16 | public Mono requestResponse(Payload payload) { 17 | return Mono.empty(); 18 | } 19 | 20 | @Override 21 | public Flux requestStream(Payload payload) { 22 | return super.requestStream(payload).take(3); 23 | } 24 | 25 | @Override 26 | public Flux requestChannel(Publisher payloads) { 27 | return super.requestChannel(payloads).take(3); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/dto/ResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.dto; 2 | 3 | public class ResponseDto { 4 | 5 | private int input; 6 | private int output; 7 | 8 | public ResponseDto() { 9 | } 10 | 11 | public ResponseDto(int input, int output) { 12 | this.input = input; 13 | this.output = output; 14 | } 15 | 16 | public int getInput() { 17 | return input; 18 | } 19 | 20 | public void setInput(int input) { 21 | this.input = input; 22 | } 23 | 24 | public int getOutput() { 25 | return output; 26 | } 27 | 28 | public void setOutput(int output) { 29 | this.output = output; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "ResponseDto{" + 35 | "input=" + input + 36 | ", output=" + output + 37 | '}'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /stock-service/src/main/java/com/vinsguru/stockservice/service/Stock.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.stockservice.service; 2 | 3 | import java.util.concurrent.ThreadLocalRandom; 4 | 5 | public class Stock { 6 | 7 | private int price; 8 | private final String code; 9 | private final int volatility; 10 | 11 | public Stock(int price, String code, int volatility) { 12 | this.price = price; 13 | this.code = code; 14 | this.volatility = volatility; 15 | } 16 | 17 | public int getPrice() { 18 | this.updatePrice(); 19 | return price; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | private void updatePrice(){ 27 | int random = ThreadLocalRandom.current().nextInt(-1 * volatility, volatility + 1); 28 | this.price = random + this.price; 29 | this.price = Math.max(this.price, 0); 30 | } 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | # Compiled class file 4 | **/*.class 5 | 6 | # Log file 7 | **/*.log 8 | 9 | # BlueJ files 10 | **/*.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | **/.mtj.tmp/ 14 | 15 | # Package Files # 16 | **/*.jar 17 | **/*.war 18 | **/*.nar 19 | **/*.ear 20 | **/*.zip 21 | **/*.tar.gz 22 | **/*.rar 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | **/hs_err_pid* 26 | 27 | ### Maven template 28 | **/target/ 29 | **/pom.xml.tag 30 | **/pom.xml.releaseBackup 31 | **/pom.xml.versionsBackup 32 | **/pom.xml.next 33 | **/release.properties 34 | **/dependency-reduced-pom.xml 35 | **/buildNumber.properties 36 | **/.mvn/timing.properties 37 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 38 | **/.mvn/wrapper/maven-wrapper.jar 39 | 40 | **/*.iml 41 | 42 | **/.idea/ 43 | 44 | **/HELP.md 45 | **/.mvn/ 46 | **/mvnw 47 | **/mvnw.cmd 48 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/config/RSocketServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.config; 2 | 3 | import com.vinsguru.userservice.dto.OperationType; 4 | import io.rsocket.metadata.WellKnownMimeType; 5 | import org.springframework.boot.rsocket.messaging.RSocketStrategiesCustomizer; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.util.MimeType; 9 | import org.springframework.util.MimeTypeUtils; 10 | 11 | @Configuration 12 | public class RSocketServerConfig { 13 | 14 | 15 | @Bean 16 | public RSocketStrategiesCustomizer strategiesCustomizer(){ 17 | MimeType mimeType = MimeTypeUtils.parseMimeType(WellKnownMimeType.APPLICATION_CBOR.getString()); 18 | return c -> c.metadataExtractorRegistry( 19 | r -> r.metadataToExtract(mimeType, OperationType.class, "operation-type") 20 | ); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/assignment/GuessNumberService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.assignment; 2 | 3 | import org.springframework.stereotype.Service; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.concurrent.ThreadLocalRandom; 7 | 8 | @Service 9 | public class GuessNumberService { 10 | 11 | public Flux play(Flux flux){ 12 | int serverNumber = ThreadLocalRandom.current().nextInt(1, 100); 13 | System.out.println("Server Number : " + serverNumber); 14 | return flux.map(i -> this.compare(serverNumber, i)); 15 | } 16 | 17 | private GuessNumberResponse compare(int serverNumber, int clientNumber){ 18 | if(serverNumber > clientNumber) 19 | return GuessNumberResponse.GREATER; 20 | else if(serverNumber < clientNumber) 21 | return GuessNumberResponse.LESSER; 22 | return GuessNumberResponse.EQUAL; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/service/SocketAcceptorImpl.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.service; 2 | 3 | import io.rsocket.ConnectionSetupPayload; 4 | import io.rsocket.RSocket; 5 | import io.rsocket.SocketAcceptor; 6 | import reactor.core.publisher.Mono; 7 | 8 | public class SocketAcceptorImpl implements SocketAcceptor { 9 | @Override 10 | public Mono accept(ConnectionSetupPayload connectionSetupPayload, RSocket rSocket) { 11 | System.out.println("SocketAcceptorImpl-accept method"); 12 | 13 | if(isValidClient(connectionSetupPayload.getDataUtf8())) 14 | return Mono.just(new MathService()); 15 | else 16 | return Mono.just(new FreeService()); 17 | //Mono.fromCallable(MathService::new); 18 | //return Mono.fromCallable(FastProducerService::new); 19 | } 20 | 21 | private boolean isValidClient(String credentials){ 22 | return "user:password".equals(credentials); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/controller/UserTransactionController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.controller; 2 | 3 | import com.vinsguru.userservice.dto.TransactionRequest; 4 | import com.vinsguru.userservice.dto.TransactionResponse; 5 | import com.vinsguru.userservice.service.UserTransactionService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.messaging.handler.annotation.MessageMapping; 8 | import org.springframework.stereotype.Controller; 9 | import reactor.core.publisher.Mono; 10 | 11 | @Controller 12 | @MessageMapping("user") 13 | public class UserTransactionController { 14 | 15 | @Autowired 16 | private UserTransactionService transactionService; 17 | 18 | @MessageMapping("transaction") 19 | public Mono doTransaction(Mono transactionRequestMono){ 20 | return transactionRequestMono.flatMap(this.transactionService::doTransaction); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | webflux-vs-rsocket 7 | com.vinsguru 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | aggregate-service 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-rsocket 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-webflux 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/util/ObjectUtil.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.util; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.rsocket.Payload; 5 | import io.rsocket.util.DefaultPayload; 6 | 7 | public class ObjectUtil { 8 | 9 | public static Payload toPayload(Object o){ 10 | try{ 11 | ObjectMapper objectMapper = new ObjectMapper(); 12 | byte[] bytes = objectMapper.writeValueAsBytes(o); 13 | return DefaultPayload.create(bytes); 14 | }catch (Exception e){ 15 | throw new RuntimeException(e); 16 | } 17 | } 18 | 19 | public static T toObject(Payload payload, Class type){ 20 | try{ 21 | ObjectMapper objectMapper = new ObjectMapper(); 22 | byte[] bytes = payload.getData().array(); 23 | return objectMapper.readValue(bytes, type); 24 | }catch (Exception e){ 25 | throw new RuntimeException(e); 26 | } 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/service/DataSetupService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.service; 2 | 3 | import com.vinsguru.userservice.entity.User; 4 | import com.vinsguru.userservice.repository.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.stereotype.Service; 8 | import reactor.core.publisher.Flux; 9 | 10 | @Service 11 | public class DataSetupService implements CommandLineRunner { 12 | 13 | @Autowired 14 | private UserRepository repository; 15 | 16 | @Override 17 | public void run(String... args) throws Exception { 18 | User user1 = new User("sam", 10000); 19 | User user2 = new User("mike", 10000); 20 | User user3 = new User("jake", 10000); 21 | 22 | Flux.just(user1, user2, user3) 23 | .flatMap(this.repository::save) 24 | .doOnNext(System.out::println) 25 | .subscribe(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/controller/BatchJobController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.controller; 2 | 3 | import org.springframework.messaging.handler.annotation.MessageMapping; 4 | import org.springframework.messaging.rsocket.RSocketRequester; 5 | import org.springframework.stereotype.Controller; 6 | import reactor.core.publisher.Mono; 7 | 8 | import java.time.Duration; 9 | 10 | @Controller 11 | public class BatchJobController { 12 | 13 | @MessageMapping("batch.job.request") 14 | public Mono submitJob(Mono integerMono, RSocketRequester rSocketRequester){ 15 | this.process(integerMono, rSocketRequester); 16 | return Mono.empty(); 17 | } 18 | 19 | private void process(Mono integerMono, RSocketRequester rSocketRequester){ 20 | integerMono 21 | .delayElement(Duration.ofSeconds(10)) 22 | .map(i -> i * i * i) 23 | .flatMap(i -> rSocketRequester.route("batch.job.response").data(i).send()) 24 | .subscribe(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/dto/Response.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.dto; 2 | 3 | import com.vinsguru.springrsocket.dto.error.ErrorEvent; 4 | 5 | import java.util.Objects; 6 | 7 | public class Response { 8 | 9 | ErrorEvent errorResponse; 10 | T successResponse; 11 | 12 | public Response() { 13 | } 14 | 15 | public Response(T successResponse) { 16 | this.successResponse = successResponse; 17 | } 18 | 19 | public Response(ErrorEvent errorResponse) { 20 | this.errorResponse = errorResponse; 21 | } 22 | 23 | public boolean hasError(){ 24 | return Objects.nonNull(this.errorResponse); 25 | } 26 | 27 | public ErrorEvent getErrorResponse() { 28 | return errorResponse; 29 | } 30 | 31 | public T getSuccessResponse() { 32 | return successResponse; 33 | } 34 | 35 | public static Response with(T t){ 36 | return new Response(t); 37 | } 38 | 39 | public static Response with(ErrorEvent errorResponse){ 40 | return new Response(errorResponse); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /stock-service/src/test/java/com/vinsguru/stockservice/StockServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.stockservice; 2 | 3 | import com.vinsguru.stockservice.dto.StockTickDto; 4 | import io.rsocket.transport.netty.client.TcpClientTransport; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.messaging.rsocket.RSocketRequester; 9 | import reactor.core.publisher.Flux; 10 | import reactor.test.StepVerifier; 11 | 12 | @SpringBootTest 13 | class StockServiceApplicationTests { 14 | 15 | @Autowired 16 | private RSocketRequester.Builder builder; 17 | 18 | @Test 19 | void stockPriceTest() { 20 | 21 | RSocketRequester requester = this.builder 22 | .transport(TcpClientTransport.create("localhost", 7070)); 23 | 24 | Flux flux = requester.route("stock.ticks") 25 | .retrieveFlux(StockTickDto.class) 26 | .doOnNext(System.out::println) 27 | .take(12); 28 | 29 | StepVerifier.create(flux) 30 | .expectNextCount(12) 31 | .verifyComplete(); 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/service/MathClientManager.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.service; 2 | 3 | import org.springframework.messaging.rsocket.RSocketRequester; 4 | import org.springframework.scheduling.annotation.Scheduled; 5 | import org.springframework.stereotype.Service; 6 | import reactor.core.publisher.Flux; 7 | 8 | import java.util.Collections; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | @Service 13 | public class MathClientManager { 14 | 15 | private final Set set = Collections.synchronizedSet(new HashSet<>()); 16 | 17 | public void add(RSocketRequester rSocketRequester){ 18 | rSocketRequester.rsocket() 19 | .onClose() 20 | .doFirst(() -> this.set.add(rSocketRequester)) 21 | .doFinally(s -> { 22 | System.out.println("finally"); 23 | this.set.remove(rSocketRequester); 24 | }).subscribe(); 25 | } 26 | 27 | public void notify(int i){ 28 | Flux.fromIterable(set) 29 | .flatMap(r -> r.route("math.updates").data(i).send()) 30 | .subscribe(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/util/EntityDtoUtil.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.util; 2 | 3 | import com.vinsguru.userservice.dto.TransactionRequest; 4 | import com.vinsguru.userservice.dto.TransactionResponse; 5 | import com.vinsguru.userservice.dto.TransactionStatus; 6 | import com.vinsguru.userservice.dto.UserDto; 7 | import com.vinsguru.userservice.entity.User; 8 | import org.springframework.beans.BeanUtils; 9 | 10 | public class EntityDtoUtil { 11 | 12 | public static UserDto toDto(User user){ 13 | UserDto dto = new UserDto(); 14 | BeanUtils.copyProperties(user, dto); 15 | return dto; 16 | } 17 | 18 | public static User toEntity(UserDto dto){ 19 | User user = new User(); 20 | BeanUtils.copyProperties(dto, user); 21 | return user; 22 | } 23 | 24 | public static TransactionResponse toResponse(TransactionRequest request, TransactionStatus status){ 25 | TransactionResponse response = new TransactionResponse(); 26 | response.setAmount(request.getAmount()); 27 | response.setType(request.getType()); 28 | response.setUserId(request.getUserId()); 29 | response.setStatus(status); 30 | return response; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec02DestinationVariableTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import io.rsocket.transport.netty.client.TcpClientTransport; 4 | import org.junit.jupiter.api.BeforeAll; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.TestInstance; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import reactor.core.publisher.Mono; 11 | import reactor.test.StepVerifier; 12 | 13 | @SpringBootTest 14 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 15 | public class Lec02DestinationVariableTest { 16 | 17 | private RSocketRequester requester; 18 | 19 | @Autowired 20 | private RSocketRequester.Builder builder; 21 | 22 | @BeforeAll 23 | public void setup(){ 24 | this.requester = this.builder 25 | .transport(TcpClientTransport.create("localhost", 6565)); 26 | } 27 | 28 | @Test 29 | public void fireAndForget(){ 30 | Mono mono = this.requester.route("math.service.print.55").send(); 31 | 32 | StepVerifier.create(mono) 33 | .verifyComplete(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.controller; 2 | 3 | import com.vinsguru.tradingservice.client.UserClient; 4 | import com.vinsguru.tradingservice.dto.UserDto; 5 | import com.vinsguru.tradingservice.dto.UserStockDto; 6 | import com.vinsguru.tradingservice.service.UserStockService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import reactor.core.publisher.Flux; 13 | 14 | @RestController 15 | @RequestMapping("user") 16 | public class UserController { 17 | 18 | @Autowired 19 | private UserClient userClient; 20 | 21 | @Autowired 22 | private UserStockService userStockService; 23 | 24 | @GetMapping("all") 25 | public Flux allUsers(){ 26 | return this.userClient.allUsers(); 27 | } 28 | 29 | @GetMapping("{userId}/stocks") 30 | public Flux getUserStocks(@PathVariable String userId){ 31 | return this.userStockService.getUserStocks(userId); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/security/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.security; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.core.userdetails.User; 5 | import org.springframework.security.core.userdetails.UserDetails; 6 | import org.springframework.security.crypto.password.PasswordEncoder; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import jakarta.annotation.PostConstruct; 10 | import java.util.Map; 11 | 12 | @Repository // for demo purposes 13 | public class UserRepository { 14 | 15 | @Autowired 16 | private PasswordEncoder encoder; 17 | 18 | private Map db; 19 | 20 | @PostConstruct 21 | private void init(){ 22 | this.db = Map.of( 23 | "user", User.withUsername("user").password(encoder.encode("password")).roles("USER").build(), 24 | "admin", User.withUsername("admin").password(encoder.encode("password")).roles("ADMIN").build(), 25 | "client", User.withUsername("client").password(encoder.encode("password")).roles("TRUSTED_CLIENT").build() 26 | ); 27 | } 28 | 29 | public UserDetails findByUsername(String username){ 30 | return this.db.get(username); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /simple-rsocket/src/test/java/com/vinsguru/rsocket/Lec03BackpressureTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import io.rsocket.Payload; 4 | import io.rsocket.RSocket; 5 | import io.rsocket.core.RSocketConnector; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import io.rsocket.util.DefaultPayload; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.TestInstance; 11 | import reactor.core.publisher.Flux; 12 | import reactor.test.StepVerifier; 13 | 14 | import java.time.Duration; 15 | 16 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 17 | public class Lec03BackpressureTest { 18 | 19 | private RSocket rSocket; 20 | 21 | @BeforeAll 22 | public void setup(){ 23 | this.rSocket = RSocketConnector.create() 24 | .connect(TcpClientTransport.create("localhost", 6565)) 25 | .block(); 26 | } 27 | 28 | @Test 29 | public void backpressure() { 30 | Flux flux = this.rSocket.requestStream(DefaultPayload.create("")) 31 | .map(Payload::getDataUtf8) 32 | .delayElements(Duration.ofSeconds(1)) 33 | .doOnNext(System.out::println); 34 | 35 | StepVerifier.create(flux) 36 | .expectNextCount(1000) 37 | .verifyComplete(); 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/src/main/java/com/vinsguru/aggregate/controller/AggregateController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregate.controller; 2 | 3 | import com.vinsguru.aggregate.service.RSocketService; 4 | import com.vinsguru.aggregate.service.RestService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Mono; 10 | 11 | import java.util.Map; 12 | 13 | @RestController 14 | public class AggregateController { 15 | 16 | @Autowired 17 | private RSocketService rSocketService; 18 | 19 | @Autowired 20 | private RestService restService; 21 | 22 | @GetMapping("rest/square/{input}") 23 | public Mono> restSquare(@PathVariable int input){ 24 | return this.restService.requestResponse(input); 25 | } 26 | 27 | @GetMapping("rsocket/rr/square/{input}") 28 | public Mono> rsocketSquareRR(@PathVariable int input){ 29 | return this.rSocketService.requestResponse(input); 30 | } 31 | 32 | @GetMapping("rsocket/rc/square/{input}") 33 | public Mono> rsocketSquareRC(@PathVariable int input){ 34 | return this.rSocketService.requestChannel(input); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/service/BatchJobService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.service; 2 | 3 | import com.vinsguru.rsocket.dto.RequestDto; 4 | import com.vinsguru.rsocket.dto.ResponseDto; 5 | import com.vinsguru.rsocket.util.ObjectUtil; 6 | import io.rsocket.Payload; 7 | import io.rsocket.RSocket; 8 | import reactor.core.publisher.Mono; 9 | 10 | import java.time.Duration; 11 | 12 | public class BatchJobService implements RSocket { 13 | 14 | private RSocket rSocket; 15 | 16 | public BatchJobService(RSocket rSocket) { 17 | this.rSocket = rSocket; 18 | } 19 | 20 | @Override 21 | public Mono fireAndForget(Payload payload) { 22 | RequestDto requestDto = ObjectUtil.toObject(payload, RequestDto.class); 23 | System.out.println("Received : " + requestDto); 24 | 25 | Mono.just(requestDto) 26 | .delayElement(Duration.ofSeconds(10)) 27 | .doOnNext(i -> System.out.println("emitting")) 28 | .flatMap(this::findCube) 29 | .subscribe(); 30 | 31 | 32 | return Mono.empty(); 33 | } 34 | 35 | private Mono findCube(RequestDto requestDto){ 36 | int input = requestDto.getInput(); 37 | int output = input * input * input; 38 | ResponseDto responseDto = new ResponseDto(input, output); 39 | Payload payload = ObjectUtil.toPayload(responseDto); 40 | return this.rSocket.fireAndForget(payload); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /simple-rsocket/src/test/java/com/vinsguru/rsocket/Lec02CallbackTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import com.vinsguru.rsocket.client.CallbackService; 4 | import com.vinsguru.rsocket.dto.RequestDto; 5 | import com.vinsguru.rsocket.util.ObjectUtil; 6 | import io.rsocket.RSocket; 7 | import io.rsocket.SocketAcceptor; 8 | import io.rsocket.core.RSocketConnector; 9 | import io.rsocket.transport.netty.client.TcpClientTransport; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.TestInstance; 13 | import reactor.core.publisher.Mono; 14 | import reactor.test.StepVerifier; 15 | 16 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 17 | public class Lec02CallbackTest { 18 | 19 | private RSocket rSocket; 20 | 21 | @BeforeAll 22 | public void setup(){ 23 | this.rSocket = RSocketConnector.create() 24 | .acceptor(SocketAcceptor.with(new CallbackService())) 25 | .connect(TcpClientTransport.create("localhost", 6565)) 26 | .block(); 27 | } 28 | 29 | @Test 30 | public void callback() throws InterruptedException { 31 | 32 | RequestDto requestDto = new RequestDto(5); 33 | Mono mono = this.rSocket.fireAndForget(ObjectUtil.toPayload(requestDto)); 34 | 35 | StepVerifier.create(mono) 36 | .verifyComplete(); 37 | 38 | System.out.println("going to wait"); 39 | 40 | 41 | Thread.sleep(12000); 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec04CallbackTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import io.rsocket.transport.netty.client.TcpClientTransport; 4 | import org.junit.jupiter.api.BeforeAll; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.TestInstance; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; 11 | import reactor.core.publisher.Mono; 12 | import reactor.test.StepVerifier; 13 | 14 | @SpringBootTest 15 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 16 | public class Lec04CallbackTest { 17 | 18 | private RSocketRequester requester; 19 | 20 | @Autowired 21 | private RSocketRequester.Builder builder; 22 | 23 | @Autowired 24 | private RSocketMessageHandler handler; 25 | 26 | @BeforeAll 27 | public void setup(){ 28 | this.requester = this.builder 29 | .rsocketConnector(c -> c.acceptor(handler.responder())) 30 | .transport(TcpClientTransport.create("localhost", 6565)); 31 | } 32 | 33 | @Test 34 | public void callbackTest() throws InterruptedException { 35 | Mono mono = this.requester.route("batch.job.request").data(5).send(); 36 | 37 | StepVerifier.create(mono) 38 | .verifyComplete(); 39 | 40 | Thread.sleep(12000); 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec07ConnectionManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import io.rsocket.transport.netty.client.TcpClientTransport; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.messaging.rsocket.RSocketRequester; 9 | import org.springframework.test.context.TestPropertySource; 10 | 11 | @SpringBootTest 12 | @TestPropertySource(properties = 13 | { 14 | "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration" 15 | } 16 | ) 17 | public class Lec07ConnectionManagerTest { 18 | 19 | @Autowired 20 | private RSocketRequester.Builder builder; 21 | 22 | @Test 23 | public void connectionTest() throws InterruptedException { 24 | 25 | RSocketRequester requester1 = this.builder 26 | .transport(TcpClientTransport.create("localhost", 6565)); 27 | 28 | RSocketRequester requester2 = this.builder 29 | .setupRoute("math.events.connection") 30 | .transport(TcpClientTransport.create("localhost", 6565)); 31 | 32 | requester1.route("math.service.print").data(new ComputationRequestDto(5)).send().subscribe(); 33 | requester2.route("math.service.print").data(new ComputationRequestDto(5)).send().subscribe(); 34 | 35 | Thread.sleep(10000); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/controller/ConnectionHandler.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.controller; 2 | 3 | import com.vinsguru.springrsocket.dto.ClientConnectionRequest; 4 | import com.vinsguru.springrsocket.service.MathClientManager; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.messaging.rsocket.RSocketRequester; 7 | import org.springframework.messaging.rsocket.annotation.ConnectMapping; 8 | import org.springframework.stereotype.Controller; 9 | import reactor.core.publisher.Mono; 10 | 11 | @Controller 12 | public class ConnectionHandler { 13 | 14 | @Autowired 15 | private MathClientManager clientManager; 16 | 17 | /* @ConnectMapping 18 | public Mono handleConnection(ClientConnectionRequest request, RSocketRequester rSocketRequester){ 19 | System.out.println("connection setup : " + request); 20 | return request.getSecretKey().equals("password") ? Mono.empty() : 21 | Mono.fromRunnable(() -> rSocketRequester.rsocketClient().dispose()); 22 | }*/ 23 | 24 | @ConnectMapping 25 | public Mono noEventConnection(RSocketRequester rSocketRequester){ 26 | System.out.println("connection setup" ); 27 | return Mono.empty(); 28 | } 29 | 30 | 31 | @ConnectMapping("math.events.connection") 32 | public Mono mathEventConnection(RSocketRequester rSocketRequester){ 33 | System.out.println("math event connection setup" ); 34 | return Mono.fromRunnable(() -> this.clientManager.add(rSocketRequester)); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/controller/TradeController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.controller; 2 | 3 | import com.vinsguru.tradingservice.client.StockClient; 4 | import com.vinsguru.tradingservice.dto.StockTickDto; 5 | import com.vinsguru.tradingservice.dto.StockTradeRequest; 6 | import com.vinsguru.tradingservice.dto.StockTradeResponse; 7 | import com.vinsguru.tradingservice.service.TradeService; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.web.bind.annotation.*; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | 15 | @RestController 16 | @RequestMapping("stock") 17 | public class TradeController { 18 | 19 | @Autowired 20 | private StockClient stockClient; 21 | 22 | @Autowired 23 | private TradeService tradeService; 24 | 25 | @GetMapping(value = "tick/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 26 | public Flux stockTicks(){ 27 | return this.stockClient.getStockStream(); 28 | } 29 | 30 | @PostMapping("trade") 31 | public Mono> trade(@RequestBody Mono tradeRequestMono){ 32 | return tradeRequestMono 33 | .filter(tr -> tr.getQuantity() > 0) 34 | .flatMap(this.tradeService::trade) 35 | .map(ResponseEntity::ok) 36 | .defaultIfEmpty(ResponseEntity.badRequest().build()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec10ServerSideLoadBalancingTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import io.rsocket.transport.netty.client.TcpClientTransport; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.messaging.rsocket.RSocketRequester; 9 | import org.springframework.test.context.TestPropertySource; 10 | 11 | @SpringBootTest 12 | @TestPropertySource(properties = 13 | { 14 | "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration" 15 | } 16 | ) 17 | public class Lec10ServerSideLoadBalancingTest { 18 | 19 | @Autowired 20 | private RSocketRequester.Builder builder; 21 | 22 | @Test 23 | public void connectionTest() throws InterruptedException { 24 | 25 | RSocketRequester requester1 = this.builder 26 | .transport(TcpClientTransport.create("localhost", 6566)); 27 | 28 | RSocketRequester requester2 = this.builder 29 | .transport(TcpClientTransport.create("localhost", 6566)); 30 | 31 | for (int i = 0; i < 50; i++) { 32 | requester1.route("math.service.print").data(new ComputationRequestDto(i)).send().subscribe(); 33 | requester2.route("math.service.print").data(new ComputationRequestDto(i)).send().subscribe(); 34 | 35 | Thread.sleep(2000); 36 | } 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec11ClientSideLoadBalancingTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import io.rsocket.loadbalance.LoadbalanceTarget; 5 | import io.rsocket.loadbalance.RoundRobinLoadbalanceStrategy; 6 | import io.rsocket.loadbalance.WeightedLoadbalanceStrategy; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.messaging.rsocket.RSocketRequester; 11 | import org.springframework.test.context.TestPropertySource; 12 | import reactor.core.publisher.Flux; 13 | 14 | import java.util.List; 15 | 16 | @SpringBootTest 17 | @TestPropertySource(properties = 18 | { 19 | "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration" 20 | } 21 | ) 22 | public class Lec11ClientSideLoadBalancingTest { 23 | 24 | @Autowired 25 | private Flux> targets; 26 | 27 | @Autowired 28 | private RSocketRequester.Builder builder; 29 | 30 | @Test 31 | public void clientSide() throws InterruptedException { 32 | 33 | RSocketRequester requester = this.builder.transports(targets, WeightedLoadbalanceStrategy.create()); 34 | 35 | for (int i = 0; i < 50; i++) { 36 | requester.route("math.service.print").data(new ComputationRequestDto(i)).send().subscribe(); 37 | 38 | Thread.sleep(200); 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/assignment/Player.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.assignment; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Sinks; 6 | 7 | import java.util.function.Consumer; 8 | 9 | @Configuration 10 | public class Player { 11 | 12 | private final Sinks.Many sink = Sinks.many().unicast().onBackpressureBuffer(); 13 | private int lower = 0; 14 | private int upper = 100; 15 | private int mid = 0; 16 | private int attempts = 0; 17 | 18 | public Flux guesses(){ 19 | return this.sink.asFlux(); 20 | } 21 | 22 | public void play(){ 23 | this.emit(); 24 | } 25 | 26 | public Consumer receives(){ 27 | return this::processResponse; 28 | } 29 | 30 | private void processResponse(GuessNumberResponse numberResponse){ 31 | 32 | attempts++; 33 | System.out.println(attempts + " : " + mid + " : " + numberResponse); 34 | 35 | if(GuessNumberResponse.EQUAL.equals(numberResponse)){ 36 | this.sink.tryEmitComplete(); 37 | return; 38 | } 39 | 40 | 41 | if(GuessNumberResponse.GREATER.equals(numberResponse)) 42 | lower = mid; 43 | else if(GuessNumberResponse.LESSER.equals(numberResponse)) 44 | upper = mid; 45 | 46 | this.emit(); 47 | 48 | } 49 | 50 | private void emit(){ 51 | mid = lower + (upper - lower) / 2; 52 | this.sink.tryEmitNext(mid); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/src/main/java/com/vinsguru/aggregate/service/RestService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregate.service; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.http.client.reactive.ReactorClientHttpConnector; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.web.reactive.function.client.WebClient; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | import reactor.netty.http.client.HttpClient; 10 | import reactor.netty.resources.ConnectionProvider; 11 | import reactor.util.function.Tuple2; 12 | import reactor.util.function.Tuples; 13 | 14 | import javax.annotation.PostConstruct; 15 | import java.util.Map; 16 | 17 | @Service 18 | public class RestService { 19 | 20 | private WebClient webClient; 21 | 22 | @Value("${rest.service.url}") 23 | private String url; 24 | 25 | @PostConstruct 26 | private void init(){ 27 | this.webClient = WebClient.builder() 28 | .baseUrl(url) 29 | .build(); 30 | } 31 | 32 | public Mono> requestResponse(int input){ 33 | return Flux.range(1, input) 34 | .flatMap(i -> this.webClient 35 | .get() 36 | .uri("{input}", i) 37 | .retrieve() 38 | .bodyToMono(Integer.class) 39 | .map(k -> Tuples.of(i, k)) 40 | ) 41 | .collectMap(Tuple2::getT1, Tuple2::getT2); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | pom 6 | 7 | rest-square-service 8 | rsocket-square-service 9 | aggregate-service 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 2.4.4 15 | 16 | 17 | com.vinsguru 18 | webflux-vs-rsocket 19 | 0.0.1-SNAPSHOT 20 | webflux-vs-rsocket 21 | Demo project for Spring Boot 22 | 23 | 11 24 | 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-test 31 | test 32 | 33 | 34 | io.projectreactor 35 | reactor-test 36 | test 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/controller/MathController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.controller; 2 | 3 | import com.vinsguru.springrsocket.dto.ChartResponseDto; 4 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 5 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 6 | import com.vinsguru.springrsocket.service.MathService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.messaging.handler.annotation.MessageMapping; 9 | import org.springframework.stereotype.Controller; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | 13 | @Controller 14 | public class MathController { 15 | 16 | @Autowired 17 | private MathService service; 18 | 19 | @MessageMapping("math.service.print") 20 | public Mono print(Mono requestDtoMono){ 21 | return this.service.print(requestDtoMono); 22 | } 23 | 24 | @MessageMapping("math.service.square") 25 | public Mono findSquare(Mono requestDtoMono){ 26 | return this.service.findSquare(requestDtoMono); 27 | } 28 | 29 | @MessageMapping("math.service.table") 30 | public Flux tableStream(Mono requestDtoMono){ 31 | return requestDtoMono.flatMapMany(this.service::tableStream); 32 | } 33 | 34 | @MessageMapping("math.service.chart") 35 | public Flux chartStream(Flux requestDtoFlux){ 36 | return this.service.chartStream(requestDtoFlux); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/security/SecuredMathController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.security; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 5 | import com.vinsguru.springrsocket.service.MathService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.messaging.handler.annotation.MessageMapping; 8 | import org.springframework.security.access.prepost.PreAuthorize; 9 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.stereotype.Controller; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | 15 | @Controller 16 | @MessageMapping("math.service.secured") 17 | public class SecuredMathController { 18 | 19 | @Autowired 20 | private MathService service; 21 | 22 | @PreAuthorize("hasRole('USER')") 23 | @MessageMapping("square") 24 | public Mono findSquare(Mono requestDtoMono, 25 | @AuthenticationPrincipal Mono userDetailsMono){ 26 | userDetailsMono.doOnNext(System.out::println).subscribe(); 27 | return this.service.findSquare(requestDtoMono); 28 | } 29 | 30 | @MessageMapping("table") 31 | public Flux tableStream(Mono requestDtoMono){ 32 | return requestDtoMono.flatMapMany(this.service::tableStream); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/service/MathService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.service; 2 | 3 | import com.vinsguru.springrsocket.dto.ChartResponseDto; 4 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 5 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 6 | import org.springframework.stereotype.Service; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | 10 | import java.time.Duration; 11 | 12 | @Service 13 | public class MathService { 14 | 15 | // ff 16 | public Mono print(Mono requestDtoMono){ 17 | return requestDtoMono 18 | .doOnNext(System.out::println) 19 | .then(); 20 | } 21 | 22 | // rr 23 | public Mono findSquare(Mono requestDtoMono){ 24 | return requestDtoMono 25 | .map(ComputationRequestDto::getInput) 26 | .map(i -> new ComputationResponseDto(i, i * i)); 27 | } 28 | 29 | // rs 30 | public Flux tableStream(ComputationRequestDto dto){ 31 | return Flux.range(1, 10) 32 | .delayElements(Duration.ofSeconds(1)) 33 | .map(i -> new ComputationResponseDto(dto.getInput(), dto.getInput() * i)); 34 | } 35 | 36 | // rc - x ^2 + 1 37 | public Flux chartStream(Flux requestDtoFlux){ 38 | return requestDtoFlux 39 | .map(ComputationRequestDto::getInput) 40 | .map(i -> new ChartResponseDto(i, (i * i) + 1)); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec05AssignmentTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.assignment.GuessNumberResponse; 4 | import com.vinsguru.springrsocket.assignment.Player; 5 | import io.rsocket.transport.netty.client.TcpClientTransport; 6 | import org.junit.jupiter.api.BeforeAll; 7 | import org.junit.jupiter.api.RepeatedTest; 8 | import org.junit.jupiter.api.TestInstance; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.messaging.rsocket.RSocketRequester; 12 | import reactor.core.publisher.Mono; 13 | import reactor.test.StepVerifier; 14 | 15 | import java.time.Duration; 16 | 17 | @SpringBootTest 18 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 19 | public class Lec05AssignmentTest { 20 | 21 | private RSocketRequester requester; 22 | 23 | @Autowired 24 | private RSocketRequester.Builder builder; 25 | 26 | @BeforeAll 27 | public void setup(){ 28 | this.requester = this.builder 29 | .transport(TcpClientTransport.create("localhost", 6565)); 30 | } 31 | 32 | @RepeatedTest(3) 33 | public void assignment() { 34 | 35 | Player player = new Player(); 36 | 37 | Mono mono = this.requester.route("guess.a.number") 38 | .data(player.guesses().delayElements(Duration.ofSeconds(1))) 39 | .retrieveFlux(GuessNumberResponse.class) 40 | .doOnNext(player.receives()) 41 | .doFirst(player::play) 42 | .then(); 43 | 44 | StepVerifier.create(mono) 45 | .verifyComplete(); 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec12SslTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 5 | import io.rsocket.transport.netty.client.TcpClientTransport; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import reactor.core.publisher.Mono; 11 | import reactor.netty.tcp.TcpClient; 12 | import reactor.test.StepVerifier; 13 | 14 | @SpringBootTest 15 | public class Lec12SslTest { 16 | 17 | static { 18 | System.setProperty("javax.net.ssl.trustStore", "/home/vins/Documents/workspace/github/vins-courses/rsocket/ssl-tls/client.truststore"); 19 | System.setProperty("javax.net.ssl.trustStorePassword", "password"); 20 | } 21 | 22 | @Autowired 23 | private RSocketRequester.Builder builder; 24 | 25 | @Test 26 | public void sslTlsTest() { 27 | 28 | RSocketRequester requester = this.builder 29 | .transport(TcpClientTransport.create( 30 | TcpClient.create().host("localhost").port(6565).secure() 31 | )); 32 | 33 | Mono mono = requester.route("math.service.square") 34 | .data(new ComputationRequestDto(5)) 35 | .retrieveMono(ComputationResponseDto.class) 36 | .doOnNext(System.out::println); 37 | 38 | StepVerifier.create(mono) 39 | .expectNextCount(1) 40 | .verifyComplete(); 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.service; 2 | 3 | import com.vinsguru.userservice.dto.UserDto; 4 | import com.vinsguru.userservice.repository.UserRepository; 5 | import com.vinsguru.userservice.util.EntityDtoUtil; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | 11 | @Service 12 | public class UserService { 13 | 14 | @Autowired 15 | private UserRepository repository; 16 | 17 | public Flux getAllUsers(){ 18 | return this.repository.findAll() 19 | .map(EntityDtoUtil::toDto); 20 | } 21 | 22 | public Mono getUserById(final String userId){ 23 | return this.repository.findById(userId) 24 | .map(EntityDtoUtil::toDto); 25 | } 26 | 27 | public Mono createUser(Mono mono){ 28 | return mono 29 | .map(EntityDtoUtil::toEntity) 30 | .flatMap(this.repository::save) 31 | .map(EntityDtoUtil::toDto); 32 | } 33 | 34 | public Mono updateUser(String id, Mono mono){ 35 | return this.repository.findById(id) 36 | .flatMap(u -> mono.map(EntityDtoUtil::toEntity) 37 | .doOnNext(e -> e.setId(id))) 38 | .flatMap(this.repository::save) 39 | .map(EntityDtoUtil::toDto); 40 | } 41 | 42 | public Mono deleteUser(String id){ 43 | return this.repository.deleteById(id); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/client/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.client; 2 | 3 | import com.vinsguru.tradingservice.dto.TransactionRequest; 4 | import com.vinsguru.tradingservice.dto.TransactionResponse; 5 | import com.vinsguru.tradingservice.dto.UserDto; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.messaging.rsocket.RSocketConnectorConfigurer; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import org.springframework.stereotype.Service; 11 | import reactor.core.publisher.Flux; 12 | import reactor.core.publisher.Mono; 13 | 14 | @Service 15 | public class UserClient { 16 | 17 | private final RSocketRequester requester; 18 | 19 | public UserClient(RSocketRequester.Builder builder, 20 | RSocketConnectorConfigurer connectorConfigurer, 21 | @Value("${user.service.host}") String host, 22 | @Value("${user.service.port}") int port){ 23 | this.requester = builder.rsocketConnector(connectorConfigurer) 24 | .transport(TcpClientTransport.create(host, port)); 25 | } 26 | 27 | public Mono doTransaction(TransactionRequest transactionRequest){ 28 | return this.requester.route("user.transaction") 29 | .data(transactionRequest) 30 | .retrieveMono(TransactionResponse.class) 31 | .doOnNext(System.out::println); 32 | } 33 | 34 | public Flux allUsers(){ 35 | return this.requester.route("user.get.all") 36 | .retrieveFlux(UserDto.class); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/client/config/LoadBalanceTargetConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.client.config; 2 | 3 | import com.vinsguru.springrsocket.client.serviceregistry.RSocketServerInstance; 4 | import com.vinsguru.springrsocket.client.serviceregistry.ServiceRegistryClient; 5 | import io.rsocket.loadbalance.LoadbalanceTarget; 6 | import io.rsocket.transport.ClientTransport; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import reactor.core.publisher.Flux; 12 | import reactor.core.publisher.Mono; 13 | 14 | import java.time.Duration; 15 | import java.util.List; 16 | import java.util.concurrent.ThreadLocalRandom; 17 | import java.util.stream.Collectors; 18 | 19 | @Configuration 20 | public class LoadBalanceTargetConfig { 21 | 22 | @Autowired 23 | private ServiceRegistryClient registryClient; 24 | 25 | @Bean 26 | public Flux> targetFlux(){ 27 | return Flux.from(targets()); 28 | } 29 | 30 | private Mono> targets(){ 31 | return Mono.fromSupplier(() -> this.registryClient.getInstances() 32 | .stream() 33 | .map(server -> LoadbalanceTarget.from(key(server), transport(server))) 34 | .collect(Collectors.toList())); 35 | } 36 | 37 | private String key(RSocketServerInstance instance){ 38 | return instance.getHost() + instance.getPort(); 39 | } 40 | 41 | private ClientTransport transport(RSocketServerInstance instance){ 42 | return TcpClientTransport.create(instance.getHost(), instance.getPort()); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/util/EntityDtoUtil.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.util; 2 | 3 | import com.vinsguru.tradingservice.dto.*; 4 | import com.vinsguru.tradingservice.entity.UserStock; 5 | import org.springframework.beans.BeanUtils; 6 | 7 | public class EntityDtoUtil { 8 | 9 | public static TransactionRequest toTransactionRequest(StockTradeRequest stockTradeRequest, int amount){ 10 | TransactionRequest transactionRequest = new TransactionRequest(); 11 | TransactionType transactionType = TradeType.BUY.equals(stockTradeRequest.getTradeType()) ? 12 | TransactionType.DEBIT : TransactionType.CREDIT; 13 | transactionRequest.setType(transactionType); 14 | transactionRequest.setUserId(stockTradeRequest.getUserId()); 15 | transactionRequest.setAmount(amount); 16 | return transactionRequest; 17 | } 18 | 19 | public static StockTradeResponse toTradeResponse(StockTradeRequest request, TradeStatus status, int price){ 20 | StockTradeResponse response = new StockTradeResponse(); 21 | BeanUtils.copyProperties(request, response); 22 | response.setTradeStatus(status); 23 | response.setPrice(price); 24 | return response; 25 | } 26 | 27 | public static UserStock toUserStock(StockTradeRequest request){ 28 | UserStock stock = new UserStock(); 29 | stock.setUserId(request.getUserId()); 30 | stock.setStockSymbol(request.getStockSymbol()); 31 | stock.setQuantity(0); 32 | return stock; 33 | } 34 | 35 | public static UserStockDto toUserStockDto(UserStock userStock){ 36 | UserStockDto dto = new UserStockDto(); 37 | BeanUtils.copyProperties(userStock, dto); 38 | return dto; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /simple-rsocket/src/test/java/com/vinsguru/rsocket/Lec05ConnectionSetupTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import com.vinsguru.rsocket.dto.RequestDto; 4 | import com.vinsguru.rsocket.dto.ResponseDto; 5 | import com.vinsguru.rsocket.util.ObjectUtil; 6 | import io.rsocket.Payload; 7 | import io.rsocket.RSocket; 8 | import io.rsocket.core.RSocketClient; 9 | import io.rsocket.core.RSocketConnector; 10 | import io.rsocket.transport.netty.client.TcpClientTransport; 11 | import io.rsocket.util.DefaultPayload; 12 | import org.junit.jupiter.api.BeforeAll; 13 | import org.junit.jupiter.api.Test; 14 | import org.junit.jupiter.api.TestInstance; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | import reactor.test.StepVerifier; 18 | 19 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 20 | public class Lec05ConnectionSetupTest { 21 | 22 | private RSocketClient rSocketClient; 23 | 24 | @BeforeAll 25 | public void setup(){ 26 | Mono socketMono = RSocketConnector.create() 27 | .setupPayload(DefaultPayload.create("user:passwrd")) 28 | .connect(TcpClientTransport.create("localhost", 6565)) 29 | .doOnNext(r -> System.out.println("going to connect")); 30 | 31 | this.rSocketClient = RSocketClient.from(socketMono); 32 | 33 | } 34 | 35 | @Test 36 | public void connectionTest() { 37 | 38 | Payload payload = ObjectUtil.toPayload(new RequestDto(5)); 39 | 40 | Flux flux = this.rSocketClient.requestStream(Mono.just(payload)) 41 | .map(p -> ObjectUtil.toObject(p, ResponseDto.class)) 42 | .doOnNext(System.out::println); 43 | 44 | StepVerifier.create(flux) 45 | .expectNextCount(10) 46 | .verifyComplete(); 47 | 48 | 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/service/UserStockService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.service; 2 | 3 | import com.vinsguru.tradingservice.dto.StockTradeRequest; 4 | import com.vinsguru.tradingservice.dto.UserStockDto; 5 | import com.vinsguru.tradingservice.entity.UserStock; 6 | import com.vinsguru.tradingservice.repository.UserStockRepository; 7 | import com.vinsguru.tradingservice.util.EntityDtoUtil; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | 13 | @Service 14 | public class UserStockService { 15 | 16 | @Autowired 17 | private UserStockRepository stockRepository; 18 | 19 | public Flux getUserStocks(String userId){ 20 | return this.stockRepository.findByUserId(userId) 21 | .map(EntityDtoUtil::toUserStockDto); 22 | } 23 | 24 | // buy 25 | public Mono buyStock(StockTradeRequest request){ 26 | return this.stockRepository.findByUserIdAndStockSymbol(request.getUserId(), request.getStockSymbol()) 27 | .defaultIfEmpty(EntityDtoUtil.toUserStock(request)) 28 | .doOnNext(us -> us.setQuantity(us.getQuantity() + request.getQuantity())) 29 | .flatMap(this.stockRepository::save); 30 | } 31 | 32 | // sell 33 | public Mono sellStock(StockTradeRequest request){ 34 | return this.stockRepository.findByUserIdAndStockSymbol(request.getUserId(), request.getStockSymbol()) 35 | .filter(us -> us.getQuantity() >= request.getQuantity()) 36 | .doOnNext(us -> us.setQuantity(us.getQuantity() - request.getQuantity())) 37 | .flatMap(this.stockRepository::save); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /stock-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.5.0 9 | 10 | 11 | com.vinsguru 12 | stock-service 13 | 0.0.1-SNAPSHOT 14 | stock-service 15 | Demo project for Spring Boot 16 | 17 | 21 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-rsocket 23 | 24 | 25 | org.projectlombok 26 | lombok 27 | true 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-test 32 | test 33 | 34 | 35 | io.projectreactor 36 | reactor-test 37 | test 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-maven-plugin 46 | 47 | 48 | 49 | org.projectlombok 50 | lombok 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/controller/InputValidationController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.controller; 2 | 3 | import com.vinsguru.springrsocket.dto.Response; 4 | import com.vinsguru.springrsocket.dto.error.ErrorEvent; 5 | import com.vinsguru.springrsocket.dto.error.StatusCode; 6 | import org.springframework.messaging.handler.annotation.DestinationVariable; 7 | import org.springframework.messaging.handler.annotation.MessageExceptionHandler; 8 | import org.springframework.messaging.handler.annotation.MessageMapping; 9 | import org.springframework.stereotype.Controller; 10 | import reactor.core.publisher.Mono; 11 | 12 | @Controller 13 | @MessageMapping("math.validation") 14 | public class InputValidationController { 15 | 16 | @MessageMapping("double.{input}") 17 | public Mono doubleIt(@DestinationVariable int input){ 18 | return Mono.just(input) 19 | .filter(i -> i < 31) 20 | .map(i -> i * 2) 21 | .switchIfEmpty(Mono.error(new IllegalArgumentException("cannot > 30"))); 22 | } 23 | 24 | @MessageMapping("double.response.{input}") 25 | public Mono> doubleResponse(@DestinationVariable int input){ 26 | return Mono.just(input) 27 | .filter(i -> i < 31) 28 | .map(i -> i * 2) 29 | .map(Response::with) 30 | .defaultIfEmpty(Response.with(new ErrorEvent(StatusCode.EC001))); 31 | } 32 | 33 | @MessageExceptionHandler 34 | public Mono handleException(Exception exception){ 35 | return Mono.just(-1); 36 | } 37 | 38 | 39 | /* @MessageMapping("double.{input}") 40 | public Mono doubleIt(@DestinationVariable int input){ 41 | if(input < 31) 42 | return Mono.just(input * 2); 43 | else 44 | return Mono.error(new IllegalArgumentException("can not be > 30")); 45 | }*/ 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/client/StockClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.client; 2 | 3 | import com.vinsguru.tradingservice.dto.StockTickDto; 4 | import io.rsocket.transport.netty.client.TcpClientTransport; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.messaging.rsocket.RSocketConnectorConfigurer; 7 | import org.springframework.messaging.rsocket.RSocketRequester; 8 | import org.springframework.stereotype.Service; 9 | import reactor.core.publisher.Flux; 10 | import reactor.util.retry.Retry; 11 | 12 | import java.time.Duration; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | @Service 17 | public class StockClient { 18 | 19 | private final RSocketRequester requester; 20 | private Flux flux; 21 | private final Map map; 22 | 23 | public StockClient(RSocketRequester.Builder builder, 24 | RSocketConnectorConfigurer connectorConfigurer, 25 | @Value("${stock.service.host}") String host, 26 | @Value("${stock.service.port}") int port){ 27 | this.requester = builder.rsocketConnector(connectorConfigurer) 28 | .transport(TcpClientTransport.create(host, port)); 29 | this.map = new HashMap<>(); 30 | this.initialize(); 31 | } 32 | 33 | public Flux getStockStream(){ 34 | return this.flux; 35 | } 36 | 37 | public int getCurrentStockPrice(String stockSymbol){ 38 | return this.map.getOrDefault(stockSymbol, 0); 39 | } 40 | 41 | private void initialize(){ 42 | this.flux = this.requester.route("stock.ticks") 43 | .retrieveFlux(StockTickDto.class) 44 | .doOnNext(s -> map.put(s.getCode(), s.getPrice())) 45 | .retryWhen(Retry.fixedDelay(Long.MAX_VALUE, Duration.ofSeconds(2))) 46 | .publish() 47 | .autoConnect(0); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec06ConnectionSetupTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ClientConnectionRequest; 4 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 5 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.RepeatedTest; 9 | import org.junit.jupiter.api.TestInstance; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.messaging.rsocket.RSocketRequester; 13 | import reactor.core.publisher.Mono; 14 | import reactor.test.StepVerifier; 15 | 16 | import java.util.concurrent.ThreadLocalRandom; 17 | 18 | @SpringBootTest 19 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 20 | public class Lec06ConnectionSetupTest { 21 | 22 | private RSocketRequester requester; 23 | 24 | @Autowired 25 | private RSocketRequester.Builder builder; 26 | 27 | @BeforeAll 28 | public void setup(){ 29 | 30 | ClientConnectionRequest request = new ClientConnectionRequest(); 31 | request.setClientId("order-service"); 32 | request.setSecretKey("passwrd"); 33 | 34 | this.requester = this.builder 35 | .setupData(request) 36 | .transport(TcpClientTransport.create("localhost", 6565)); 37 | } 38 | 39 | @RepeatedTest(3) 40 | public void connectionTest() { 41 | 42 | Mono mono = this.requester.route("math.service.square") 43 | .data(new ComputationRequestDto(ThreadLocalRandom.current().nextInt(1, 50))) 44 | .retrieveMono(ComputationResponseDto.class) 45 | .doOnNext(System.out::println); 46 | 47 | StepVerifier.create(mono) 48 | .expectNextCount(1) 49 | .verifyComplete(); 50 | 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/service/UserTransactionService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.service; 2 | 3 | import com.vinsguru.userservice.dto.TransactionRequest; 4 | import com.vinsguru.userservice.dto.TransactionResponse; 5 | import com.vinsguru.userservice.dto.TransactionStatus; 6 | import com.vinsguru.userservice.dto.TransactionType; 7 | import com.vinsguru.userservice.entity.User; 8 | import com.vinsguru.userservice.repository.UserRepository; 9 | import com.vinsguru.userservice.util.EntityDtoUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | import reactor.core.publisher.Mono; 13 | 14 | import java.util.function.UnaryOperator; 15 | 16 | @Service 17 | public class UserTransactionService { 18 | 19 | @Autowired 20 | private UserRepository repository; 21 | 22 | public Mono doTransaction(TransactionRequest request){ 23 | UnaryOperator> operation = TransactionType.CREDIT.equals(request.getType()) ? credit(request) : debit(request); 24 | return this.repository.findById(request.getUserId()) 25 | .transform(operation) 26 | .flatMap(this.repository::save) 27 | .map(s -> EntityDtoUtil.toResponse(request, TransactionStatus.COMPLETED)) 28 | .defaultIfEmpty(EntityDtoUtil.toResponse(request, TransactionStatus.FAILED)); 29 | } 30 | 31 | private UnaryOperator> credit(TransactionRequest request){ 32 | return userMono -> userMono 33 | .doOnNext(u -> u.setBalance(u.getBalance() + request.getAmount())); 34 | } 35 | 36 | private UnaryOperator> debit(TransactionRequest request){ 37 | return userMono -> userMono 38 | .filter(u -> u.getBalance() >= request.getAmount()) 39 | .doOnNext(u -> u.setBalance(u.getBalance() - request.getAmount())); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec08ConnectionRetryTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 5 | import io.rsocket.transport.netty.client.TcpClientTransport; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import org.springframework.test.context.TestPropertySource; 11 | import reactor.core.publisher.Mono; 12 | import reactor.test.StepVerifier; 13 | import reactor.util.retry.Retry; 14 | 15 | import java.time.Duration; 16 | 17 | @SpringBootTest 18 | @TestPropertySource(properties = 19 | { 20 | "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration" 21 | } 22 | ) 23 | public class Lec08ConnectionRetryTest { 24 | 25 | @Autowired 26 | private RSocketRequester.Builder builder; 27 | 28 | @Test 29 | public void connectionTest() throws InterruptedException { 30 | 31 | RSocketRequester requester1 = this.builder 32 | .rsocketConnector(c -> c.reconnect(Retry.fixedDelay(10, Duration.ofSeconds(2)) 33 | .doBeforeRetry(s -> System.out.println("retrying " + s.totalRetriesInARow())))) 34 | .transport(TcpClientTransport.create("localhost", 6565)); 35 | 36 | 37 | for (int i = 0; i < 50; i++) { 38 | 39 | Mono mono = requester1.route("math.service.square") 40 | .data(new ComputationRequestDto(i)) 41 | .retrieveMono(ComputationResponseDto.class) 42 | .doOnNext(System.out::println); 43 | 44 | StepVerifier.create(mono) 45 | .expectNextCount(1) 46 | .verifyComplete(); 47 | 48 | Thread.sleep(2000); 49 | } 50 | 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /webflux-vs-rsocket/aggregate-service/src/main/java/com/vinsguru/aggregate/service/RSocketService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregate.service; 2 | 3 | import io.rsocket.transport.netty.client.TcpClientTransport; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.messaging.rsocket.RSocketRequester; 7 | import org.springframework.stereotype.Service; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | import reactor.core.publisher.Sinks; 11 | import reactor.util.function.Tuple2; 12 | import reactor.util.function.Tuples; 13 | 14 | import javax.annotation.PostConstruct; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import java.util.concurrent.atomic.AtomicInteger; 18 | 19 | @Service 20 | public class RSocketService { 21 | 22 | private RSocketRequester requester; 23 | 24 | @Autowired 25 | private RSocketRequester.Builder builder; 26 | 27 | @Value("${rsocket.service.host}") 28 | private String host; 29 | 30 | @Value("${rsocket.service.port}") 31 | private int port; 32 | 33 | @PostConstruct 34 | private void init(){ 35 | this.requester = this.builder.transport(TcpClientTransport.create(host, port)); 36 | } 37 | 38 | public Mono> requestResponse(int input){ 39 | return Flux.range(1, input) 40 | .flatMap(i -> this.requester.route("rr.square") 41 | .data(i) 42 | .retrieveMono(Integer.class) 43 | .map(k -> Tuples.of(i, k)) 44 | ) 45 | .collectMap(Tuple2::getT1, Tuple2::getT2); 46 | } 47 | 48 | public Mono> requestChannel(int input){ 49 | AtomicInteger atomicInteger = new AtomicInteger(1); 50 | return this.requester.route("rc.square") 51 | .data(Flux.range(1, input)) 52 | .retrieveFlux(Integer.class) 53 | .collectMap(i -> atomicInteger.getAndIncrement(), i -> i); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/vinsguru/userservice/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice.controller; 2 | 3 | import com.vinsguru.userservice.dto.OperationType; 4 | import com.vinsguru.userservice.dto.UserDto; 5 | import com.vinsguru.userservice.service.UserService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.messaging.handler.annotation.DestinationVariable; 8 | import org.springframework.messaging.handler.annotation.Header; 9 | import org.springframework.messaging.handler.annotation.MessageMapping; 10 | import org.springframework.stereotype.Controller; 11 | import reactor.core.publisher.Flux; 12 | import reactor.core.publisher.Mono; 13 | 14 | // crud demo 15 | 16 | @Controller 17 | @MessageMapping("user") 18 | public class UserController { 19 | 20 | @Autowired 21 | private UserService service; 22 | 23 | // RS 24 | @MessageMapping("get.all") 25 | public Flux allUsers(){ 26 | return this.service.getAllUsers(); 27 | } 28 | 29 | // RR 30 | @MessageMapping("get.{id}") 31 | public Mono getUserById(@DestinationVariable String id){ 32 | return this.service.getUserById(id); 33 | } 34 | 35 | // RR 36 | @MessageMapping("create") 37 | public Mono createUser(Mono userDtoMono){ 38 | return this.service.createUser(userDtoMono); 39 | } 40 | 41 | // RR 42 | @MessageMapping("update.{id}") 43 | public Mono updateUser(@DestinationVariable String id, Mono userDtoMono){ 44 | return this.service.updateUser(id, userDtoMono); 45 | } 46 | 47 | // FF 48 | @MessageMapping("delete.{id}") 49 | public Mono deleteUser(@DestinationVariable String id){ 50 | return this.service.deleteUser(id); 51 | } 52 | 53 | @MessageMapping("operation.type") 54 | public Mono metadataOperationType(@Header("operation-type") OperationType operationType, 55 | Mono userDtoMono){ 56 | System.out.println(operationType); 57 | userDtoMono.doOnNext(System.out::println).subscribe(); 58 | return Mono.empty(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /simple-rsocket/src/main/java/com/vinsguru/rsocket/service/MathService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket.service; 2 | 3 | import com.vinsguru.rsocket.dto.ChartResponseDto; 4 | import com.vinsguru.rsocket.dto.RequestDto; 5 | import com.vinsguru.rsocket.dto.ResponseDto; 6 | import com.vinsguru.rsocket.util.ObjectUtil; 7 | import io.rsocket.Payload; 8 | import io.rsocket.RSocket; 9 | import org.reactivestreams.Publisher; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | 13 | import java.time.Duration; 14 | 15 | public class MathService implements RSocket { 16 | 17 | @Override 18 | public Mono fireAndForget(Payload payload) { 19 | System.out.println("Receiving : " + ObjectUtil.toObject(payload, RequestDto.class)); 20 | return Mono.empty(); 21 | } 22 | 23 | @Override 24 | public Mono requestResponse(Payload payload) { 25 | return Mono.fromSupplier(() -> { 26 | RequestDto requestDto = ObjectUtil.toObject(payload, RequestDto.class); 27 | ResponseDto responseDto = new ResponseDto(requestDto.getInput(), requestDto.getInput() * requestDto.getInput()); 28 | return ObjectUtil.toPayload(responseDto); 29 | }); 30 | } 31 | 32 | @Override 33 | public Flux requestStream(Payload payload) { 34 | RequestDto requestDto = ObjectUtil.toObject(payload, RequestDto.class); 35 | return Flux.range(1, 10) 36 | .map(i -> i * requestDto.getInput()) 37 | .map(i -> new ResponseDto(requestDto.getInput(), i)) 38 | .delayElements(Duration.ofSeconds(1)) 39 | .doOnNext(System.out::println) 40 | .doFinally(s -> System.out.println(s)) 41 | .map(ObjectUtil::toPayload); 42 | } 43 | 44 | @Override 45 | public Flux requestChannel(Publisher payloads) { 46 | return Flux.from(payloads) 47 | .map(p -> ObjectUtil.toObject(p, RequestDto.class)) 48 | .map(RequestDto::getInput) 49 | .map(i -> new ChartResponseDto(i, (i * i) + 1)) 50 | .map(ObjectUtil::toPayload); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /simple-rsocket/src/test/java/com/vinsguru/rsocket/Lec04PersistentConnectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import io.rsocket.Payload; 4 | import io.rsocket.RSocket; 5 | import io.rsocket.core.RSocketClient; 6 | import io.rsocket.core.RSocketConnector; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import io.rsocket.util.DefaultPayload; 9 | import org.junit.jupiter.api.BeforeAll; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.TestInstance; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | import reactor.test.StepVerifier; 15 | 16 | import java.time.Duration; 17 | 18 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 19 | public class Lec04PersistentConnectionTest { 20 | 21 | private RSocketClient rSocketClient; 22 | 23 | @BeforeAll 24 | public void setup(){ 25 | Mono socketMono = RSocketConnector.create() 26 | .connect(TcpClientTransport.create("localhost", 6565)) 27 | .doOnNext(r -> System.out.println("going to connect")); 28 | 29 | this.rSocketClient = RSocketClient.from(socketMono); 30 | 31 | } 32 | 33 | @Test 34 | public void connectionTest() throws Exception { 35 | Flux flux1 = this.rSocketClient.requestStream(Mono.just(DefaultPayload.create(""))) 36 | .map(Payload::getDataUtf8) 37 | .delayElements(Duration.ofMillis(300)) 38 | .take(10) 39 | .doOnNext(System.out::println); 40 | 41 | StepVerifier.create(flux1) 42 | .expectNextCount(10) 43 | .verifyComplete(); 44 | 45 | 46 | System.out.println("going to sleep"); 47 | Thread.sleep(5000); 48 | System.out.println("woke up"); 49 | 50 | Flux flux2 = this.rSocketClient.requestStream(Mono.just(DefaultPayload.create(""))) 51 | .map(Payload::getDataUtf8) 52 | .delayElements(Duration.ofMillis(300)) 53 | .take(10) 54 | .doOnNext(System.out::println); 55 | 56 | StepVerifier.create(flux2) 57 | .expectNextCount(10) 58 | .verifyComplete(); 59 | 60 | 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /user-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.5.0 9 | 10 | 11 | com.vinsguru 12 | user-service 13 | 0.0.1-SNAPSHOT 14 | user-service 15 | Demo project for Spring Boot 16 | 17 | 21 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-mongodb-reactive 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-rsocket 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | true 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | de.flapdoodle.embed 40 | de.flapdoodle.embed.mongo.spring3x 41 | 4.18.0 42 | 43 | 44 | io.projectreactor 45 | reactor-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | org.projectlombok 59 | lombok 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec03InputValidationTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.Response; 4 | import io.rsocket.transport.netty.client.TcpClientTransport; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.TestInstance; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.core.ParameterizedTypeReference; 11 | import org.springframework.messaging.rsocket.RSocketRequester; 12 | import reactor.core.publisher.Mono; 13 | import reactor.test.StepVerifier; 14 | 15 | @SpringBootTest 16 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 17 | public class Lec03InputValidationTest { 18 | 19 | private RSocketRequester requester; 20 | 21 | @Autowired 22 | private RSocketRequester.Builder builder; 23 | 24 | @BeforeAll 25 | public void setup(){ 26 | this.requester = this.builder 27 | .transport(TcpClientTransport.create("localhost", 6565)); 28 | } 29 | 30 | @Test 31 | public void validationTest(){ 32 | Mono mono = this.requester.route("math.validation.double.31") 33 | .retrieveMono(Integer.class) 34 | .onErrorReturn(Integer.MIN_VALUE) 35 | .doOnNext(System.out::println); 36 | 37 | StepVerifier.create(mono) 38 | .expectNextCount(1) 39 | .verifyComplete(); 40 | } 41 | 42 | @Test 43 | public void responseTest(){ 44 | Mono> mono = this.requester.route("math.validation.double.response.30") 45 | .retrieveMono(new ParameterizedTypeReference>() { 46 | }) 47 | .doOnNext(r -> { 48 | if (r.hasError()) 49 | System.out.println(r.getErrorResponse().getStatusCode().getDescription()); 50 | else 51 | System.out.println(r.getSuccessResponse()); 52 | }); 53 | 54 | StepVerifier.create(mono) 55 | .expectNextCount(1) 56 | .verifyComplete(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /spring-rsocket/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.5.0 9 | 10 | 11 | com.vinsguru 12 | spring-rsocket 13 | 0.0.1-SNAPSHOT 14 | spring-rsocket 15 | Demo project for Spring Boot 16 | 17 | 21 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-rsocket 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-security 27 | 28 | 29 | org.springframework.security 30 | spring-security-messaging 31 | 32 | 33 | org.springframework.security 34 | spring-security-rsocket 35 | 36 | 37 | org.projectlombok 38 | lombok 39 | true 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | io.projectreactor 48 | reactor-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | org.projectlombok 62 | lombok 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec09SessionResumptionTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 5 | import io.rsocket.core.Resume; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.messaging.rsocket.RSocketRequester; 11 | import org.springframework.test.context.TestPropertySource; 12 | import reactor.core.publisher.Flux; 13 | import reactor.test.StepVerifier; 14 | import reactor.util.retry.Retry; 15 | 16 | import java.time.Duration; 17 | 18 | @SpringBootTest 19 | @TestPropertySource(properties = 20 | { 21 | "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration" 22 | } 23 | ) 24 | public class Lec09SessionResumptionTest { 25 | 26 | @Autowired 27 | private RSocketRequester.Builder builder; 28 | 29 | @Test 30 | public void connectionTest() { 31 | 32 | RSocketRequester requester = this.builder 33 | .rsocketConnector(c -> c 34 | .resume(resumeStrategy()) 35 | .reconnect(retryStrategy())) 36 | .transport(TcpClientTransport.create("localhost", 6566)); 37 | 38 | Flux flux = requester.route("math.service.table") 39 | .data(new ComputationRequestDto(5)) 40 | .retrieveFlux(ComputationResponseDto.class) 41 | .doOnNext(System.out::println); 42 | 43 | StepVerifier.create(flux) 44 | .expectNextCount(1000) 45 | .verifyComplete(); 46 | 47 | 48 | } 49 | 50 | private Resume resumeStrategy(){ 51 | return new Resume() 52 | .retry(Retry.fixedDelay(2000, Duration.ofSeconds(2)) 53 | .doBeforeRetry(s -> System.out.println("resume - retry :" + s.totalRetriesInARow()))); 54 | } 55 | 56 | private Retry retryStrategy(){ 57 | return Retry.fixedDelay(100, Duration.ofSeconds(1)) 58 | .doBeforeRetry(s -> System.out.println("Retrying connection : " + s.totalRetriesInARow())); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /trading-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.5.0 9 | 10 | 11 | com.vinsguru 12 | trading-service 13 | 0.0.1-SNAPSHOT 14 | trading-service 15 | Demo project for Spring Boot 16 | 17 | 21 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-mongodb-reactive 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-rsocket 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-webflux 31 | 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | true 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | de.flapdoodle.embed 45 | de.flapdoodle.embed.mongo.spring3x 46 | 4.18.0 47 | 48 | 49 | io.projectreactor 50 | reactor-test 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-maven-plugin 60 | 61 | 62 | 63 | org.projectlombok 64 | lombok 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /trading-service/src/main/java/com/vinsguru/tradingservice/service/TradeService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tradingservice.service; 2 | 3 | import com.vinsguru.tradingservice.client.StockClient; 4 | import com.vinsguru.tradingservice.client.UserClient; 5 | import com.vinsguru.tradingservice.dto.*; 6 | import com.vinsguru.tradingservice.util.EntityDtoUtil; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import reactor.core.publisher.Mono; 10 | 11 | @Service 12 | public class TradeService { 13 | 14 | @Autowired 15 | private UserStockService stockService; 16 | 17 | @Autowired 18 | private UserClient userClient; 19 | 20 | @Autowired 21 | private StockClient stockClient; 22 | 23 | public Mono trade(StockTradeRequest tradeRequest){ 24 | TransactionRequest transactionRequest = EntityDtoUtil.toTransactionRequest(tradeRequest, this.estimatePrice(tradeRequest)); 25 | Mono responseMono = TradeType.BUY.equals(tradeRequest.getTradeType()) ? 26 | buyStock(tradeRequest, transactionRequest) : 27 | sellStock(tradeRequest, transactionRequest); 28 | return responseMono 29 | .defaultIfEmpty(EntityDtoUtil.toTradeResponse(tradeRequest, TradeStatus.FAILED, 0)); 30 | } 31 | 32 | private Mono buyStock(StockTradeRequest tradeRequest, TransactionRequest transactionRequest) { 33 | return this.userClient.doTransaction(transactionRequest) 34 | .filter(tr -> TransactionStatus.COMPLETED.equals(tr.getStatus())) 35 | .flatMap(tr -> this.stockService.buyStock(tradeRequest)) 36 | .map(us -> EntityDtoUtil.toTradeResponse(tradeRequest, TradeStatus.COMPLETED, transactionRequest.getAmount())); 37 | } 38 | 39 | private Mono sellStock(StockTradeRequest tradeRequest, TransactionRequest transactionRequest) { 40 | return this.stockService.sellStock(tradeRequest) 41 | .flatMap(us -> this.userClient.doTransaction(transactionRequest)) 42 | .map(tr -> EntityDtoUtil.toTradeResponse(tradeRequest, TradeStatus.COMPLETED, transactionRequest.getAmount())); 43 | } 44 | 45 | private int estimatePrice(StockTradeRequest request){ 46 | return request.getQuantity() * this.stockClient.getCurrentStockPrice(request.getStockSymbol()); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /user-service/src/test/java/com/vinsguru/userservice/UserTransactionTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice; 2 | 3 | import com.vinsguru.userservice.dto.*; 4 | import io.rsocket.transport.netty.client.TcpClientTransport; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.TestInstance; 8 | import org.junit.jupiter.params.ParameterizedTest; 9 | import org.junit.jupiter.params.provider.Arguments; 10 | import org.junit.jupiter.params.provider.MethodSource; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.messaging.rsocket.RSocketRequester; 14 | import reactor.core.publisher.Flux; 15 | import reactor.core.publisher.Mono; 16 | import reactor.test.StepVerifier; 17 | 18 | import java.util.stream.Stream; 19 | 20 | @SpringBootTest 21 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 22 | public class UserTransactionTest { 23 | 24 | private RSocketRequester requester; 25 | 26 | @Autowired 27 | private RSocketRequester.Builder builder; 28 | 29 | @BeforeAll 30 | public void setRequester(){ 31 | this.requester = this.builder 32 | .transport(TcpClientTransport.create("localhost", 7071)); 33 | } 34 | 35 | @ParameterizedTest 36 | @MethodSource("testData") 37 | void transactionTest(int amount, TransactionType type, TransactionStatus status) { 38 | UserDto dto = this.getRandomUser(); 39 | TransactionRequest request = new TransactionRequest(dto.getId(), amount, type); 40 | Mono mono = this.requester.route("user.transaction") 41 | .data(request) 42 | .retrieveMono(TransactionResponse.class) 43 | .doOnNext(System.out::println); 44 | 45 | StepVerifier.create(mono) 46 | .expectNextMatches(r -> r.getStatus().equals(status)) 47 | .verifyComplete(); 48 | } 49 | 50 | private Stream testData(){ 51 | return Stream.of( 52 | Arguments.of(2000, TransactionType.CREDIT, TransactionStatus.COMPLETED), 53 | Arguments.of(2000, TransactionType.DEBIT, TransactionStatus.COMPLETED), 54 | Arguments.of(12000, TransactionType.DEBIT, TransactionStatus.FAILED) 55 | ); 56 | } 57 | 58 | 59 | private UserDto getRandomUser(){ 60 | return this.requester.route("user.get.all") 61 | .retrieveFlux(UserDto.class) 62 | .next() 63 | .block(); 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec01RSocketTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ChartResponseDto; 4 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 5 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestInstance; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.messaging.rsocket.RSocketRequester; 13 | import reactor.core.publisher.Flux; 14 | import reactor.core.publisher.Mono; 15 | import reactor.test.StepVerifier; 16 | 17 | @SpringBootTest 18 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 19 | class Lec01RSocketTest { 20 | 21 | private RSocketRequester requester; 22 | 23 | @Autowired 24 | private RSocketRequester.Builder builder; 25 | 26 | @BeforeAll 27 | public void setup(){ 28 | this.requester = this.builder 29 | .transport(TcpClientTransport.create("localhost", 6565)); 30 | } 31 | 32 | @Test 33 | public void fireAndForget(){ 34 | Mono mono = this.requester.route("math.service.print") 35 | .data(new ComputationRequestDto(5)) 36 | .send(); 37 | 38 | StepVerifier.create(mono) 39 | .verifyComplete(); 40 | } 41 | 42 | @Test 43 | public void requestResponse(){ 44 | Mono mono = this.requester.route("math.service.square") 45 | .data(new ComputationRequestDto(5)) 46 | .retrieveMono(ComputationResponseDto.class) 47 | .doOnNext(System.out::println); 48 | 49 | StepVerifier.create(mono) 50 | .expectNextCount(1) 51 | .verifyComplete(); 52 | } 53 | 54 | @Test 55 | public void requestStream(){ 56 | Flux flux = this.requester.route("math.service.table") 57 | .data(new ComputationRequestDto(5)) 58 | .retrieveFlux(ComputationResponseDto.class) 59 | .doOnNext(System.out::println); 60 | 61 | StepVerifier.create(flux) 62 | .expectNextCount(10) 63 | .verifyComplete(); 64 | } 65 | 66 | @Test 67 | public void requestChannel(){ 68 | 69 | Flux dtoFlux = Flux.range(-10, 21) 70 | .map(ComputationRequestDto::new); 71 | 72 | Flux flux = this.requester.route("math.service.chart") 73 | .data(dtoFlux) 74 | .retrieveFlux(ChartResponseDto.class) 75 | .doOnNext(System.out::println); 76 | 77 | StepVerifier.create(flux) 78 | .expectNextCount(21) 79 | .verifyComplete(); 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /simple-rsocket/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.vinsguru 8 | simple-rsocket 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 1.1.5 13 | 2.16.0 14 | 5.4.2 15 | 2024.0.6 16 | 17 | 18 | 19 | io.rsocket 20 | rsocket-core 21 | ${rsocket.version} 22 | 23 | 24 | io.rsocket 25 | rsocket-transport-netty 26 | ${rsocket.version} 27 | 28 | 29 | com.fasterxml.jackson.core 30 | jackson-databind 31 | ${jackson.databind.version} 32 | 33 | 34 | org.junit.jupiter 35 | junit-jupiter-engine 36 | ${junit.version} 37 | test 38 | 39 | 40 | io.projectreactor 41 | reactor-test 42 | test 43 | 44 | 45 | 46 | 47 | 48 | 49 | io.projectreactor 50 | reactor-bom 51 | ${reactor.bom.version} 52 | pom 53 | import 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-compiler-plugin 63 | 64 | 21 65 | 21 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /spring-rsocket/src/main/java/com/vinsguru/springrsocket/security/RSocketSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket.security; 2 | 3 | import org.springframework.boot.rsocket.messaging.RSocketStrategiesCustomizer; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.messaging.rsocket.RSocketStrategies; 7 | import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; 8 | import org.springframework.security.config.Customizer; 9 | import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; 10 | import org.springframework.security.config.annotation.rsocket.EnableRSocketSecurity; 11 | import org.springframework.security.config.annotation.rsocket.RSocketSecurity; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | import org.springframework.security.messaging.handler.invocation.reactive.AuthenticationPrincipalArgumentResolver; 15 | import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor; 16 | import org.springframework.security.rsocket.metadata.SimpleAuthenticationEncoder; 17 | 18 | @Configuration 19 | @EnableRSocketSecurity 20 | @EnableReactiveMethodSecurity 21 | public class RSocketSecurityConfig { 22 | 23 | @Bean 24 | public PasswordEncoder passwordEncoder(){ 25 | return new BCryptPasswordEncoder(); 26 | } 27 | 28 | @Bean 29 | public RSocketStrategiesCustomizer strategiesCustomizer(){ 30 | return c -> c.encoder(new SimpleAuthenticationEncoder()); 31 | } 32 | 33 | @Bean 34 | public RSocketMessageHandler messageHandler(RSocketStrategies socketStrategies){ 35 | RSocketMessageHandler handler = new RSocketMessageHandler(); 36 | handler.setRSocketStrategies(socketStrategies); 37 | handler.getArgumentResolverConfigurer().addCustomResolver(new AuthenticationPrincipalArgumentResolver()); 38 | return handler; 39 | } 40 | 41 | @Bean 42 | public PayloadSocketAcceptorInterceptor interceptor(RSocketSecurity security){ 43 | return security 44 | .simpleAuthentication(Customizer.withDefaults()) 45 | .authorizePayload( 46 | authorize -> authorize 47 | .setup().permitAll() 48 | .anyRequest().permitAll() 49 | .anyExchange().permitAll() 50 | // .setup().hasRole("TRUSTED_CLIENT") 51 | // .route("*.*.*.table").hasRole("ADMIN") 52 | // .route("math.service.secured.square").hasRole("USER") 53 | ).build(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /spring-rsocket/src/test/java/com/vinsguru/springrsocket/Lec13SecurityTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.springrsocket; 2 | 3 | import com.vinsguru.springrsocket.dto.ComputationRequestDto; 4 | import com.vinsguru.springrsocket.dto.ComputationResponseDto; 5 | import io.rsocket.metadata.WellKnownMimeType; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestInstance; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.messaging.rsocket.RSocketRequester; 13 | import org.springframework.security.rsocket.metadata.UsernamePasswordMetadata; 14 | import org.springframework.util.MimeType; 15 | import org.springframework.util.MimeTypeUtils; 16 | import reactor.core.publisher.Flux; 17 | import reactor.core.publisher.Mono; 18 | import reactor.test.StepVerifier; 19 | 20 | @SpringBootTest 21 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 22 | public class Lec13SecurityTest { 23 | 24 | private final MimeType mimeType = MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString()); 25 | private RSocketRequester requester; 26 | 27 | @Autowired 28 | private RSocketRequester.Builder builder; 29 | 30 | @BeforeAll 31 | public void connectionSetup(){ 32 | UsernamePasswordMetadata metadata = new UsernamePasswordMetadata("client", "password"); 33 | this.requester = this.builder 34 | .setupMetadata(metadata, mimeType) 35 | .transport(TcpClientTransport.create("localhost", 6565)); 36 | } 37 | 38 | @Test 39 | public void requestResponse(){ 40 | UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password"); 41 | Mono mono = requester.route("math.service.secured.square") 42 | .metadata(credentials, mimeType) 43 | .data(new ComputationRequestDto(5)) 44 | .retrieveMono(ComputationResponseDto.class) 45 | .doOnNext(System.out::println); 46 | 47 | StepVerifier.create(mono) 48 | .expectNextCount(1) 49 | .verifyComplete(); 50 | } 51 | 52 | @Test 53 | public void requestStream(){ 54 | UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("admin", "password"); 55 | Flux flux = this.requester.route("math.service.secured.table") 56 | .metadata(credentials, mimeType) 57 | .data(new ComputationRequestDto(5)) 58 | .retrieveFlux(ComputationResponseDto.class) 59 | .doOnNext(System.out::println) 60 | .take(3); 61 | 62 | StepVerifier.create(flux) 63 | .expectNextCount(3) 64 | .verifyComplete(); 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /simple-rsocket/src/test/java/com/vinsguru/rsocket/Lec01RSocketTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.rsocket; 2 | 3 | import com.vinsguru.rsocket.dto.ChartResponseDto; 4 | import com.vinsguru.rsocket.dto.RequestDto; 5 | import com.vinsguru.rsocket.dto.ResponseDto; 6 | import com.vinsguru.rsocket.util.ObjectUtil; 7 | import io.rsocket.Payload; 8 | import io.rsocket.RSocket; 9 | import io.rsocket.core.RSocketConnector; 10 | import io.rsocket.transport.netty.client.TcpClientTransport; 11 | import org.junit.jupiter.api.BeforeAll; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.TestInstance; 14 | import reactor.core.publisher.Flux; 15 | import reactor.core.publisher.Mono; 16 | import reactor.test.StepVerifier; 17 | 18 | import java.time.Duration; 19 | 20 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 21 | public class Lec01RSocketTest { 22 | 23 | private RSocket rSocket; 24 | 25 | @BeforeAll 26 | public void setup(){ 27 | this.rSocket = RSocketConnector.create() 28 | .connect(TcpClientTransport.create("localhost", 6565)) 29 | .block(); 30 | } 31 | 32 | @Test 33 | public void fireAndForget(){ 34 | 35 | Payload payload = ObjectUtil.toPayload(new RequestDto(5)); 36 | Mono mono = this.rSocket.fireAndForget(payload); 37 | 38 | StepVerifier.create(mono) 39 | .verifyComplete(); 40 | } 41 | 42 | @Test 43 | public void requestResponse(){ 44 | Payload payload = ObjectUtil.toPayload(new RequestDto(5)); 45 | Mono mono = this.rSocket.requestResponse(payload) 46 | .map(p -> ObjectUtil.toObject(p, ResponseDto.class)) 47 | .doOnNext(System.out::println); 48 | 49 | StepVerifier.create(mono) 50 | .expectNextCount(1) 51 | .verifyComplete(); 52 | } 53 | 54 | @Test 55 | public void requestStream(){ 56 | Payload payload = ObjectUtil.toPayload(new RequestDto(5)); 57 | Flux flux = this.rSocket.requestStream(payload) 58 | .map(p -> ObjectUtil.toObject(p, ResponseDto.class)) 59 | .doOnNext(System.out::println) 60 | .take(4); 61 | 62 | StepVerifier.create(flux) 63 | .expectNextCount(4) 64 | .verifyComplete(); 65 | } 66 | 67 | @Test 68 | public void requestChannel(){ 69 | 70 | Flux payloadFlux = Flux.range(-10, 21) 71 | .delayElements(Duration.ofMillis(500)) 72 | .map(RequestDto::new) 73 | .map(ObjectUtil::toPayload); 74 | 75 | Flux flux = this.rSocket.requestChannel(payloadFlux) 76 | .map(p -> ObjectUtil.toObject(p, ChartResponseDto.class)) 77 | .doOnNext(System.out::println); 78 | 79 | 80 | StepVerifier.create(flux) 81 | .expectNextCount(21) 82 | .verifyComplete(); 83 | 84 | 85 | } 86 | 87 | 88 | } -------------------------------------------------------------------------------- /user-service/src/test/java/com/vinsguru/userservice/UserCrudTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.userservice; 2 | 3 | import com.vinsguru.userservice.dto.OperationType; 4 | import com.vinsguru.userservice.dto.UserDto; 5 | import io.rsocket.metadata.WellKnownMimeType; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.TestInstance; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.messaging.rsocket.RSocketRequester; 13 | import org.springframework.util.MimeType; 14 | import org.springframework.util.MimeTypeUtils; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | import reactor.test.StepVerifier; 18 | 19 | @SpringBootTest 20 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 21 | class UserCrudTest { 22 | 23 | private RSocketRequester requester; 24 | 25 | @Autowired 26 | private RSocketRequester.Builder builder; 27 | 28 | @BeforeAll 29 | public void setRequester(){ 30 | this.requester = this.builder 31 | .transport(TcpClientTransport.create("localhost", 7071)); 32 | } 33 | 34 | @Test 35 | void getAllUsersTest() { 36 | Flux flux = this.requester.route("user.get.all") 37 | .retrieveFlux(UserDto.class) 38 | .doOnNext(System.out::println); 39 | 40 | StepVerifier.create(flux) 41 | .expectNextCount(3) 42 | .verifyComplete(); 43 | } 44 | 45 | @Test 46 | void getSingleUserTest() { 47 | 48 | UserDto userDto = this.getRandomUser(); 49 | 50 | Mono mono = this.requester.route("user.get.{id}", userDto.getId()) 51 | .retrieveMono(UserDto.class) 52 | .doOnNext(System.out::println); 53 | 54 | StepVerifier.create(mono) 55 | .expectNextMatches(d -> d.getId().equals(userDto.getId())) 56 | .verifyComplete(); 57 | } 58 | 59 | @Test 60 | void postUserTest() { 61 | 62 | UserDto userDto = new UserDto(); 63 | userDto.setName("vins"); 64 | userDto.setBalance(10); 65 | 66 | Mono mono = this.requester.route("user.create") 67 | .data(userDto) 68 | .retrieveMono(UserDto.class) 69 | .doOnNext(System.out::println); 70 | 71 | StepVerifier.create(mono) 72 | .expectNextCount(1) 73 | .verifyComplete(); 74 | } 75 | 76 | @Test 77 | void putUserTest() { 78 | 79 | UserDto userDto = this.getRandomUser(); 80 | userDto.setBalance(-10); 81 | 82 | Mono mono = this.requester.route("user.update.{id}", userDto.getId()) 83 | .data(userDto) 84 | .retrieveMono(UserDto.class) 85 | .doOnNext(System.out::println); 86 | 87 | StepVerifier.create(mono) 88 | .expectNextMatches(d -> d.getBalance() == -10) 89 | .verifyComplete(); 90 | } 91 | 92 | @Test 93 | void deleteUserTest() throws InterruptedException { 94 | UserDto userDto = this.getRandomUser(); 95 | Mono mono = this.requester.route("user.delete.{id}", userDto.getId()) 96 | .send(); 97 | 98 | StepVerifier.create(mono) 99 | .verifyComplete(); 100 | 101 | Thread.sleep(1000); 102 | 103 | Flux flux = this.requester.route("user.get.all") 104 | .retrieveFlux(UserDto.class) 105 | .doOnNext(System.out::println); 106 | 107 | StepVerifier.create(flux) 108 | .expectNextCount(2) 109 | .verifyComplete(); 110 | 111 | 112 | } 113 | 114 | @Test 115 | void metadataTest() { 116 | 117 | MimeType mimeType = MimeTypeUtils.parseMimeType(WellKnownMimeType.APPLICATION_CBOR.getString()); 118 | 119 | UserDto dto = new UserDto(); 120 | dto.setName("md"); 121 | dto.setBalance(100); 122 | Mono mono = this.requester.route("user.operation.type") 123 | .metadata(OperationType.PUT, mimeType) 124 | .data(dto) 125 | .send(); 126 | 127 | StepVerifier.create(mono) 128 | .verifyComplete(); 129 | 130 | 131 | } 132 | 133 | 134 | private UserDto getRandomUser(){ 135 | return this.requester.route("user.get.all") 136 | .retrieveFlux(UserDto.class) 137 | .next() 138 | .block(); 139 | } 140 | 141 | } 142 | --------------------------------------------------------------------------------