diff --git a/README.md b/README.md
index ff6dedeb54..36764bb759 100644
--- a/README.md
+++ b/README.md
@@ -21,11 +21,13 @@ git clone --recursive git://github.com/bitsquare/bitsquare
* Offer fee payment with a OP_RETURN tx and fees to miners
* Pay in to MS fund
* Payout from MS fund
+* TomP2P as messaging lib integrated and basic use cases in msg screen implemented: orderbook, add order, remove order, find peer, chat with peer
### Next steps:
+* Implement messaging with TomP2P for registration, orderbook and payment process
* Arbitrator integration
-* Messaging system
* Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer)
+* Verify registration and fee payments tx and get them from the blockchain
* ...
diff --git a/TODO.txt b/TODO.txt
index d7537c35f8..5e55bbfa05 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,5 +1,4 @@
- arbitration integration
-- Messaging!
- settings
low prio:
diff --git a/pom.xml b/pom.xml
index fbf83c9527..6ca28ffb93 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,7 +50,7 @@
bitcoinj-release
-
+
http://distribution.bitcoinj.googlecode.com/git/releases
@@ -59,6 +59,12 @@
http://mvn-adamgent.googlecode.com/svn/maven/release
Adam Gent Maven Repository
+
+
+ tomp2p.net
+ http://tomp2p.net/dev/mvn/
+
+
@@ -106,13 +112,13 @@
4.11
test
-
+
org.slf4j
slf4j-api
@@ -170,6 +176,12 @@
1.3
+
+ net.tomp2p
+ TomP2P
+ 4.4
+
+
diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java
index 113cd712e8..436eee24f3 100644
--- a/src/main/java/io/bitsquare/BitSquare.java
+++ b/src/main/java/io/bitsquare/BitSquare.java
@@ -9,6 +9,7 @@ import io.bitsquare.btc.WalletFacade;
import io.bitsquare.di.BitSquareModule;
import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.util.Localisation;
+import io.bitsquare.msg.MessageFacade;
import io.bitsquare.settings.Settings;
import io.bitsquare.storage.Storage;
import io.bitsquare.user.Arbitrator;
@@ -28,9 +29,15 @@ public class BitSquare extends Application
{
private static final Logger log = LoggerFactory.getLogger(BitSquare.class);
private WalletFacade walletFacade;
+ private MessageFacade messageFacade;
public static void main(String[] args)
{
+ if (args.length > 0)
+ WalletFacade.WALLET_PREFIX = args[0];
+ else
+ WalletFacade.WALLET_PREFIX = "bitsquare";
+
launch(args);
}
@@ -39,6 +46,7 @@ public class BitSquare extends Application
{
final Injector injector = Guice.createInjector(new BitSquareModule());
walletFacade = injector.getInstance(WalletFacade.class);
+ messageFacade = injector.getInstance(MessageFacade.class);
// apply stored data
final User user = injector.getInstance(User.class);
@@ -51,7 +59,7 @@ public class BitSquare extends Application
settings.updateFromStorage((Settings) storage.read(settings.getClass().getName()));
- stage.setTitle("BitSquare");
+ stage.setTitle("BitSquare (" + WalletFacade.WALLET_PREFIX + ")");
GuiceFXMLLoader.setInjector(injector);
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource("/io/bitsquare/gui/MainView.fxml"), Localisation.getResourceBundle());
@@ -75,6 +83,7 @@ public class BitSquare extends Application
public void stop() throws Exception
{
walletFacade.shutDown();
+ messageFacade.shutDown();
super.stop();
}
diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java
index 4f56a96dfd..08f02079a1 100644
--- a/src/main/java/io/bitsquare/btc/WalletFacade.java
+++ b/src/main/java/io/bitsquare/btc/WalletFacade.java
@@ -36,11 +36,13 @@ public class WalletFacade implements WalletEventListener
public static final String MAIN_NET = "MAIN_NET";
public static final String TEST_NET = "TEST_NET";
- // for testing trade process between offerer and taker
- //public static final String WALLET_PREFIX = "offerer"; // offerer
- public static final String WALLET_PREFIX = "taker"; // offerer
+ public static String WALLET_PREFIX;
- //public static final String WALLET_PREFIX = "bitsquare";
+ // for testing trade process between offerer and taker
+ //public static String WALLET_PREFIX = "offerer"; // offerer
+ //public static String WALLET_PREFIX = "taker"; // offerer
+
+ //public static String WALLET_PREFIX = "bitsquare";
private static final Logger log = LoggerFactory.getLogger(WalletFacade.class);
@@ -105,14 +107,11 @@ public class WalletFacade implements WalletEventListener
wallet = walletAppKit.wallet();
- // Don't make the user wait for confirmations for now, as the intention is they're sending it their own money!
- wallet.allowSpendingUnconfirmedTransactions();
+ //wallet.allowSpendingUnconfirmedTransactions();
walletAppKit.peerGroup().setMaxConnections(20);
wallet.addEventListener(this);
- log.info(wallet.toString());
-
// testTradeProcessDepositTx();
// testTradeProcessPayOutTx();
}
diff --git a/src/main/java/io/bitsquare/gui/ChildController.java b/src/main/java/io/bitsquare/gui/ChildController.java
index 2d44b2fd25..03a20c98db 100644
--- a/src/main/java/io/bitsquare/gui/ChildController.java
+++ b/src/main/java/io/bitsquare/gui/ChildController.java
@@ -3,4 +3,6 @@ package io.bitsquare.gui;
public interface ChildController
{
void setNavigationController(NavigationController navigationController);
+
+ void cleanup();
}
diff --git a/src/main/java/io/bitsquare/gui/MainController.java b/src/main/java/io/bitsquare/gui/MainController.java
index 675f6ea63b..423d9ef3a8 100644
--- a/src/main/java/io/bitsquare/gui/MainController.java
+++ b/src/main/java/io/bitsquare/gui/MainController.java
@@ -10,6 +10,7 @@ import io.bitsquare.gui.market.MarketController;
import io.bitsquare.gui.setup.SetupController;
import io.bitsquare.gui.util.Icons;
import io.bitsquare.gui.util.Localisation;
+import io.bitsquare.msg.MessageFacade;
import io.bitsquare.trade.Direction;
import io.bitsquare.user.User;
import javafx.application.Platform;
@@ -39,6 +40,7 @@ public class MainController implements Initializable, NavigationController, Wall
private User user;
private WalletFacade walletFacade;
+ private MessageFacade messageFacade;
private ChildController childController;
private ToggleGroup toggleGroup;
private ToggleButton prevToggleButton;
@@ -62,10 +64,11 @@ public class MainController implements Initializable, NavigationController, Wall
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
- public MainController(User user, WalletFacade walletFacade)
+ public MainController(User user, WalletFacade walletFacade, MessageFacade messageFacade)
{
this.user = user;
this.walletFacade = walletFacade;
+ this.messageFacade = messageFacade;
}
@@ -80,6 +83,8 @@ public class MainController implements Initializable, NavigationController, Wall
networkSyncPane.setSpacing(10);
networkSyncPane.setPrefHeight(20);
+ messageFacade.init();
+
walletFacade.addDownloadListener(this);
walletFacade.initWallet();
@@ -116,10 +121,8 @@ public class MainController implements Initializable, NavigationController, Wall
return null;
}
- if (childController instanceof MarketController)
- {
- ((MarketController) childController).cleanup();
- }
+ if (childController != null)
+ childController.cleanup();
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(fxmlView), Localisation.getResourceBundle());
try
@@ -184,14 +187,15 @@ public class MainController implements Initializable, NavigationController, Wall
addNavButton(leftNavPane, "Orders", Icons.ORDERS, Icons.ORDERS, NavigationController.ORDERS);
addNavButton(leftNavPane, "History", Icons.HISTORY, Icons.HISTORY, NavigationController.HISTORY);
addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, NavigationController.FUNDS);
- addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG);
+ ToggleButton msgButton = addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG);
addBalanceInfo(rightNavPane);
addAccountComboBox(rightNavPane);
addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, NavigationController.SETTINGS);
- sellButton.fire();
+ //sellButton.fire();
//homeButton.fire();
+ msgButton.fire();
}
private ToggleButton addNavButton(Pane parent, String title, String iconId, String iconIdActivated, String navTarget)
diff --git a/src/main/java/io/bitsquare/gui/funds/FundsController.java b/src/main/java/io/bitsquare/gui/funds/FundsController.java
index 850591e6d0..b61d935962 100644
--- a/src/main/java/io/bitsquare/gui/funds/FundsController.java
+++ b/src/main/java/io/bitsquare/gui/funds/FundsController.java
@@ -66,6 +66,12 @@ public class FundsController implements Initializable, ChildController
balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false));
}
+ @Override
+ public void cleanup()
+ {
+
+ }
+
}
diff --git a/src/main/java/io/bitsquare/gui/history/HistoryController.java b/src/main/java/io/bitsquare/gui/history/HistoryController.java
index f30f2da28f..3f90c155f4 100644
--- a/src/main/java/io/bitsquare/gui/history/HistoryController.java
+++ b/src/main/java/io/bitsquare/gui/history/HistoryController.java
@@ -24,5 +24,11 @@ public class HistoryController implements Initializable, ChildController
{
this.navigationController = navigationController;
}
+
+ @Override
+ public void cleanup()
+ {
+
+ }
}
diff --git a/src/main/java/io/bitsquare/gui/home/HomeController.java b/src/main/java/io/bitsquare/gui/home/HomeController.java
index 2d91fd5754..9d557c51a9 100644
--- a/src/main/java/io/bitsquare/gui/home/HomeController.java
+++ b/src/main/java/io/bitsquare/gui/home/HomeController.java
@@ -28,5 +28,11 @@ public class HomeController implements Initializable, ChildController
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+
+ }
+
}
diff --git a/src/main/java/io/bitsquare/gui/market/MarketController.java b/src/main/java/io/bitsquare/gui/market/MarketController.java
index 3c69dab6cb..0360c82c3c 100644
--- a/src/main/java/io/bitsquare/gui/market/MarketController.java
+++ b/src/main/java/io/bitsquare/gui/market/MarketController.java
@@ -93,11 +93,7 @@ public class MarketController implements Initializable, NavigationController, Ch
this.navigationController = navigationController;
}
-
- ///////////////////////////////////////////////////////////////////////////////////////////
- // Public methods
- ///////////////////////////////////////////////////////////////////////////////////////////
-
+ @Override
public void cleanup()
{
if (orderBookController != null)
diff --git a/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java b/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java
index 39ea036a67..354612817c 100644
--- a/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java
+++ b/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java
@@ -114,6 +114,12 @@ public class CreateOfferController implements Initializable, ChildController, Wa
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: WalletFacade.WalletListener
diff --git a/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java b/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java
index 4e687d5431..2a9cc05f62 100644
--- a/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java
+++ b/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java
@@ -138,6 +138,15 @@ public class OrderBookController implements Initializable, ChildController
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+ orderBookTable.setItems(null);
+ orderBookTable.getSortOrder().clear();
+ offerList.comparatorProperty().unbind();
+ }
+
+
public void setDirection(Direction direction)
{
orderBookTable.getSelectionModel().clearSelection();
@@ -145,12 +154,6 @@ public class OrderBookController implements Initializable, ChildController
orderBookFilter.setDirection(direction);
}
- public void cleanup()
- {
- orderBookTable.setItems(null);
- orderBookTable.getSortOrder().clear();
- offerList.comparatorProperty().unbind();
- }
private void openTradeTab(OrderBookListItem orderBookListItem)
{
diff --git a/src/main/java/io/bitsquare/gui/market/trade/TradeController.java b/src/main/java/io/bitsquare/gui/market/trade/TradeController.java
index 630fcdbb91..cbf586e6fb 100644
--- a/src/main/java/io/bitsquare/gui/market/trade/TradeController.java
+++ b/src/main/java/io/bitsquare/gui/market/trade/TradeController.java
@@ -122,6 +122,12 @@ public class TradeController implements Initializable, ChildController, WalletFa
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: WalletFacade.WalletListener
diff --git a/src/main/java/io/bitsquare/gui/msg/MockDelay.java b/src/main/java/io/bitsquare/gui/msg/MockDelay.java
deleted file mode 100644
index 61af376bec..0000000000
--- a/src/main/java/io/bitsquare/gui/msg/MockDelay.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.bitsquare.gui.msg;
-
-
-import java.util.concurrent.*;
-
-public class MockDelay
-{
- public String waitForMsg(String expectedMsg)
- {
- ExecutorService executor = Executors.newSingleThreadExecutor();
- Future future = executor.submit(new Task(expectedMsg));
- // max timeout 5 sec
- try
- {
- return future.get(5, TimeUnit.SECONDS);
- } catch (InterruptedException | TimeoutException | ExecutionException e)
- {
- e.printStackTrace();
- }
- executor.shutdownNow();
- return null;
- }
-}
-
-class Task implements Callable
-{
- private String expectedMsg;
-
- Task(String expectedMsg)
- {
- this.expectedMsg = expectedMsg;
- }
-
- @Override
- public String call() throws Exception
- {
- Thread.sleep(1000); // 1 seconds pause
- return expectedMsg;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/msg/MsgController.java b/src/main/java/io/bitsquare/gui/msg/MsgController.java
index 46fdf1f79c..9669fa1491 100644
--- a/src/main/java/io/bitsquare/gui/msg/MsgController.java
+++ b/src/main/java/io/bitsquare/gui/msg/MsgController.java
@@ -1,26 +1,346 @@
package io.bitsquare.gui.msg;
+import com.google.inject.Inject;
+import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
+import io.bitsquare.msg.MessageFacade;
+import io.bitsquare.msg.MessageListener;
+import javafx.beans.property.ReadOnlyObjectWrapper;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
import javafx.fxml.Initializable;
+import javafx.scene.control.*;
+import javafx.util.Callback;
+import net.tomp2p.peers.Number160;
+import net.tomp2p.storage.Data;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.IOException;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
import java.util.ResourceBundle;
-public class MsgController implements Initializable, ChildController
+public class MsgController implements Initializable, ChildController, MessageListener
{
- private NavigationController navigationController;
+ private static final Logger log = LoggerFactory.getLogger(MsgController.class);
+
+ private MessageFacade messageFacade;
+ private String selectedCurrency;
+ private ObservableList offerList = FXCollections.observableArrayList();
+ private int selectedIndex;
+ private String myID, otherID;
+ private boolean pingPending;
+
+ @FXML
+ public ComboBox currencyComboBox;
+ @FXML
+ public Button sendButton;
+ @FXML
+ public TextArea chatTextArea;
+ @FXML
+ public TextField chatInputField, peerIDTextField, currencyTextField, offerDataTextField;
+ @FXML
+ public TableView offerTable;
+ @FXML
+ public TableColumn connectToPeerColumn, removeOfferColumn, offerColumn;
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Constructor
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Inject
+ public MsgController(MessageFacade messageFacade)
+ {
+ this.messageFacade = messageFacade;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Interface implementation: Initializable
+ ///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL url, ResourceBundle rb)
{
+ myID = WalletFacade.WALLET_PREFIX;
+ otherID = WalletFacade.WALLET_PREFIX.equals("taker") ? "offerer" : "taker";
+ messageFacade.addMessageListener(this);
+
+ peerIDTextField.setText(myID);
+ currencyTextField.setText("EUR");
+ offerDataTextField.setText(myID + " serialized offer object");
+
+ selectedCurrency = currencyTextField.getText();
+
+ currencyComboBox.setItems(FXCollections.observableArrayList(new ArrayList<>(Arrays.asList("EUR", "USD", "CHF"))));
+ currencyComboBox.getSelectionModel().select(0);
+
+ setupConnectToPeerOfferColumn();
+ setupRemoveOfferColumn();
+ offerTable.setItems(offerList);
+ offerTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
}
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Interface implementation: MessageListener
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void onMessage(Object message)
+ {
+ sendButton.setDisable(!messageFacade.isOtherPeerDefined());
+
+ if (message instanceof String)
+ chatTextArea.appendText("\n" + otherID + ": " + message);
+ }
+
+ @Override
+ public void onPing()
+ {
+ sendChatMsg(MessageFacade.PONG);
+ }
+
+ @Override
+ public void onOfferPublished(boolean success)
+ {
+ if (success)
+ getOffers();
+ else
+ log.warn("onOfferPublished returned false");
+ }
+
+ @Override
+ public void onOffersReceived(Map dataMap, boolean success)
+ {
+ if (success && dataMap != null)
+ {
+ offerList.clear();
+ for (Data offerData : dataMap.values())
+ {
+ try
+ {
+ Object offerDataObject = offerData.getObject();
+ if (offerDataObject instanceof OfferListItem && offerDataObject != null)
+ offerList.add((OfferListItem) offerDataObject);
+ } catch (ClassNotFoundException | IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ else
+ {
+ offerList.clear();
+ }
+ }
+
+
+ @Override
+ public void onOfferRemoved(boolean success)
+ {
+ if (success)
+ getOffers();
+ else
+ log.warn("onOfferRemoved failed");
+ }
+
+ @Override
+ public void onResponseFromSend(Object response)
+ {
+ String msg = (response instanceof String) ? (String) response : null;
+ if (msg != null)
+ {
+ chatTextArea.appendText("\n" + otherID + ": " + msg);
+ offerTable.getSelectionModel().select(selectedIndex);
+ }
+ }
+
+ @Override
+ public void onSendFailed()
+ {
+ offerTable.getSelectionModel().clearSelection();
+ }
+
+ @Override
+ public void onPeerFound()
+ {
+ sendButton.setDisable(!messageFacade.isOtherPeerDefined());
+ if (pingPending)
+ sendChatMsg(MessageFacade.PING);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Interface implementation: ChildController
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
@Override
public void setNavigationController(NavigationController navigationController)
{
- this.navigationController = navigationController;
+ }
+
+ @Override
+ public void cleanup()
+ {
+ messageFacade.removeMessageListener(this);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // GUI Event handlers
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @FXML
+ public void publishOffer(ActionEvent actionEvent)
+ {
+ OfferListItem offerListItem = new OfferListItem(offerDataTextField.getText(), messageFacade.getPubKeyAsHex(), currencyTextField.getText());
+ try
+ {
+ messageFacade.publishOffer(currencyTextField.getText(), offerListItem);
+ } catch (IOException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+ @FXML
+ public void selectCurrency(ActionEvent actionEvent)
+ {
+ selectedCurrency = currencyComboBox.getSelectionModel().getSelectedItem().toString();
+ getOffers();
+ }
+
+ @FXML
+ public void sendChatMsg(ActionEvent actionEvent)
+ {
+ sendChatMsg(chatInputField.getText());
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Private Methods
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ private void inviteForChat(OfferListItem item, int index)
+ {
+ selectedIndex = index;
+ messageFacade.findPeer(item.getPubKey());
+ pingPending = true;
+
+ }
+
+ private void sendChatMsg(String msg)
+ {
+ messageFacade.sendMessage(msg);
+
+ chatTextArea.appendText("\n" + myID + ": " + msg);
+ chatInputField.setText("");
+ }
+
+ private void getOffers()
+ {
+ messageFacade.getOffers(selectedCurrency);
+ }
+
+ private void removeOffer(OfferListItem offer)
+ {
+ try
+ {
+ messageFacade.removeOffer(currencyTextField.getText(), offer);
+ } catch (IOException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Columns
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ private void setupRemoveOfferColumn()
+ {
+ removeOfferColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
+ removeOfferColumn.setCellFactory(new Callback, TableCell>()
+ {
+ @Override
+ public TableCell call(TableColumn directionColumn)
+ {
+ return new TableCell()
+ {
+ final Button button = new Button();
+
+ {
+ button.setMinWidth(70);
+ }
+
+ @Override
+ public void updateItem(final OfferListItem item, boolean empty)
+ {
+ super.updateItem(item, empty);
+
+ if (item != null)
+ {
+ button.setText("Remove");
+ setGraphic(button);
+
+ button.setOnAction(event -> removeOffer(item));
+ }
+ else
+ {
+ setGraphic(null);
+ }
+ }
+ };
+ }
+ });
+ }
+
+ private void setupConnectToPeerOfferColumn()
+ {
+ connectToPeerColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue()));
+ connectToPeerColumn.setCellFactory(new Callback, TableCell>()
+ {
+ @Override
+ public TableCell call(TableColumn directionColumn)
+ {
+ return new TableCell()
+ {
+ final Button button = new Button();
+
+ {
+ button.setMinWidth(70);
+ }
+
+ @Override
+ public void updateItem(OfferListItem item, boolean empty)
+ {
+ super.updateItem(item, empty);
+
+ if (item != null)
+ {
+ button.setText("Chat");
+ setGraphic(button);
+
+
+ button.setOnAction(event -> inviteForChat(item, getIndex()));
+ }
+ else
+ {
+ setGraphic(null);
+ }
+ }
+ };
+ }
+ });
}
}
diff --git a/src/main/java/io/bitsquare/gui/msg/MsgView.fxml b/src/main/java/io/bitsquare/gui/msg/MsgView.fxml
index 8114fc9289..f8bf7197b2 100644
--- a/src/main/java/io/bitsquare/gui/msg/MsgView.fxml
+++ b/src/main/java/io/bitsquare/gui/msg/MsgView.fxml
@@ -1,6 +1,80 @@
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/io/bitsquare/gui/msg/OfferListItem.java b/src/main/java/io/bitsquare/gui/msg/OfferListItem.java
new file mode 100644
index 0000000000..881bf7df7f
--- /dev/null
+++ b/src/main/java/io/bitsquare/gui/msg/OfferListItem.java
@@ -0,0 +1,40 @@
+package io.bitsquare.gui.msg;
+
+import java.io.Serializable;
+
+/**
+ * Wrapper for observable properties used by orderbook table view
+ */
+public class OfferListItem implements Serializable
+{
+
+ private static final long serialVersionUID = 7914481258209700131L;
+
+ private String _offer;
+ private String pubKey;
+ private String currency;
+
+
+ public OfferListItem(String offer, String pubKey, String currency)
+ {
+ _offer = offer;
+ this.pubKey = pubKey;
+ this.currency = currency;
+
+ }
+
+ public String getOffer()
+ {
+ return _offer;
+ }
+
+ public String getPubKey()
+ {
+ return pubKey;
+ }
+
+ public String getCurrency()
+ {
+ return currency;
+ }
+}
diff --git a/src/main/java/io/bitsquare/gui/orders/OrdersController.java b/src/main/java/io/bitsquare/gui/orders/OrdersController.java
index 976c581f81..941ed671d7 100644
--- a/src/main/java/io/bitsquare/gui/orders/OrdersController.java
+++ b/src/main/java/io/bitsquare/gui/orders/OrdersController.java
@@ -26,5 +26,11 @@ public class OrdersController implements Initializable, ChildController
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+
+ }
+
}
diff --git a/src/main/java/io/bitsquare/gui/settings/SettingsController.java b/src/main/java/io/bitsquare/gui/settings/SettingsController.java
index 0873cc351e..e63a633262 100644
--- a/src/main/java/io/bitsquare/gui/settings/SettingsController.java
+++ b/src/main/java/io/bitsquare/gui/settings/SettingsController.java
@@ -39,5 +39,11 @@ public class SettingsController implements Initializable, ChildController
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+
+ }
+
}
diff --git a/src/main/java/io/bitsquare/gui/setup/SetupController.java b/src/main/java/io/bitsquare/gui/setup/SetupController.java
index 82d97c1b3a..5330260240 100644
--- a/src/main/java/io/bitsquare/gui/setup/SetupController.java
+++ b/src/main/java/io/bitsquare/gui/setup/SetupController.java
@@ -18,6 +18,7 @@ import io.bitsquare.gui.util.FormBuilder;
import io.bitsquare.gui.util.Localisation;
import io.bitsquare.gui.util.Popups;
import io.bitsquare.gui.util.Verification;
+import io.bitsquare.msg.MessageFacade;
import io.bitsquare.storage.Storage;
import io.bitsquare.user.User;
import io.bitsquare.util.Utils;
@@ -43,6 +44,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
private final User user;
private final WalletFacade walletFacade;
+ private MessageFacade messageFacade;
private final Storage storage;
private final List processStepItems = new ArrayList<>();
private NavigationController navigationController;
@@ -71,10 +73,11 @@ public class SetupController implements Initializable, ChildController, WalletFa
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
- public SetupController(User user, WalletFacade walletFacade, Storage storage)
+ public SetupController(User user, WalletFacade walletFacade, MessageFacade messageFacade, Storage storage)
{
this.user = user;
this.walletFacade = walletFacade;
+ this.messageFacade = messageFacade;
this.storage = storage;
}
@@ -118,6 +121,11 @@ public class SetupController implements Initializable, ChildController, WalletFa
this.navigationController = navigationController;
}
+ @Override
+ public void cleanup()
+ {
+
+ }
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: WalletFacade.WalletListener
@@ -305,6 +313,7 @@ public class SetupController implements Initializable, ChildController, WalletFa
walletFacade.sendRegistrationTx(user.getStringifiedBankAccounts());
user.setAccountID(walletFacade.getAccountRegistrationAddress().toString());
user.setMessageID(walletFacade.getAccountRegistrationPubKey());
+ //user.setMessageID(messageFacade.getPubKey());
storage.write(user.getClass().getName(), user);
processStepBar.next();
diff --git a/src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java b/src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java
new file mode 100755
index 0000000000..5dcdd6d527
--- /dev/null
+++ b/src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java
@@ -0,0 +1,24 @@
+package io.bitsquare.msg;
+
+import net.tomp2p.p2p.Peer;
+import net.tomp2p.p2p.PeerMaker;
+import net.tomp2p.peers.Number160;
+
+public class BootstrapMasterPeer
+{
+ private static Peer masterPeer = null;
+ public static Number160 ID = Number160.createHash(1);
+
+ public static void main(String[] args) throws Exception
+ {
+ INSTANCE(5000);
+ }
+
+ public static Peer INSTANCE(int port) throws Exception
+ {
+ if (masterPeer == null)
+ masterPeer = new PeerMaker(ID).setPorts(port).makeAndListen();
+
+ return masterPeer;
+ }
+}
diff --git a/src/main/java/io/bitsquare/msg/MessageFacade.java b/src/main/java/io/bitsquare/msg/MessageFacade.java
index b2e0dadc4d..ad419fe9dc 100644
--- a/src/main/java/io/bitsquare/msg/MessageFacade.java
+++ b/src/main/java/io/bitsquare/msg/MessageFacade.java
@@ -1,30 +1,398 @@
package io.bitsquare.msg;
+import com.google.bitcoin.core.Utils;
+import com.google.inject.Inject;
+import io.bitsquare.btc.WalletFacade;
+import javafx.application.Platform;
+import net.tomp2p.connection.Bindings;
+import net.tomp2p.connection.PeerConnection;
+import net.tomp2p.futures.*;
+import net.tomp2p.p2p.Peer;
+import net.tomp2p.p2p.PeerMaker;
+import net.tomp2p.peers.Number160;
+import net.tomp2p.peers.PeerAddress;
+import net.tomp2p.rpc.ObjectDataReply;
+import net.tomp2p.storage.Data;
+import net.tomp2p.storage.StorageDisk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
/**
- * That facade delivers messaging functionality from an external library -> to be defined...
- * The external library codebase must not be used outside that facade.
+ * That facade delivers messaging functionality from the TomP2P library
+ * The TomP2P library codebase shall not be used outside that facade.
* That way a change of the library will only affect that class.
*/
public class MessageFacade
{
private static final Logger log = LoggerFactory.getLogger(MessageFacade.class);
- public void broadcast(Message message)
+ public static final String PING = "ping";
+ public static final String PONG = "pong";
+ private static final int MASTER_PEER_PORT = 5000;
+ private static String MASTER_PEER_IP = "127.0.0.1";
+
+ private Peer myPeerInstance;
+ private int port;
+ private KeyPair keyPair;
+ private Peer masterPeer;
+ private PeerAddress otherPeerAddress;
+ private PeerConnection peerConnection;
+ private List messageListeners = new ArrayList<>();
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Constructor
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Inject
+ public MessageFacade()
{
- log.info(message.toString());
+ try
+ {
+ masterPeer = BootstrapMasterPeer.INSTANCE(MASTER_PEER_PORT);
+ } catch (Exception e)
+ {
+ if (masterPeer != null)
+ masterPeer.shutdown();
+ log.info("masterPeer already instantiated by another app. " + e.getMessage());
+ }
}
- public void send(Message message, String receiverPubKey)
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Public Methods
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public void init()
{
- log.info(message.toString() + "/" + receiverPubKey);
+ String keyName = WalletFacade.WALLET_PREFIX;
+ port = Bindings.MAX_PORT - Math.abs(new Random().nextInt()) % (Bindings.MAX_PORT - Bindings.MIN_DYN_PORT);
+ if (WalletFacade.WALLET_PREFIX.equals("taker"))
+ port = 4501;
+ else if (WalletFacade.WALLET_PREFIX.equals("offerer"))
+ port = 4500;
+
+ try
+ {
+ createMyPeerInstance(keyName, port);
+ setupStorage();
+ saveMyAddressToDHT();
+ setupReplyHandler();
+ } catch (IOException e)
+ {
+ shutDown();
+ log.error("Error at setup peer" + e.getMessage());
+ }
+
+ //log.info("myPeerInstance knows: " + myPeerInstance.getPeerBean().getPeerMap().getAll());
}
- public void registerListener(String listenerPubKey)
+ public void shutDown()
{
- log.info(listenerPubKey);
+ if (peerConnection != null)
+ peerConnection.close();
+
+ if (myPeerInstance != null)
+ myPeerInstance.shutdown();
+
+ if (masterPeer != null)
+ masterPeer.shutdown();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Publish offer
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ //TODO use Offer and do proper serialisation here
+ public void publishOffer(String currency, Object offerObject) throws IOException
+ {
+ Number160 locationKey = Number160.createHash(currency);
+ Data offerData = new Data(offerObject);
+ offerData.setTTLSeconds(5);
+ FutureDHT putFuture = myPeerInstance.add(locationKey).setData(offerData).start();
+ putFuture.addListener(new BaseFutureAdapter()
+ {
+ @Override
+ public void operationComplete(BaseFuture future) throws Exception
+ {
+ Platform.runLater(() -> onOfferPublished(future.isSuccess()));
+ }
+ });
+ }
+
+ private void onOfferPublished(boolean success)
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onOfferPublished(success);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Get offers
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public void getOffers(String currency)
+ {
+ Number160 locationKey = Number160.createHash(currency);
+ final FutureDHT getOffersFuture = myPeerInstance.get(locationKey).setAll().start();
+ getOffersFuture.addListener(new BaseFutureAdapter()
+ {
+ @Override
+ public void operationComplete(BaseFuture future) throws Exception
+ {
+ final Map dataMap = getOffersFuture.getDataMap();
+ Platform.runLater(() -> onOffersReceived(dataMap, future.isSuccess()));
+ }
+ });
+ }
+
+ private void onOffersReceived(Map dataMap, boolean success)
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onOffersReceived(dataMap, success);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Remove offer
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public void removeOffer(String currency, Object offerObject) throws IOException
+ {
+ Data offerData = new Data(offerObject);
+ Number160 locationKey = Number160.createHash(currency);
+ Number160 contentKey = offerData.getHash();
+ FutureDHT putFuture = myPeerInstance.remove(locationKey).setContentKey(contentKey).start();
+ putFuture.addListener(new BaseFutureAdapter()
+ {
+ @Override
+ public void operationComplete(BaseFuture future) throws Exception
+ {
+ Platform.runLater(() -> onOfferRemoved(future.isSuccess()));
+ }
+ });
+ }
+
+ private void onOfferRemoved(boolean success)
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onOfferRemoved(success);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Send message
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public boolean sendMessage(String message)
+ {
+ boolean result = false;
+ if (otherPeerAddress != null)
+ {
+ if (peerConnection != null)
+ peerConnection.close();
+
+ peerConnection = myPeerInstance.createPeerConnection(otherPeerAddress, 20);
+ if (!peerConnection.isClosed())
+ {
+ FutureResponse sendFuture = myPeerInstance.sendDirect(peerConnection).setObject(message).start();
+ sendFuture.addListener(new BaseFutureAdapter()
+ {
+ @Override
+ public void operationComplete(BaseFuture baseFuture) throws Exception
+ {
+ if (sendFuture.isSuccess())
+ {
+ final Object object = sendFuture.getObject();
+ Platform.runLater(() -> onResponseFromSend(object));
+ }
+ else
+ {
+ Platform.runLater(() -> onSendFailed());
+ }
+ }
+ }
+ );
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ private void onResponseFromSend(Object response)
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onResponseFromSend(response);
+ }
+
+ private void onSendFailed()
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onSendFailed();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Find peer
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public void findPeer(String pubKeyAsHex)
+ {
+ final FutureDHT getPeerAddressFuture = myPeerInstance.get(getPubKeyHash(pubKeyAsHex)).start();
+ getPeerAddressFuture.addListener(new BaseFutureAdapter()
+ {
+ @Override
+ public void operationComplete(BaseFuture baseFuture) throws Exception
+ {
+ final PeerAddress peerAddress = (PeerAddress) getPeerAddressFuture.getData().getObject();
+ Platform.runLater(() -> onPeerFound(peerAddress));
+ }
+ });
+ }
+
+ private void onPeerFound(PeerAddress peerAddress)
+ {
+ if (!peerAddress.equals(myPeerInstance.getPeerAddress()))
+ {
+ otherPeerAddress = peerAddress;
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onPeerFound();
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Misc
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public boolean isOtherPeerDefined()
+ {
+ return otherPeerAddress != null;
+ }
+
+ public String getPubKeyAsHex()
+ {
+ return Utils.bytesToHexString(keyPair.getPublic().getEncoded());
+ }
+
+ public PublicKey getPubKey()
+ {
+ return keyPair.getPublic();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Event Listeners
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ public void addMessageListener(MessageListener listener)
+ {
+ messageListeners.add(listener);
+ }
+
+ public void removeMessageListener(MessageListener listener)
+ {
+ messageListeners.remove(listener);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Private Methods
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ private void createMyPeerInstance(String keyName, int port) throws IOException
+ {
+ keyPair = MsgKeyUtil.getKeyPair(keyName);
+ myPeerInstance = new PeerMaker(keyPair).setPorts(port).makeAndListen();
+
+ //TODO use list of multiple master bootstrap peers
+ /*PeerAddress bootstrapServerPeerAddress = new PeerAddress(BootstrapMasterPeer.ID, new InetSocketAddress(InetAddress.getByName(MASTER_PEER_IP), port));
+ FutureBootstrap futureBootstrap = myPeerInstance.bootstrap().setPeerAddress(bootstrapServerPeerAddress).start();
+ */
+ FutureBootstrap futureBootstrap = myPeerInstance.bootstrap().setBroadcast().setPorts(MASTER_PEER_PORT).start();
+ if (futureBootstrap != null)
+ {
+ futureBootstrap.awaitUninterruptibly();
+ if (futureBootstrap.getBootstrapTo() != null)
+ {
+ PeerAddress peerAddress = futureBootstrap.getBootstrapTo().iterator().next();
+ myPeerInstance.discover().setPeerAddress(peerAddress).start().awaitUninterruptibly();
+ }
+ }
+ }
+
+ private void setupStorage() throws IOException
+ {
+ //TODO WalletFacade.WALLET_PREFIX just temp...
+ String dirPath = io.bitsquare.util.Utils.getRootDir() + "tomP2P_" + WalletFacade.WALLET_PREFIX;
+ File dirFile = new File(dirPath);
+ boolean success = true;
+ if (!dirFile.exists())
+ success = dirFile.mkdir();
+
+ if (success)
+ myPeerInstance.getPeerBean().setStorage(new StorageDisk(dirPath));
+ else
+ log.warn("Unable to create directory " + dirPath);
+ }
+
+ private void saveMyAddressToDHT() throws IOException
+ {
+ myPeerInstance.put(getPubKeyHash(getPubKeyAsHex())).setData(new Data(myPeerInstance.getPeerAddress())).start();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Incoming message handler
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ private void setupReplyHandler()
+ {
+ myPeerInstance.setObjectDataReply(new ObjectDataReply()
+ {
+ @Override
+ public Object reply(PeerAddress sender, Object request) throws Exception
+ {
+ String reply = null;
+ if (!sender.equals(myPeerInstance.getPeerAddress()))
+ {
+ otherPeerAddress = sender;
+
+ Platform.runLater(() -> onMessage(request));
+ if (request.equals(PING))
+ {
+ Platform.runLater(() -> onPing());
+ }
+ }
+ return reply;
+ }
+ });
+ }
+
+ private void onMessage(Object message)
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onMessage(message);
+ }
+
+ private void onPing()
+ {
+ for (MessageListener messageListener : messageListeners)
+ messageListener.onPing();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Utils
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ private Number160 getPubKeyHash(String pubKeyAsHex)
+ {
+ return net.tomp2p.utils.Utils.makeSHAHash(pubKeyAsHex);
}
}
diff --git a/src/main/java/io/bitsquare/msg/MessageListener.java b/src/main/java/io/bitsquare/msg/MessageListener.java
new file mode 100644
index 0000000000..d6ff7e39e0
--- /dev/null
+++ b/src/main/java/io/bitsquare/msg/MessageListener.java
@@ -0,0 +1,26 @@
+package io.bitsquare.msg;
+
+import net.tomp2p.peers.Number160;
+import net.tomp2p.storage.Data;
+
+import java.util.EventListener;
+import java.util.Map;
+
+public interface MessageListener extends EventListener
+{
+ void onMessage(Object message);
+
+ void onPing();
+
+ void onOfferPublished(boolean success);
+
+ void onSendFailed();
+
+ void onResponseFromSend(Object response);
+
+ void onPeerFound();
+
+ void onOffersReceived(Map dataMap, boolean success);
+
+ void onOfferRemoved(boolean success);
+}
diff --git a/src/main/java/io/bitsquare/msg/MsgKeyUtil.java b/src/main/java/io/bitsquare/msg/MsgKeyUtil.java
new file mode 100755
index 0000000000..30d6152501
--- /dev/null
+++ b/src/main/java/io/bitsquare/msg/MsgKeyUtil.java
@@ -0,0 +1,131 @@
+package io.bitsquare.msg;
+
+import io.bitsquare.util.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class MsgKeyUtil
+{
+ private static final Logger log = LoggerFactory.getLogger(MsgKeyUtil.class);
+ private static final String baseDir = Utils.getRootDir();
+
+ public static KeyPair getKeyPair()
+ {
+ return getKeyPair("public.key", "private.key");
+ }
+
+ public static KeyPair getKeyPair(String keyName)
+ {
+ return getKeyPair("public_" + keyName + ".key", "private_" + keyName + ".key");
+ }
+
+ public static KeyPair getKeyPair(String pubKeyPath, String privKeyPath)
+ {
+ try
+ {
+ KeyPair loadedKeyPair = loadKeyPair(pubKeyPath, privKeyPath, "DSA");
+ //System.out.println("Loaded Key Pair");
+ return loadedKeyPair;
+ } catch (Exception e)
+ {
+ try
+ {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
+
+ keyGen.initialize(1024);
+ KeyPair generatedKeyPair = keyGen.genKeyPair();
+
+ // System.out.println("Generated Key Pair");
+ dumpKeyPair(generatedKeyPair);
+ saveKeyPair(pubKeyPath, privKeyPath, generatedKeyPair);
+ return generatedKeyPair;
+ } catch (Exception e2)
+ {
+ e2.printStackTrace();
+ return null;
+ }
+ }
+ }
+
+
+ private static void dumpKeyPair(KeyPair keyPair)
+ {
+ PublicKey pub = keyPair.getPublic();
+ // System.out.println("Public Key: " + getHexString(pub.getEncoded()));
+
+ PrivateKey priv = keyPair.getPrivate();
+ // System.out.println("Private Key: " + getHexString(priv.getEncoded()));
+ }
+
+ private static String getHexString(byte[] b)
+ {
+ String result = "";
+ for (int i = 0; i < b.length; i++)
+ {
+ result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
+ }
+ return result;
+ }
+
+ public static void saveKeyPair(String pubKeyPath, String privKeyPath, KeyPair keyPair) throws IOException
+ {
+ PrivateKey privateKey = keyPair.getPrivate();
+ PublicKey publicKey = keyPair.getPublic();
+
+ // Store Public Key.
+ X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
+ publicKey.getEncoded());
+ FileOutputStream fos = new FileOutputStream(baseDir + pubKeyPath);
+ fos.write(x509EncodedKeySpec.getEncoded());
+ fos.close();
+
+ // Store Private Key.
+ PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
+ privateKey.getEncoded());
+ fos = new FileOutputStream(baseDir + privKeyPath);
+ fos.write(pkcs8EncodedKeySpec.getEncoded());
+ fos.close();
+ }
+
+
+ public static KeyPair loadKeyPair(String pubKeyPath, String privKeyPath, String algorithm)
+ throws IOException, NoSuchAlgorithmException,
+ InvalidKeySpecException
+ {
+ // Read Public Key.
+ File filePublicKey = new File(baseDir + pubKeyPath);
+ FileInputStream fis = new FileInputStream(baseDir + pubKeyPath);
+ byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
+ fis.read(encodedPublicKey);
+ fis.close();
+
+ // Read Private Key.
+ File filePrivateKey = new File(baseDir + privKeyPath);
+ fis = new FileInputStream(baseDir + privKeyPath);
+ byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
+ fis.read(encodedPrivateKey);
+ fis.close();
+
+ // Generate KeyPair.
+ KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+ X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
+ encodedPublicKey);
+ PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
+
+ PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
+ encodedPrivateKey);
+ PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
+
+ return new KeyPair(publicKey, privateKey);
+ }
+
+}
diff --git a/src/main/java/io/bitsquare/storage/Storage.java b/src/main/java/io/bitsquare/storage/Storage.java
index 0e410ae707..dbbf699a45 100644
--- a/src/main/java/io/bitsquare/storage/Storage.java
+++ b/src/main/java/io/bitsquare/storage/Storage.java
@@ -1,5 +1,6 @@
package io.bitsquare.storage;
+import io.bitsquare.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,7 +27,7 @@ public class Storage
public Storage()
{
- storageFile = Storage.class.getProtectionDomain().getCodeSource().getLocation().getFile() + "/" + preferencesFileName;
+ storageFile = Utils.getRootDir() + preferencesFileName;
dict = readDataVO();
if (dict == null)
diff --git a/src/main/java/io/bitsquare/trade/Offer.java b/src/main/java/io/bitsquare/trade/Offer.java
index 1b32033b7c..ce6bf032ba 100644
--- a/src/main/java/io/bitsquare/trade/Offer.java
+++ b/src/main/java/io/bitsquare/trade/Offer.java
@@ -11,15 +11,18 @@ import java.util.UUID;
public class Offer
{
+ // key attributes for lookup
+ private Direction direction;
+ private Currency currency;
+
private UUID uid;
+
private double price;
private BigInteger amount;
private BigInteger minAmount;
private String accountID;
private String messageID;
- private Direction direction;
private BankAccountType.BankAccountTypeEnum bankAccountTypeEnum;
- private Currency currency;
private Locale bankAccountCountryLocale;
private double collateral;
diff --git a/src/main/java/io/bitsquare/trade/Trading.java b/src/main/java/io/bitsquare/trade/Trading.java
index 5069032935..2c11d141f2 100644
--- a/src/main/java/io/bitsquare/trade/Trading.java
+++ b/src/main/java/io/bitsquare/trade/Trading.java
@@ -9,7 +9,6 @@ import io.bitsquare.btc.Fees;
import io.bitsquare.btc.KeyPair;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade;
-import io.bitsquare.msg.Message;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.settings.Settings;
import io.bitsquare.user.User;
@@ -70,7 +69,7 @@ public class Trading
offers.put(offer.getUid().toString(), offer);
walletFacade.payFee(Fees.OFFER_CREATION_FEE, callback);
- messageFacade.broadcast(new Message(Message.BROADCAST_NEW_OFFER, offer));
+ // messageFacade.broadcast(new Message(Message.BROADCAST_NEW_OFFER, offer));
}
public Trade createTrade(Offer offer)
diff --git a/src/main/java/io/bitsquare/util/Utils.java b/src/main/java/io/bitsquare/util/Utils.java
index 4ef351b08e..4a1c764d6d 100644
--- a/src/main/java/io/bitsquare/util/Utils.java
+++ b/src/main/java/io/bitsquare/util/Utils.java
@@ -21,6 +21,12 @@ public class Utils
{
private static final Logger log = LoggerFactory.getLogger(Utils.class);
+ public static String getRootDir()
+ {
+ return Utils.class.getProtectionDomain().getCodeSource().getLocation().getFile() + "/";
+ }
+
+
public static String objectToJson(Object object)
{
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index f510b0b2b8..c6cee1e717 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -13,14 +13,17 @@
-
+
+
+
+
-
+