use of services.moleculer.util.FastBuildTree in project moleculer-java by moleculer-java.
the class TcpTransporter method processGossipRequest.
// --- GOSSIP REQUEST MESSAGE RECEIVED ---
protected Tree processGossipRequest(Tree data) throws Exception {
// Debug
String sender = data.get("sender", (String) null);
if (debug) {
logger.info("Gossip request received from \"" + sender + "\" node:\r\n" + data);
}
// Add "online" and "offline" response blocks
LinkedList<NodeDescriptor> allNodes = new LinkedList<>(nodes.values());
NodeDescriptor descriptor = getDescriptor();
allNodes.add(descriptor);
int size = allNodes.size() + 1;
FastBuildTree onlineRsp = new FastBuildTree(size);
FastBuildTree offlineRsp = new FastBuildTree(size);
// Online / offline nodes in request
Tree onlineReq = data.get("online");
Tree offlineReq = data.get("offline");
// Loop in nodes
LinkedList<NodeDescriptor> disconnectedNodes = new LinkedList<>();
for (NodeDescriptor node : allNodes) {
node.writeLock.lock();
try {
Tree online = onlineReq == null ? null : onlineReq.get(node.nodeID);
Tree offline = offlineReq == null ? null : offlineReq.get(node.nodeID);
// Online or offline sequence number
long seq = 0;
// CPU data
long cpuSeq = 0;
int cpu = 0;
if (offline != null) {
if (!offline.isPrimitive()) {
logger.warn("Invalid \"offline\" block: " + offline.toString(false));
continue;
}
seq = offline.asLong();
} else if (online != null) {
if (!online.isEnumeration() || online.size() != 3) {
logger.warn("Invalid \"online\" block: " + online.toString(false));
continue;
}
seq = online.get(0).asLong();
cpuSeq = online.get(1).asLong();
cpu = online.get(2).asInteger();
}
if ((seq == 0 || seq < node.seq) && node.seq > 0) {
// We have newer info or requester doesn't know it
if (node.offlineSince == 0) {
if (!node.info.isEmpty()) {
if ((cpuSeq == 0 || cpuSeq < node.cpuSeq) && node.cpuSeq > 0) {
ArrayList<Object> array = new ArrayList<>(3);
array.add(node.info.asObject());
array.add(node.cpuSeq);
array.add(node.cpu);
onlineRsp.putUnsafe(node.nodeID, array);
} else {
onlineRsp.putUnsafe(node.nodeID, Collections.singletonList(node.info.asObject()));
}
}
} else {
offlineRsp.putUnsafe(node.nodeID, node.seq);
}
}
if (offline != null) {
// Requester said it is OFFLINE
if (node.offlineSince > 0) {
// We also knew it as offline
node.markAsOffline(seq);
continue;
}
if (!node.local) {
if (node.offlineSince == 0) {
// We know it is online, so we change it to offline
if (node.markAsOffline(seq)) {
// Remove remote actions and listeners
registry.removeActions(node.nodeID);
eventbus.removeListeners(node.nodeID);
writer.close(node.nodeID);
disconnectedNodes.add(node);
} else if (seq == node.seq) {
// We send back that this node is online
node.seq = seq + 1;
node.info.put("seq", node.seq);
if (cpuSeq < node.cpuSeq && node.cpuSeq > 0) {
ArrayList<Object> array = new ArrayList<>(3);
array.add(node.info.asObject());
array.add(node.cpuSeq);
array.add(node.cpu);
onlineRsp.putUnsafe(node.nodeID, array);
} else {
onlineRsp.putUnsafe(node.nodeID, Collections.singletonList(node.info.asObject()));
}
}
}
continue;
}
} else if (online != null) {
// Requester said it is ONLINE
if (node.offlineSince == 0) {
if (cpuSeq > node.cpuSeq) {
// We update our CPU info
node.updateCpu(cpuSeq, cpu);
} else if (cpuSeq < node.cpuSeq && node.cpuSeq > 0) {
// We have newer CPU value, send back
ArrayList<Object> array = new ArrayList<>(2);
array.add(node.cpuSeq);
array.add(node.cpu);
onlineRsp.putUnsafe(node.nodeID, array);
}
} else {
// request it and we'll receive its INFO
continue;
}
}
} finally {
node.writeLock.unlock();
}
}
// Create gossip response
FastBuildTree root = new FastBuildTree(4);
root.putUnsafe("ver", ServiceBroker.PROTOCOL_VERSION);
root.putUnsafe("sender", nodeID);
// Remove empty blocks
boolean emptyOnlineBlock = onlineRsp.isEmpty();
boolean emptyOfflineBlock = offlineRsp.isEmpty();
if (emptyOnlineBlock && emptyOfflineBlock) {
// Message is empty
return root;
}
if (!emptyOnlineBlock) {
root.putUnsafe("online", onlineRsp.asObject());
}
if (!emptyOfflineBlock) {
root.putUnsafe("offline", offlineRsp.asObject());
}
// Debug
if (debug) {
logger.info("Gossip response submitting to \"" + sender + "\" node:\r\n" + root);
}
// Serialize response
byte[] packet = serialize(PACKET_GOSSIP_RSP_ID, root);
// Send response
writer.send(sender, packet);
// Notify listeners (unexpected disconnection)
for (NodeDescriptor node : disconnectedNodes) {
logger.info("Node \"" + node.nodeID + "\" disconnected.");
broadcastNodeDisconnected(node.info, true);
}
// For unit testing
return root;
}
use of services.moleculer.util.FastBuildTree in project moleculer-java by moleculer-java.
the class TcpTransporter method received.
// --- MESSAGE RECEIVED ---
public void received(byte packetID, byte[] packet) {
executor.execute(() -> {
// Parse message
Tree data;
try {
data = serializer.read(packet);
} catch (Exception cause) {
logger.warn("Unable to parse incoming message!", cause);
return;
}
// Send message to proper component
try {
switch(packetID) {
case PACKET_EVENT_ID:
// Incoming event
if (debug) {
logger.info("Event message received:\r\n" + data);
}
eventbus.receiveEvent(data);
return;
case PACKET_REQUEST_ID:
// Incoming request
if (debug) {
logger.info("Request message received:\r\n" + data);
}
registry.receiveRequest(data);
return;
case PACKET_RESPONSE_ID:
// Incoming response
if (debug) {
logger.info("Response message received:\r\n" + data);
}
registry.receiveResponse(data);
return;
case PACKET_PING_ID:
// Send pong
if (debug) {
logger.info("Ping message received:\r\n" + data);
}
String id = data.get("id", "");
if (id == null || id.isEmpty()) {
logger.warn("Missing \"id\" property:\r\n" + data);
return;
}
String sender = data.get("sender", "");
if (sender == null || sender.isEmpty()) {
logger.warn("Missing \"sender\" property:\r\n" + data);
return;
}
long time = data.get("time", 0L);
FastBuildTree msg = new FastBuildTree(5);
msg.putUnsafe("ver", PROTOCOL_VERSION);
msg.putUnsafe("sender", this.nodeID);
msg.putUnsafe("id", id);
msg.putUnsafe("received", time);
msg.putUnsafe("time", System.currentTimeMillis());
writer.send(sender, serialize(PACKET_PONG_ID, msg));
return;
case PACKET_PONG_ID:
// Pong received
if (debug) {
logger.info("Pong message received:\r\n" + data);
}
registry.receiveResponse(data);
return;
case PACKET_GOSSIP_REQ_ID:
// Incoming gossip request
processGossipRequest(data);
return;
case PACKET_GOSSIP_RSP_ID:
// Incoming gossip request
processGossipResponse(data);
return;
case PACKET_GOSSIP_HELLO_ID:
// Incoming "hello" message
processGossipHello(data);
return;
default:
logger.warn("Unsupported message ID (" + packetID + ")!");
}
} catch (Exception cause) {
logger.warn("Unable to process incoming message!", cause);
}
});
}
use of services.moleculer.util.FastBuildTree in project moleculer-java by moleculer-java.
the class TcpTransporter method generateGossipHello.
/**
* Create Gossip HELLO packet. Hello message is invariable, so we can cache
* it.
*/
public byte[] generateGossipHello() {
if (cachedHelloMessage != null) {
return cachedHelloMessage;
}
try {
FastBuildTree root = new FastBuildTree(4);
root.putUnsafe("ver", ServiceBroker.PROTOCOL_VERSION);
root.putUnsafe("sender", nodeID);
if (useHostname) {
root.putUnsafe("host", getHostName());
} else {
root.putUnsafe("host", InetAddress.getLocalHost().getHostAddress());
}
root.putUnsafe("port", reader.getCurrentPort());
cachedHelloMessage = serialize(PACKET_GOSSIP_HELLO_ID, root);
} catch (Exception error) {
throw new RuntimeException("Unable to create HELLO message!", error);
}
return cachedHelloMessage;
}
use of services.moleculer.util.FastBuildTree in project moleculer-java by moleculer-java.
the class EventbusTest method putIncomingMessage.
protected void putIncomingMessage(String name, boolean broadcast, Groups groups, Tree payload) throws Exception {
FastBuildTree msg = new FastBuildTree(6);
msg.putUnsafe("ver", ServiceBroker.PROTOCOL_VERSION);
msg.putUnsafe("sender", "node5");
msg.putUnsafe("event", name);
msg.putUnsafe("broadcast", broadcast);
if (groups != null) {
String[] array = groups.groups();
if (array != null && array.length > 0) {
msg.putUnsafe("groups", array);
}
}
if (payload != null) {
msg.putUnsafe("data", payload);
}
tr.received(tr.eventChannel, msg);
}
use of services.moleculer.util.FastBuildTree in project moleculer-java by moleculer-java.
the class TcpTransporter method unableToSend.
// --- CONNECTION ERROR ---
public void unableToSend(String nodeID, LinkedList<byte[]> packets, Throwable cause) {
if (nodeID != null) {
executor.execute(() -> {
// Debug
if (debug) {
logger.warn("Unable to send message to \"" + nodeID + "\".", cause);
}
// Mark endpoint as offline
NodeDescriptor node = nodes.get(nodeID);
boolean disconnected = false;
if (node != null) {
node.writeLock.lock();
try {
if (node != null && node.markAsOffline()) {
// Remove actions and listeners
registry.removeActions(nodeID);
eventbus.removeListeners(nodeID);
writer.close(node.nodeID);
disconnected = true;
}
} catch (Exception error) {
logger.warn("Unable to turn off node!", error);
} finally {
node.writeLock.unlock();
}
}
if (node != null && disconnected) {
// Notify listeners (unexpected disconnection)
logger.info("Node \"" + nodeID + "\" disconnected.");
broadcastNodeDisconnected(node.info, true);
}
// Send error back to the source
if (packets != null) {
FastBuildTree errorMap = null;
if (cause != null) {
errorMap = new FastBuildTree(2);
// Add message
errorMap.putUnsafe("message", cause.getMessage());
// Add trace
StringWriter sw = new StringWriter(128);
PrintWriter pw = new PrintWriter(sw);
cause.printStackTrace(pw);
errorMap.putUnsafe("trace", sw.toString());
}
for (byte[] packet : packets) {
try {
// Remove header
if (packet != null && packet.length > 6) {
byte[] copy = new byte[packet.length - 6];
System.arraycopy(packet, 6, copy, 0, copy.length);
// Deserialize packet
Tree message = serializer.read(copy);
// Get request's unique ID
String id = message.get("id", (String) null);
if (id == null || id.isEmpty()) {
// Not a request
return;
}
// Create response message
FastBuildTree response = new FastBuildTree(6);
response.putUnsafe("id", id);
response.putUnsafe("ver", ServiceBroker.PROTOCOL_VERSION);
response.putUnsafe("sender", nodeID);
response.putUnsafe("success", false);
response.putUnsafe("data", (String) null);
if (errorMap != null) {
response.putUnsafe("error", errorMap);
}
registry.receiveResponse(response);
}
} catch (Exception error) {
logger.warn("Unable to handle error!", error);
}
}
}
});
}
}
Aggregations