forked from LimeChain/Fruzhin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement WsRpcClient and support all required rpc methods. (#21)
# Description Fruzhin's web client needs to support all subscription RPC methods via WS. This PR provides such an implementation. Also further adds support for more RPC methods. - What does this PR do? Adds support for WS RPC communication with a full node. - Why are these changes needed? So that all required by the polkadot spec RPC methods are supported and a more user friendly RPC api is available. - How were these changes implemented and what do they affect? By adding a WS client implementation that communicates with an external full node. Also exposes a client that can be used to invoke RPC methods. Fixes LimeChain#519 ## Checklist: - [X] I have read the [contributing guidelines](https://github.com/LimeChain/Fruzhin/blob/dev/CONTRIBUTING.md). - [X] My PR title matches the [Conventional Commits spec](https://www.conventionalcommits.org/). - [X] My change requires a change to the documentation. - [X] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [X] All new and existing tests passed.
- Loading branch information
Showing
6 changed files
with
138 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.limechain.rpc; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum WebsocketState { | ||
|
||
CONNECTING(0), | ||
OPEN(1), | ||
CLOSING(2), | ||
CLOSED(3); | ||
|
||
private final int intValue; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.limechain.rpc; | ||
|
||
import org.teavm.jso.JSObject; | ||
import org.teavm.jso.core.JSString; | ||
|
||
/** | ||
* TeaVM overlay interface for a client used to communicate with a full node's RPC server. | ||
*/ | ||
public interface WsRpcClient extends JSObject { | ||
|
||
void send(JSString rpcString); | ||
|
||
String nextResponse(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.limechain.rpc; | ||
|
||
import com.limechain.constants.RpcConstants; | ||
import lombok.SneakyThrows; | ||
import lombok.extern.java.Log; | ||
import org.teavm.jso.browser.Window; | ||
import org.teavm.jso.core.JSString; | ||
import org.teavm.jso.websocket.WebSocket; | ||
|
||
import java.util.ArrayDeque; | ||
import java.util.Queue; | ||
|
||
/** | ||
* The implementation of {@link WsRpcClient}. Uses a native JS Websocket implementation. | ||
*/ | ||
@Log | ||
public class WsRpcClientImpl implements WsRpcClient { | ||
|
||
private static final int WS_OPEN_WAIT_MS = 50; | ||
|
||
private WebSocket ws; | ||
private final Queue<String> responseQueue; | ||
|
||
public WsRpcClientImpl() { | ||
responseQueue = new ArrayDeque<>(); | ||
openWebsocketConnection(); | ||
} | ||
|
||
private void openWebsocketConnection() { | ||
log.info("Initializing RPC websocket connection..."); | ||
//TODO change when configuring chain. | ||
ws = new WebSocket(RpcConstants.POLKADOT_WS_RPC); | ||
initHandlers(); | ||
} | ||
|
||
private void initHandlers() { | ||
ws.onClose(e -> { | ||
log.info("RPC websocket connection was closed."); | ||
log.info("Retrying connection..."); | ||
Window.setTimeout(this::openWebsocketConnection, 1000); | ||
}); | ||
|
||
ws.onError(e -> { | ||
log.warning("There was an error in the RPC websocket connection. Closing connection..."); | ||
ws.close(); | ||
}); | ||
|
||
ws.onOpen(e -> log.info("Websocket connection is open.")); | ||
ws.onMessage(e -> responseQueue.offer(e.getDataAsString())); | ||
} | ||
|
||
/** | ||
* Waits for the current ws connection to be in an opened state then sends an RPC request to the full node. | ||
*/ | ||
@Override | ||
public void send(JSString rpcString) { | ||
new Thread(() -> { | ||
handleSocketState(); | ||
ws.send(rpcString.stringValue()); | ||
}).start(); | ||
} | ||
|
||
/** | ||
* Handles the state of the websocket when sending a message. If the connection is in a closing (2) or a closed (3) | ||
* state the client throws an error. | ||
*/ | ||
@SneakyThrows | ||
private void handleSocketState() { | ||
int startState = ws.getReadyState(); | ||
int openedState = WebsocketState.OPEN.getIntValue(); | ||
|
||
while (startState != openedState) { | ||
if (startState > openedState) { | ||
throw new Exception("Calling function of a closed websocket is prohibited."); | ||
} | ||
|
||
Thread.sleep(WS_OPEN_WAIT_MS); | ||
startState = ws.getReadyState(); | ||
} | ||
} | ||
|
||
/** | ||
* Polls the first item in the queue and returns it as a string. | ||
*/ | ||
@Override | ||
public String nextResponse() { | ||
return responseQueue.poll(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters