Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP and WS RPC APIs to listen on the same socket #133

Merged
merged 9 commits into from
Aug 17, 2023
8 changes: 3 additions & 5 deletions src/main/java/com/limechain/Main.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.limechain;

import com.limechain.lightclient.LightClient;
import com.limechain.rpc.http.server.HttpRpc;
import com.limechain.rpc.ws.server.WebSocketRPC;
import com.limechain.rpc.server.RpcApp;
import sun.misc.Signal;

public class Main {
public static void main(String[] args) {
HttpRpc httpRpc = new HttpRpc();
WebSocketRPC wsRpc = new WebSocketRPC();
LightClient client = new LightClient(args, httpRpc, wsRpc);
RpcApp rpcApp = new RpcApp();
LightClient client = new LightClient(args, rpcApp);

client.start();
Signal.handle(new Signal("INT"), signal -> client.stop());
Expand Down
19 changes: 7 additions & 12 deletions src/main/java/com/limechain/lightclient/LightClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

import com.limechain.network.ConnectionManager;
import com.limechain.network.Network;
import com.limechain.rpc.http.server.AppBean;
import com.limechain.rpc.http.server.HttpRpc;
import com.limechain.rpc.ws.server.WebSocketRPC;
import com.limechain.rpc.server.AppBean;
import com.limechain.rpc.server.RpcApp;
import com.limechain.sync.warpsync.WarpSyncMachine;
import lombok.SneakyThrows;
import lombok.extern.java.Log;
Expand All @@ -19,16 +18,14 @@
public class LightClient {
// TODO: Add service dependencies i.e rpc, sync, network, etc.
private final String[] cliArgs;
private final HttpRpc httpRpc;
private final WebSocketRPC wsRpc;
private final RpcApp rpcApp;
private final ConnectionManager connectionManager = ConnectionManager.getInstance();
private Network network;
private WarpSyncMachine warpSyncMachine;

public LightClient(String[] cliArgs, HttpRpc httpRpc, WebSocketRPC wsRpc) {
public LightClient(String[] cliArgs, RpcApp rpcApp) {
this.cliArgs = cliArgs;
this.httpRpc = httpRpc;
this.wsRpc = wsRpc;
this.rpcApp = rpcApp;
}

/**
Expand All @@ -37,8 +34,7 @@ public LightClient(String[] cliArgs, HttpRpc httpRpc, WebSocketRPC wsRpc) {
@SneakyThrows
public void start() {
// TODO: Add business logic
this.httpRpc.start(cliArgs);
this.wsRpc.start(cliArgs);
this.rpcApp.start(cliArgs);

this.network = AppBean.getBean(Network.class);
this.network.start();
Expand All @@ -65,8 +61,7 @@ public void start() {
*/
public void stop() {
// TODO: Stop running services
this.httpRpc.stop();
this.wsRpc.stop();
this.rpcApp.stop();
log.log(Level.INFO, "\uD83D\uDED1Stopped light client!");
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/limechain/network/Network.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ private void ping(PeerId peerId) {

public void updateCurrentSelectedPeer() {
Random random = new Random();
if(connectionManager.getPeerIds().size() == 0) return;
if(connectionManager.getPeerIds().isEmpty()) return;
this.currentSelectedPeer = connectionManager.getPeerIds().stream()
.skip(random.nextInt(connectionManager.getPeerIds().size())).findAny().orElse(null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.ws.client;
package com.limechain.rpc.client;

import lombok.extern.java.Log;
import org.java_websocket.client.WebSocketClient;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.ws.client;
package com.limechain.rpc.client;

import com.limechain.rpc.pubsub.Message;
import com.limechain.rpc.pubsub.PubSubService;
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/com/limechain/rpc/config/CommonConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
import org.springframework.context.annotation.Configuration;

/**
* Spring configuration class used to instantiate beans used by both http and ws rpc modules.
* <p>
* <b>IMPORTANT: This class is invoked twice on Host startup. This means that unless beans are singletons,
* the http and ws spring apps will hold different bean references.</b>
* Spring configuration class used to instantiate beans.
*/
@Configuration
public class CommonConfig {
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/limechain/rpc/config/RpcConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.limechain.rpc.config;

import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.socket.server.support.WebSocketHandlerMapping;

/**
* Spring configuration class used to configure the websocket handler mapping
* to process only websocket requests or http requests with upgrade headers only
*
* <p>
* The configuration is in separate file from {@link CommonConfig} because of the circular dependency loop
*/
@Configuration
@Log
public class RpcConfig {

public RpcConfig(@Qualifier("webSocketHandlerMapping") HandlerMapping webSocketHandlerMapping) {
if(webSocketHandlerMapping instanceof WebSocketHandlerMapping handlerMapping)
handlerMapping.setWebSocketUpgradeMatch(true);
else {
String message = "%s was not found. The WS Rpc and Http Rpc may not work as intended!";
String formattedMsg = String.format(message, WebSocketHandlerMapping.class.getName());
log.severe(formattedMsg);
}
}

}
67 changes: 0 additions & 67 deletions src/main/java/com/limechain/rpc/http/server/HttpRpc.java

This file was deleted.

5 changes: 0 additions & 5 deletions src/main/java/com/limechain/rpc/pubsub/PubSubService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
* A singleton mediator class standing between {@link com.limechain.rpc.pubsub.publisher.Publisher}
* and {@link AbstractSubscriberChannel} which accepts messages from the formers and sends them at some point
* to the latter.
* <p>
* <b>IMPORTANT: This class is a singleton as both http and ws Spring apps
* use it and we want to always have a single reference.
* Otherwise each Spring app will have it's own instance of this
* service which will lead to undocumented runtime behaviour</b>
*/
@Log
public class PubSubService {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.http.server;
package com.limechain.rpc.server;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.ws.server;
package com.limechain.rpc.server;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.SpringApplication;
Expand All @@ -9,20 +9,16 @@
import java.util.Collections;

/**
* Main WS Spring application class. Starts one of the two Spring applications.
* <p>
* Reason for having two Spring applications is because we have to expose both http and ws
* <a href="https://wiki.polkadot.network/docs/build-node-interaction#polkadot-rpc">endpoints on different ports</a>
* which isn't possible with a single Spring app.
* Main RPC Spring application class.
*/
@SpringBootApplication
@ComponentScan(basePackages = {
"com.limechain.rpc.config",
"com.limechain.rpc.methods",
"com.limechain.rpc.ws.server",
"com.limechain.rpc.server",
"com.limechain.storage"
})
public class WebSocketRPC {
public class RpcApp {

/**
* Port the Spring app will run on
Expand All @@ -42,7 +38,7 @@ public class WebSocketRPC {
* @see com.limechain.rpc.config.CommonConfig#hostConfig(ApplicationArguments)
*/
public void start(String[] cliArgs) {
SpringApplication app = new SpringApplication(WebSocketRPC.class);
SpringApplication app = new SpringApplication(RpcApp.class);
app.setDefaultProperties(Collections.singletonMap("server.port", serverPort));
ConfigurableApplicationContext ctx = app.run(cliArgs);
this.springCtx = ctx;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.ws.server;
package com.limechain.rpc.server;

import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.ws.server;
package com.limechain.rpc.server;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.googlecode.jsonrpc4j.JsonRpcBasicServer;
Expand All @@ -24,15 +24,15 @@

@Component
@Log
public class WebSocketHandler extends TextWebSocketHandler {
public class RpcWsHandler extends TextWebSocketHandler {

private final JsonRpcBasicServer server;
private final PubSubService pubSubService = PubSubService.getInstance();
private final ObjectMapper mapper = new ObjectMapper();
private final ChainHeadRpc chainHeadRpc;
private final TransactionRpc transactionRpc;

public WebSocketHandler(RPCMethods rpcMethods, ChainHeadRpc chainHeadRpc, TransactionRpc transactionRpc) {
public RpcWsHandler(RPCMethods rpcMethods, ChainHeadRpc chainHeadRpc, TransactionRpc transactionRpc) {
ObjectMapper mapper = new ObjectMapper();
this.server = new JsonRpcBasicServer(mapper, rpcMethods);
this.chainHeadRpc = chainHeadRpc;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.limechain.rpc.ws.server;
package com.limechain.rpc.server;

import com.limechain.config.HostConfig;
import com.limechain.rpc.methods.RPCMethods;
Expand All @@ -17,15 +17,15 @@
*/
@Configuration
@EnableWebSocket
public class WebSocketRoutingConfig implements WebSocketConfigurer {
public class RpcWsRoutingConfig implements WebSocketConfigurer {

/**
* Dependencies will be injected from {@link com.limechain.rpc.config.CommonConfig}
*/
private final RPCMethods rpcMethods;
private final HostConfig hostConfig;

public WebSocketRoutingConfig(RPCMethods rpcMethods, HostConfig hostConfig) {
public RpcWsRoutingConfig(RPCMethods rpcMethods, HostConfig hostConfig) {
this.rpcMethods = rpcMethods;
this.hostConfig = hostConfig;
}
Expand All @@ -39,14 +39,14 @@ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
}

/**
* The handler that will be executed when ws request is received
* The handler that will be executed when ws rpc request is received
*/
public WebSocketHandler webSocketHandler() {
return new WebSocketHandler(rpcMethods, chainHeadRpc(), transactionRpc());
public RpcWsHandler webSocketHandler() {
return new RpcWsHandler(rpcMethods, chainHeadRpc(), transactionRpc());
}

/**
* Additional beans used by {@link WebSocketHandler}
* Additional beans used by {@link RpcWsHandler}
*/
@Bean
public ChainHeadRpc chainHeadRpc() {
Expand Down
Loading