From 8b79cd4cbe10d8a2836c6721ececd518b55e4ec3 Mon Sep 17 00:00:00 2001
From: David Bohn <david@cancrisoft.net>
Date: Wed, 15 Jun 2016 16:22:47 +0200
Subject: [PATCH] Made network interface for remote selectable

---
 src/main/java/fucoin/MainRemote.java          | 92 +++++++++++++++----
 .../setup/SelectableNetworkInterface.java     | 36 ++++++++
 src/main/resources/application.conf           |  1 +
 3 files changed, 110 insertions(+), 19 deletions(-)
 create mode 100644 src/main/java/fucoin/setup/SelectableNetworkInterface.java

diff --git a/src/main/java/fucoin/MainRemote.java b/src/main/java/fucoin/MainRemote.java
index 2919875..e148dc8 100644
--- a/src/main/java/fucoin/MainRemote.java
+++ b/src/main/java/fucoin/MainRemote.java
@@ -3,22 +3,28 @@ package fucoin;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.ActorSystem;
+import akka.japi.Pair;
 import akka.util.Timeout;
 import com.typesafe.config.Config;
 import com.typesafe.config.ConfigFactory;
+import fucoin.setup.SelectableNetworkInterface;
 import fucoin.wallet.WalletImpl;
 import scala.concurrent.Await;
+import scala.concurrent.duration.FiniteDuration;
 
 import javax.swing.*;
+import java.awt.*;
 import java.io.File;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.net.*;
+import java.util.*;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 public class MainRemote {
 
-    private static JTextField walletNameField = new JTextField(5);
-    private static JTextField pathField = new JTextField(5);
+    private static JTextField walletNameField = new JTextField(10);
+    private static JTextField pathField = new JTextField(10);
+    private static JComboBox<SelectableNetworkInterface> hostnameField = new JComboBox<>();
 
     public static void main(String[] args) throws InterruptedException {
 
@@ -43,7 +49,7 @@ public class MainRemote {
         //Init System Actor System
         ActorSystem system = ActorSystem.create("Remote", ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname).withFallback(config));
 
-        JPanel dialogPanel = createDialogPanel();
+        JPanel dialogPanel = createDialogPanel(hostname);
 
         Timeout timeout = new Timeout(5, TimeUnit.SECONDS);
         ActorRef preknownNeighbour = null;
@@ -55,20 +61,35 @@ public class MainRemote {
 
             int result = JOptionPane.showConfirmDialog(null, dialogPanel, "Connect to wallet network", JOptionPane.OK_CANCEL_OPTION);
 
-            if (result == JOptionPane.OK_OPTION) {
-                walletName = walletNameField.getText();
-                path = pathField.getText();
+            // terminate if user clicked cancel
+            if (result == JOptionPane.CANCEL_OPTION) {
+                if (system != null) {
+                    system.terminate();
+                }
+                return;
             }
 
-            // check input
-            if(result == JOptionPane.OK_OPTION && (path.equals("") || walletName.equals(""))){
-                continue;
+            SelectableNetworkInterface selectedHostname = (SelectableNetworkInterface) hostnameField.getSelectedItem();
+
+            if (!selectedHostname.getHostName().equals(hostname)) {
+                if (system != null) {
+                    try {
+                        Await.result(system.terminate(), new FiniteDuration(5, TimeUnit.SECONDS));
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+
+                hostname = selectedHostname.getHostName();
+                system = ActorSystem.create("Remote", ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname).withFallback(config));
             }
 
-            // terminate if user clicked cancel
-            if (result == JOptionPane.CANCEL_OPTION) {
-                system.terminate();
-                return;
+            walletName = walletNameField.getText();
+            path = pathField.getText();
+
+            // check input
+            if (path.equals("") || walletName.equals("")) {
+                continue;
             }
 
             // resolve the given address
@@ -86,13 +107,46 @@ public class MainRemote {
 
     }
 
-    private static JPanel createDialogPanel() {
+    private static JPanel createDialogPanel(String defaultHostname) {
         JPanel dialogPanel = new JPanel();
-        dialogPanel.setLayout(new BoxLayout(dialogPanel, BoxLayout.PAGE_AXIS));
-        dialogPanel.add(new JLabel("Pick your wallet name: "));
+        dialogPanel.setLayout(new GridLayout(3, 1));
+        JLabel walletLabel = new JLabel("Pick your wallet name: ", SwingConstants.LEFT);
+        dialogPanel.add(walletLabel);
         dialogPanel.add(walletNameField);
-        dialogPanel.add(new JLabel("Enter a neighbour node address: "));
+        dialogPanel.add(new JLabel("Enter a neighbour node address: ", SwingConstants.LEFT));
         dialogPanel.add(pathField);
+        dialogPanel.add(new JLabel("Select your reachable IP address: ", SwingConstants.LEFT));
+
+        List<SelectableNetworkInterface> interfaces = fetchNetworkInterfaces();
+
+        for (SelectableNetworkInterface netint : interfaces) {
+            hostnameField.addItem(netint);
+        }
+
+        hostnameField.setSelectedItem(new SelectableNetworkInterface(defaultHostname, "default"));
+        dialogPanel.add(hostnameField);
         return dialogPanel;
     }
+
+    private static List<SelectableNetworkInterface> fetchNetworkInterfaces() {
+        List<SelectableNetworkInterface> map = new ArrayList<>();
+
+        try {
+            Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
+
+            for (NetworkInterface networkInterface : Collections.list(nets)) {
+                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
+                // To ease the setup, currently only IPv4 addresses are supported
+                Optional<InetAddress> picked = Collections.list(inetAddresses).stream().filter(inetAddress -> !(inetAddress instanceof Inet6Address)).findFirst();
+                if (picked.isPresent()) {
+                    String hostAddress = picked.get().getHostAddress();
+                    map.add(new SelectableNetworkInterface(hostAddress, networkInterface.getDisplayName()));
+                }
+            }
+        } catch (SocketException e) {
+            e.printStackTrace();
+        }
+
+        return map;
+    }
 }
diff --git a/src/main/java/fucoin/setup/SelectableNetworkInterface.java b/src/main/java/fucoin/setup/SelectableNetworkInterface.java
new file mode 100644
index 0000000..0e023c0
--- /dev/null
+++ b/src/main/java/fucoin/setup/SelectableNetworkInterface.java
@@ -0,0 +1,36 @@
+package fucoin.setup;
+
+/**
+ * @author davidbohn
+ */
+public class SelectableNetworkInterface {
+
+    String hostName;
+    String interfaceName;
+
+    public SelectableNetworkInterface(String hostName, String interfaceName) {
+        this.hostName = hostName;
+        this.interfaceName = interfaceName;
+    }
+
+    public String getHostName() {
+        return hostName;
+    }
+
+    public String getInterfaceName() {
+        return interfaceName;
+    }
+
+    @Override
+    public String toString() {
+        return getInterfaceName() + " (" + getHostName() + ")";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof SelectableNetworkInterface) {
+            return ((SelectableNetworkInterface) obj).getHostName().equals(this.getHostName());
+        }
+        return super.equals(obj);
+    }
+}
diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf
index b264199..b2e7193 100644
--- a/src/main/resources/application.conf
+++ b/src/main/resources/application.conf
@@ -2,6 +2,7 @@ akka {
 
   actor {
     provider = "akka.remote.RemoteActorRefProvider"
+    warn-about-java-serializer-usage = false
   }
 
   remote {
-- 
GitLab