/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.net.shh;
import org.apache.commons.lang3.tuple.Pair;
import org.ethereum.config.NoAutoscan;
import org.ethereum.facade.Ethereum;
import org.ethereum.facade.EthereumFactory;
import org.ethereum.listener.EthereumListenerAdapter;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.p2p.HelloMessage;
import org.ethereum.net.rlpx.Node;
import org.ethereum.net.server.Channel;
import org.junit.Ignore;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* This is not a JUnit test but rather a long running standalone test for messages exchange with another peer.
* To start it another peer with JSON PRC API should be started.
* E.g. the following is the cmd for starting up C++ eth:
*
* > eth --no-bootstrap --no-discovery --listen 10003 --shh --json-rpc
*
* If the eth is running on a remote host:port the appropriate constants in the test need to be updated
*
* Created by Anton Nashatyrev on 05.10.2015.
*/
@Ignore
public class ShhLongRun extends Thread {
private static URL remoteJsonRpc;
@Test
public void test() throws Exception {
// remoteJsonRpc = new URL("http://whisper-1.ether.camp:8545");
// Node node = new Node("enode://52994910050f13cbd7848f02709f2f5ebccc363f13dafc4ec201e405e2f143ebc9c440935b3217073f6ec47f613220e0bc6b7b34274b7d2de125b82a2acd34ee" +
// "@whisper-1.ether.camp:30303");
remoteJsonRpc = new URL("http://localhost:8545");
Node node = new Node("enode://6ed738b650ac2b771838506172447dc683b7e9dae7b91d699a48a0f94651b1a0d2e2ef01c6fffa22f762aaa553286047f0b0bb39f2e3a24b2a18fe1b9637dcbe" +
"@localhost:10003");
Ethereum ethereum = EthereumFactory.createEthereum(Config.class);
ethereum.connect(
node.getHost(),
node.getPort(),
Hex.toHexString(node.getId()));
Thread.sleep(1000000000);
}
public static void main(String[] args) throws Exception {
new ShhLongRun().test();
}
@Configuration
@NoAutoscan
public static class Config {
@Bean
public TestComponent testBean() {
return new TestComponent();
}
}
@Component
@NoAutoscan
public static class TestComponent extends Thread {
@Autowired
WorldManager worldManager;
@Autowired
Ethereum ethereum;
@Autowired
Whisper whisper;
Whisper remoteWhisper;
public TestComponent() {
}
@PostConstruct
void init() {
System.out.println("========= init");
worldManager.addListener(new EthereumListenerAdapter() {
@Override
public void onHandShakePeer(Channel channel, HelloMessage helloMessage) {
System.out.println("========= onHandShakePeer");
if (!isAlive()) {
start();
}
}
});
}
static class MessageMatcher extends MessageWatcher {
List<Pair<Date, WhisperMessage>> awaitedMsgs = new ArrayList<>();
public MessageMatcher(String to, String from, Topic[] topics) {
super(to, from, topics);
}
@Override
protected synchronized void newMessage(WhisperMessage msg) {
System.out.println("=== Msg received: " + msg);
for (Pair<Date, WhisperMessage> awaitedMsg : awaitedMsgs) {
if (Arrays.equals(msg.getPayload(), awaitedMsg.getRight().getPayload())) {
if (!match(msg, awaitedMsg.getRight())) {
throw new RuntimeException("Messages not matched: \n" + awaitedMsg + "\n" + msg);
} else {
awaitedMsgs.remove(awaitedMsg);
break;
}
}
}
checkForMissingMessages();
}
private boolean equal(Object o1, Object o2) {
if (o1 == null) return o2 == null;
return o1.equals(o2);
}
protected boolean match(WhisperMessage m1, WhisperMessage m2) {
if (!Arrays.equals(m1.getPayload(), m2.getPayload())) return false;
if (!equal(m1.getFrom(), m2.getFrom())) return false;
if (!equal(m1.getTo(), m2.getTo())) return false;
if (m1.getTopics() != null) {
if (m1.getTopics().length != m2.getTopics().length) return false;
for (int i = 0; i < m1.getTopics().length; i++) {
if (!m1.getTopics()[i].equals(m2.getTopics()[i])) return false;
}
} else if (m2.getTopics() != null) return false;
return true;
}
public synchronized void waitForMessage(WhisperMessage msg) {
checkForMissingMessages();
awaitedMsgs.add(Pair.of(new Date(), msg));
}
private void checkForMissingMessages() {
for (Pair<Date, WhisperMessage> msg : awaitedMsgs) {
if (System.currentTimeMillis() > msg.getLeft().getTime() + 10 * 1000) {
throw new RuntimeException("Message was not delivered: " + msg);
}
}
}
}
@Override
public void run() {
try {
remoteWhisper = new JsonRpcWhisper(remoteJsonRpc);
Whisper whisper = this.whisper;
// Whisper whisper = new JsonRpcWhisper(remoteJsonRpc1);
System.out.println("========= Waiting for SHH init");
Thread.sleep(1 * 1000);
System.out.println("========= Running");
String localKey1 = whisper.newIdentity();
String localKey2 = whisper.newIdentity();
String remoteKey1 = remoteWhisper.newIdentity();
String remoteKey2 = remoteWhisper.newIdentity();
String localTopic = "LocalTopic";
String remoteTopic = "RemoteTopic";
MessageMatcher localMatcherBroad = new MessageMatcher(null, null, Topic.createTopics(remoteTopic));
MessageMatcher remoteMatcherBroad = new MessageMatcher(null, null, Topic.createTopics(localTopic));
MessageMatcher localMatcherTo = new MessageMatcher(localKey1, null, null);
MessageMatcher localMatcherToFrom = new MessageMatcher(localKey2, remoteKey2, null);
MessageMatcher remoteMatcherTo = new MessageMatcher(remoteKey1, null, Topic.createTopics("aaa"));
MessageMatcher remoteMatcherToFrom = new MessageMatcher(remoteKey2, localKey2, Topic.createTopics("aaa"));
whisper.watch(localMatcherBroad);
whisper.watch(localMatcherTo);
whisper.watch(localMatcherToFrom);
remoteWhisper.watch(remoteMatcherBroad);
remoteWhisper.watch(remoteMatcherTo);
remoteWhisper.watch(remoteMatcherToFrom);
int cnt = 0;
while (true) {
{
WhisperMessage msg = new WhisperMessage()
.setPayload("local-" + cnt)
.setTopics(Topic.createTopics(localTopic));
remoteMatcherBroad.waitForMessage(msg);
whisper.send(msg.getPayload(), msg.getTopics());
}
{
WhisperMessage msg = new WhisperMessage()
.setPayload("remote-" + cnt)
.setTopics(Topic.createTopics(remoteTopic));
localMatcherBroad.waitForMessage(msg);
remoteWhisper.send(msg.getPayload(), msg.getTopics());
}
{
WhisperMessage msg = new WhisperMessage()
.setPayload("local-to-" + cnt)
.setTo(remoteKey1)
.setTopics(Topic.createTopics("aaa"));
remoteMatcherTo.waitForMessage(msg);
whisper.send(msg.getTo(), msg.getPayload(), msg.getTopics());
}
{
WhisperMessage msg = new WhisperMessage()
.setPayload("remote-to-" + cnt)
.setTo(localKey1);
localMatcherTo.waitForMessage(msg);
remoteWhisper.send(msg.getTo(), msg.getPayload(), Topic.createTopics());
}
{
WhisperMessage msg = new WhisperMessage()
.setPayload("local-to-from-" + cnt)
.setTo(remoteKey2)
.setFrom(localKey2)
.setTopics(Topic.createTopics("aaa"));
remoteMatcherToFrom.waitForMessage(msg);
whisper.send(msg.getFrom(), msg.getTo(), msg.getPayload(), msg.getTopics());
}
{
WhisperMessage msg = new WhisperMessage()
.setPayload("remote-to-from-" + cnt)
.setTo(localKey2)
.setFrom(remoteKey2);
localMatcherToFrom.waitForMessage(msg);
remoteWhisper.send(msg.getFrom(), msg.getTo(), msg.getPayload(), msg.getTopics());
}
Thread.sleep(1000);
cnt++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}