forked from PoC-Consortium/burstcoin
-
-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip: implemented block and pending tx ws events - tests missing
- Loading branch information
Showing
17 changed files
with
317 additions
and
69 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,99 @@ | ||
package brs.web.api.ws; | ||
|
||
import brs.*; | ||
import brs.web.api.ws.handler.BlockGeneratedEventHandler; | ||
import brs.web.api.ws.handler.PendingTransactionsAddedEventHandler; | ||
import brs.web.api.ws.handler.TestEventHandler; | ||
import brs.web.server.WebServerContext; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.List; | ||
import java.util.Timer; | ||
import java.util.TimerTask; | ||
import java.util.concurrent.*; | ||
|
||
public class BlockchainEventNotifier { | ||
|
||
private final static int SHUTDOWN_TIMEOUT_SECS = 5; | ||
private final static int IO_THREAD_COUNT = 10; | ||
private final ExecutorService executor; | ||
private Logger logger = LoggerFactory.getLogger(BlockchainEventNotifier.class); | ||
private static BlockchainEventNotifier instance; | ||
private final WebServerContext context; | ||
|
||
private ConcurrentHashMap<String, WebSocketConnection> connections = new ConcurrentHashMap<>(); | ||
|
||
public static BlockchainEventNotifier getInstance(WebServerContext context) { | ||
if (BlockchainEventNotifier.instance == null) { | ||
BlockchainEventNotifier.instance = new BlockchainEventNotifier(context); | ||
} | ||
return BlockchainEventNotifier.instance; | ||
} | ||
|
||
private BlockchainEventNotifier(WebServerContext context) { | ||
this.context = context; | ||
this.executor = Executors.newFixedThreadPool(IO_THREAD_COUNT); | ||
this.context.getBlockchainProcessor().addListener(this::onNewBlockEvent, BlockchainProcessor.Event.BLOCK_GENERATED); | ||
this.context.getTransactionProcessor().addListener(this::onPendingTransactionEvent, TransactionProcessor.Event.ADDED_UNCONFIRMED_TRANSACTIONS); | ||
|
||
Timer timer = new Timer(); | ||
timer.scheduleAtFixedRate(wrap(this::onTestEvent), 0, 10_000); | ||
} | ||
|
||
private static TimerTask wrap(Runnable r) { | ||
return new TimerTask() { | ||
|
||
@Override | ||
public void run() { | ||
r.run(); | ||
} | ||
}; | ||
} | ||
|
||
public void addConnection(WebSocketConnection connection) { | ||
connections.put(connection.getId(), connection); | ||
} | ||
|
||
public void removeConnection(WebSocketConnection connection) { | ||
connections.remove(connection.getId()); | ||
} | ||
|
||
public void onTestEvent() { | ||
this.executor.submit(() -> { | ||
connections.values().forEach(connection -> new TestEventHandler(connection).notify("some test data")); | ||
}); | ||
} | ||
|
||
public void onNewBlockEvent(Block block) { | ||
this.executor.submit(() -> { | ||
connections.values().forEach(connection -> new BlockGeneratedEventHandler(connection).notify(block)); | ||
}); | ||
} | ||
|
||
private void onPendingTransactionEvent(List<? extends Transaction> transactions) { | ||
this.executor.submit(() -> { | ||
connections.values().forEach(connection -> new PendingTransactionsAddedEventHandler(connection).notify(transactions)); | ||
}); | ||
} | ||
|
||
public void shutdown() { | ||
if (!executor.isTerminated()) { | ||
logger.info("Closing {} websocket connection(s)...", connections.size()); | ||
executor.submit(() -> { | ||
connections.values().forEach(WebSocketConnection::close); | ||
}); | ||
executor.shutdown(); | ||
try { | ||
executor.awaitTermination(SHUTDOWN_TIMEOUT_SECS, TimeUnit.SECONDS); // should be able to close all connections within 5 seconds | ||
} catch (InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
} | ||
if (!executor.isTerminated()) { | ||
logger.warn("Some threads didn't terminate, forcing shutdown"); | ||
executor.shutdownNow(); | ||
} | ||
} | ||
} | ||
|
||
} |
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,39 @@ | ||
package brs.web.api.ws; | ||
|
||
import org.eclipse.jetty.websocket.api.RemoteEndpoint; | ||
import org.eclipse.jetty.websocket.api.Session; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
|
||
public class WebSocketConnection { | ||
private static final Logger logger = LoggerFactory.getLogger(WebSocketConnection.class); | ||
|
||
private final Session session; | ||
|
||
public WebSocketConnection(Session session) { | ||
this.session = session; | ||
} | ||
|
||
public String getId() { | ||
return session.getRemoteAddress().toString(); | ||
} | ||
|
||
public Session getSession() { | ||
return session; | ||
} | ||
|
||
public void sendMessage(String message) { | ||
RemoteEndpoint remote = this.getSession().getRemote(); | ||
try { | ||
remote.sendString(message); | ||
} catch (IOException e) { | ||
logger.debug("Error sending message to {}: {}", remote.getRemoteAddress().toString(), e.getMessage()); | ||
} | ||
} | ||
|
||
public void close() { | ||
this.getSession().close(); | ||
} | ||
} |
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,22 @@ | ||
package brs.web.api.ws.common; | ||
|
||
public abstract class BaseWebSocketResponse<T> { | ||
|
||
private final String eventName; | ||
private final T payload; | ||
|
||
public BaseWebSocketResponse(String eventName, T payload) { | ||
this.eventName = eventName; | ||
this.payload = payload; | ||
} | ||
|
||
public abstract String toString(); | ||
|
||
public T getPayload() { | ||
return payload; | ||
} | ||
|
||
public String getEventName() { | ||
return eventName; | ||
} | ||
} |
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,15 @@ | ||
package brs.web.api.ws.common; | ||
|
||
import com.google.gson.Gson; | ||
|
||
public class JSONWebSocketResponse<T> extends BaseWebSocketResponse<T> { | ||
public JSONWebSocketResponse(String eventName, T payload) { | ||
super(eventName, payload); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
Gson gson = new Gson(); | ||
return gson.toJson(this); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/brs/web/api/ws/handler/AbstractWebSocketOutgoingEventHandlerImpl.java
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,19 @@ | ||
package brs.web.api.ws.handler; | ||
|
||
import brs.web.api.ws.WebSocketConnection; | ||
|
||
public abstract class AbstractWebSocketOutgoingEventHandlerImpl<T> implements WebSocketOutgoingEventHandler<T> { | ||
|
||
private final WebSocketConnection connection; | ||
|
||
protected AbstractWebSocketOutgoingEventHandlerImpl(WebSocketConnection connection) { | ||
this.connection = connection; | ||
} | ||
|
||
@Override | ||
public abstract void notify(T t); | ||
|
||
public WebSocketConnection getConnection() { | ||
return connection; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
32 changes: 32 additions & 0 deletions
32
src/brs/web/api/ws/handler/BlockGeneratedEventHandler.java
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,32 @@ | ||
package brs.web.api.ws.handler; | ||
|
||
import brs.Block; | ||
import brs.Transaction; | ||
import brs.web.api.ws.WebSocketConnection; | ||
import brs.web.api.ws.common.JSONWebSocketResponse; | ||
|
||
public class BlockGeneratedEventHandler extends AbstractWebSocketOutgoingEventHandlerImpl<Block> { | ||
public BlockGeneratedEventHandler(WebSocketConnection connection) { | ||
super(connection); | ||
} | ||
|
||
@Override | ||
public void notify(Block block) { | ||
JSONWebSocketResponse<GeneratedBlockPayload> response = new JSONWebSocketResponse<>("BlockGenerated", new GeneratedBlockPayload(block)); | ||
this.getConnection().sendMessage(response.toString()); | ||
} | ||
|
||
private class GeneratedBlockPayload { | ||
private final String blockId; | ||
private final int height; | ||
private final int timestamp; | ||
private final String[] transactionIds; | ||
|
||
public GeneratedBlockPayload(Block block) { | ||
this.blockId = block.getStringId(); | ||
this.height = block.getHeight(); | ||
this.timestamp = block.getTimestamp(); | ||
this.transactionIds = block.getTransactions().stream().map(Transaction::getStringId).toArray(String[]::new); | ||
} | ||
} | ||
} |
Oops, something went wrong.