From 92f8ec3f67743a3d93ca8b230cbeb61a91938e20 Mon Sep 17 00:00:00 2001 From: deepcloudlabs Date: Thu, 25 Jun 2020 11:09:04 +0300 Subject: [PATCH] initial commit --- .../lottery/client/MarketApiHttpClient.java | 24 +++++ .../client/MarketApiWebsocketClient.java | 45 ++++++++ ...LotteryConsumerServiceWithRateLimiter.java | 26 +++++ ...tteryConsumerServiceWithRetryTemplate.java | 3 +- .../lottery/service/StudyRetryStrategy.java | 1 - .../src/main/resources/application.properties | 2 + market-websocket-client-spring-boot/pom.xml | 63 +++++++++++ .../example/config/WebsocketClientConfig.java | 14 +++ .../com/example/config/WebsocketConfig.java | 23 ++++ .../java/com/example/event/TradeEvent.java | 102 ++++++++++++++++++ .../repository/TradeEventRepository.java | 9 ++ .../example/service/MarketClientService.java | 58 ++++++++++ .../example/service/TradeMongoService.java | 20 ++++ .../service/TradeWebsocketService.java | 21 ++++ .../src/main/resources/application.properties | 6 ++ 15 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 lottery-client-java-se/src/com/example/lottery/client/MarketApiHttpClient.java create mode 100644 lottery-client-java-se/src/com/example/lottery/client/MarketApiWebsocketClient.java create mode 100644 lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRateLimiter.java create mode 100644 market-websocket-client-spring-boot/pom.xml create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketClientConfig.java create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketConfig.java create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/event/TradeEvent.java create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/repository/TradeEventRepository.java create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/service/MarketClientService.java create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/service/TradeMongoService.java create mode 100644 market-websocket-client-spring-boot/src/main/java/com/example/service/TradeWebsocketService.java create mode 100644 market-websocket-client-spring-boot/src/main/resources/application.properties diff --git a/lottery-client-java-se/src/com/example/lottery/client/MarketApiHttpClient.java b/lottery-client-java-se/src/com/example/lottery/client/MarketApiHttpClient.java new file mode 100644 index 0000000..7a294fe --- /dev/null +++ b/lottery-client-java-se/src/com/example/lottery/client/MarketApiHttpClient.java @@ -0,0 +1,24 @@ +package com.example.lottery.client; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.TimeUnit; + +public class MarketApiHttpClient { + + private static final String URL = "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT"; + + public static void main(String[] args) throws IOException, InterruptedException { + var client = HttpClient.newHttpClient(); + var request = HttpRequest.newBuilder().uri(URI.create(URL)).header("Accept", "application/json").build(); + while(true) { + var response = client.send(request, HttpResponse.BodyHandlers.ofString()).body(); + System.out.println(response); + TimeUnit.SECONDS.sleep(1); + } + } + +} diff --git a/lottery-client-java-se/src/com/example/lottery/client/MarketApiWebsocketClient.java b/lottery-client-java-se/src/com/example/lottery/client/MarketApiWebsocketClient.java new file mode 100644 index 0000000..54c087c --- /dev/null +++ b/lottery-client-java-se/src/com/example/lottery/client/MarketApiWebsocketClient.java @@ -0,0 +1,45 @@ +package com.example.lottery.client; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.WebSocket; +import java.net.http.WebSocket.Listener; +import java.util.concurrent.CompletionStage; + +public class MarketApiWebsocketClient { + private static final String URL = "wss://stream.binance.com:9443/ws/btcusdt@trade"; + + public static void main(String[] args) throws InterruptedException { + Listener listener = new MarketWebsocketListener(); + HttpClient.newHttpClient().newWebSocketBuilder().buildAsync(URI.create(URL),listener); + Thread.sleep(60_000); + } +} + +class MarketWebsocketListener implements Listener { + + @Override + public void onOpen(WebSocket webSocket) { + System.err.println("Connected to the market."); + webSocket.request(1); + } + + @Override + public CompletionStage onText(WebSocket webSocket, CharSequence data, boolean last) { + System.err.println(data); + webSocket.request(1); + return null; + } + + @Override + public CompletionStage onClose(WebSocket webSocket, int statusCode, String reason) { + System.err.println("Connection is closed!"); + return null; + } + + @Override + public void onError(WebSocket webSocket, Throwable error) { + System.err.println("An error has occured: "+error.getMessage()+" at session "+webSocket); + } + +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRateLimiter.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRateLimiter.java new file mode 100644 index 0000000..34519c5 --- /dev/null +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRateLimiter.java @@ -0,0 +1,26 @@ +package com.example.lottery.service; + +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.example.lottery.dto.LotteryResponse; + +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; + +/** + * + * @author Binnur Kurt + * + */ +@Service +public class LotteryConsumerServiceWithRateLimiter { + + @RateLimiter(name = "lotterySrvLimiter") + public LotteryResponse getLotteryNumbers() { + System.err.println("Calling lottery service from LotteryConsumerServiceWithRateLimiter..."); + var rt = new RestTemplate(); + var response = rt.getForObject("http://localhost:8001/lottery/api/v1/numbers?column=10", LotteryResponse.class); + System.err.println(response); + return response; + } +} diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRetryTemplate.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRetryTemplate.java index 0402431..d23964c 100644 --- a/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRetryTemplate.java +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/LotteryConsumerServiceWithRetryTemplate.java @@ -7,12 +7,11 @@ import org.springframework.retry.RetryCallback; import org.springframework.retry.support.RetryTemplate; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.example.lottery.dto.LotteryResponse; -@Service +//@Service public class LotteryConsumerServiceWithRetryTemplate { @Autowired private RetryTemplate retryTemplate; diff --git a/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java b/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java index 46fd133..16c7dda 100644 --- a/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java +++ b/lottery-consumer-service/src/main/java/com/example/lottery/service/StudyRetryStrategy.java @@ -11,7 +11,6 @@ import org.springframework.web.client.RestTemplate; import com.example.lottery.dto.LotteryResponse; -import com.google.inject.Exposed; /** * diff --git a/lottery-consumer-service/src/main/resources/application.properties b/lottery-consumer-service/src/main/resources/application.properties index 2428e89..7624d41 100644 --- a/lottery-consumer-service/src/main/resources/application.properties +++ b/lottery-consumer-service/src/main/resources/application.properties @@ -1,3 +1,5 @@ +spring.main.banner-mode=off + server.address=localhost server.port=5001 diff --git a/market-websocket-client-spring-boot/pom.xml b/market-websocket-client-spring-boot/pom.xml new file mode 100644 index 0000000..8055304 --- /dev/null +++ b/market-websocket-client-spring-boot/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.1.RELEASE + + + com.example + market-websocket-client-spring-boot + 0.0.1-SNAPSHOT + market-websocket-client-spring-boot + Spring Boot Project for Market Client + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-websocket + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketClientConfig.java b/market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketClientConfig.java new file mode 100644 index 0000000..d8d6949 --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketClientConfig.java @@ -0,0 +1,14 @@ +package com.example.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.client.WebSocketClient; +import org.springframework.web.socket.client.standard.StandardWebSocketClient; + +@Configuration +public class WebsocketClientConfig { + @Bean + public WebSocketClient webSocketClient() { + return new StandardWebSocketClient(); + } +} diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketConfig.java b/market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketConfig.java new file mode 100644 index 0000000..7e1ffe6 --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/config/WebsocketConfig.java @@ -0,0 +1,23 @@ +package com.example.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +@Configuration +@EnableWebSocketMessageBroker +public class WebsocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + registry.enableSimpleBroker("/topic"); + registry.setApplicationDestinationPrefixes("/ws"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/changes").setAllowedOrigins("*").withSockJS(); + } +} diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/event/TradeEvent.java b/market-websocket-client-spring-boot/src/main/java/com/example/event/TradeEvent.java new file mode 100644 index 0000000..c127822 --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/event/TradeEvent.java @@ -0,0 +1,102 @@ +package com.example.event; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import com.fasterxml.jackson.annotation.JsonProperty; + +@Document(collection = "trades") +public class TradeEvent { + @Id + private String id; + @JsonProperty("s") + private String symbol; + @JsonProperty("p") + private String price; + @JsonProperty("q") + private String quantity; + @JsonProperty("T") + private long timestamp; + @JsonProperty("t") + private long eventId; + @JsonProperty("a") + private long askId; + @JsonProperty("b") + private long bidId; + + public TradeEvent() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getPrice() { + return price; + } + + public void setPrice(String price) { + this.price = price; + } + + public String getQuantity() { + return quantity; + } + + public void setQuantity(String quantity) { + this.quantity = quantity; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public long getEventId() { + return eventId; + } + + public void setEventId(long eventId) { + this.eventId = eventId; + } + + public long getAskId() { + return askId; + } + + public void setAskId(long askId) { + this.askId = askId; + } + + public long getBidId() { + return bidId; + } + + public void setBidId(long bidId) { + this.bidId = bidId; + } + + @Override + public String toString() { + return "TradeEvent [id=" + id + ", symbol=" + symbol + ", price=" + price + ", quantity=" + quantity + + ", timestamp=" + timestamp + ", eventId=" + eventId + ", askId=" + askId + ", bidId=" + bidId + "]"; + } + + + +} diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/repository/TradeEventRepository.java b/market-websocket-client-spring-boot/src/main/java/com/example/repository/TradeEventRepository.java new file mode 100644 index 0000000..4f0f14b --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/repository/TradeEventRepository.java @@ -0,0 +1,9 @@ +package com.example.repository; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.example.event.TradeEvent; + +public interface TradeEventRepository extends MongoRepository { + +} diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/service/MarketClientService.java b/market-websocket-client-spring-boot/src/main/java/com/example/service/MarketClientService.java new file mode 100644 index 0000000..35b7d5e --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/service/MarketClientService.java @@ -0,0 +1,58 @@ +package com.example.service; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.client.WebSocketClient; + +import com.example.event.TradeEvent; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Service +public class MarketClientService implements WebSocketHandler { + @Autowired private WebSocketClient websocketClient; + @Value("${market.url}") private String marketUrl; + @Autowired private ObjectMapper mapper; + @Autowired private ApplicationEventPublisher eventPublisher; + + @PostConstruct + public void init() { + websocketClient.doHandshake(this, marketUrl); + } + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + System.err.println("Connected to the market"); + } + + @Override + public void handleMessage(WebSocketSession session, WebSocketMessage message) throws Exception { + String payload = message.getPayload().toString(); + TradeEvent trade = mapper.readValue(payload,TradeEvent.class); + eventPublisher.publishEvent(trade); + } + + @Override + public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { + System.err.println("An error has occurred: "+exception.getMessage()); + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { + System.err.println("Connection is closed!"); + } + + @Override + public boolean supportsPartialMessages() { + return false; + } + + +} diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/service/TradeMongoService.java b/market-websocket-client-spring-boot/src/main/java/com/example/service/TradeMongoService.java new file mode 100644 index 0000000..87236f9 --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/service/TradeMongoService.java @@ -0,0 +1,20 @@ +package com.example.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +import com.example.event.TradeEvent; +import com.example.repository.TradeEventRepository; + +@Service +public class TradeMongoService { + @Autowired + private TradeEventRepository repository; + + @EventListener + public void handleEvent(TradeEvent trade) { + repository.save(trade); + System.err.println("TradeMongoService has received one trade event: "+trade); + } +} diff --git a/market-websocket-client-spring-boot/src/main/java/com/example/service/TradeWebsocketService.java b/market-websocket-client-spring-boot/src/main/java/com/example/service/TradeWebsocketService.java new file mode 100644 index 0000000..748ad0e --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/java/com/example/service/TradeWebsocketService.java @@ -0,0 +1,21 @@ +package com.example.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Service; + +import com.example.event.TradeEvent; + +@Service +public class TradeWebsocketService { + + @Autowired + private SimpMessagingTemplate template; + + @EventListener + public void handleEvent(TradeEvent trade) { + System.err.println("TradeWebsocketService has received one trade event: "+trade); + template.convertAndSend("/topic/changes", trade); + } +} diff --git a/market-websocket-client-spring-boot/src/main/resources/application.properties b/market-websocket-client-spring-boot/src/main/resources/application.properties new file mode 100644 index 0000000..422f218 --- /dev/null +++ b/market-websocket-client-spring-boot/src/main/resources/application.properties @@ -0,0 +1,6 @@ +server.address=localhost +server.port=7070 +market.url=wss://stream.binance.com:9443/ws/btcusdt@trade + +# mongodb configuration +spring.data.mongodb.uri=mongodb://localhost:27017/market \ No newline at end of file