mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-03-15 10:26:37 -04:00
integration of TomP2P and basic use cases in dummy views tested
This commit is contained in:
parent
9a29004251
commit
6459184ce9
@ -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
|
||||
* ...
|
||||
|
||||
|
||||
|
28
pom.xml
28
pom.xml
@ -50,7 +50,7 @@
|
||||
<!-- bitcoin-j repo -->
|
||||
<repository>
|
||||
<id>bitcoinj-release</id>
|
||||
<releases />
|
||||
<releases/>
|
||||
<url>http://distribution.bitcoinj.googlecode.com/git/releases</url>
|
||||
</repository>
|
||||
<!-- zxing repo -->
|
||||
@ -59,6 +59,12 @@
|
||||
<url>http://mvn-adamgent.googlecode.com/svn/maven/release</url>
|
||||
<name>Adam Gent Maven Repository</name>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>tomp2p.net</id>
|
||||
<url>http://tomp2p.net/dev/mvn/</url>
|
||||
</repository>
|
||||
|
||||
</repositories>
|
||||
|
||||
<!-- TODO Maven build not working yet... -->
|
||||
@ -106,13 +112,13 @@
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.7</version>
|
||||
</dependency>
|
||||
-->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.7</version>
|
||||
</dependency>
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
@ -170,6 +176,12 @@
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.tomp2p</groupId>
|
||||
<artifactId>TomP2P</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -3,4 +3,6 @@ package io.bitsquare.gui;
|
||||
public interface ChildController
|
||||
{
|
||||
void setNavigationController(NavigationController navigationController);
|
||||
|
||||
void cleanup();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -66,6 +66,12 @@ public class FundsController implements Initializable, ChildController
|
||||
balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,5 +24,11 @@ public class HistoryController implements Initializable, ChildController
|
||||
{
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,5 +28,11 @@ public class HomeController implements Initializable, ChildController
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -93,11 +93,7 @@ public class MarketController implements Initializable, NavigationController, Ch
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
if (orderBookController != null)
|
||||
|
@ -114,6 +114,12 @@ public class CreateOfferController implements Initializable, ChildController, Wa
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface implementation: WalletFacade.WalletListener
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -122,6 +122,12 @@ public class TradeController implements Initializable, ChildController, WalletFa
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface implementation: WalletFacade.WalletListener
|
||||
|
@ -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<String> 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<String>
|
||||
{
|
||||
private String expectedMsg;
|
||||
|
||||
Task(String expectedMsg)
|
||||
{
|
||||
this.expectedMsg = expectedMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String call() throws Exception
|
||||
{
|
||||
Thread.sleep(1000); // 1 seconds pause
|
||||
return expectedMsg;
|
||||
}
|
||||
}
|
@ -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<OfferListItem> 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<String, OfferListItem> 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<Number160, Data> 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<TableColumn<String, OfferListItem>, TableCell<String, OfferListItem>>()
|
||||
{
|
||||
@Override
|
||||
public TableCell<String, OfferListItem> call(TableColumn<String, OfferListItem> directionColumn)
|
||||
{
|
||||
return new TableCell<String, OfferListItem>()
|
||||
{
|
||||
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<TableColumn<String, OfferListItem>, TableCell<String, OfferListItem>>()
|
||||
{
|
||||
@Override
|
||||
public TableCell<String, OfferListItem> call(TableColumn<String, OfferListItem> directionColumn)
|
||||
{
|
||||
return new TableCell<String, OfferListItem>()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,80 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<Pane fx:controller="io.bitsquare.gui.msg.MsgController"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<Label text="Msg"/>
|
||||
</Pane>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.control.cell.PropertyValueFactory?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<AnchorPane fx:controller="io.bitsquare.gui.msg.MsgController" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0"
|
||||
AnchorPane.topAnchor="0" xmlns="http://javafx.com/javafx/8"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
|
||||
<Label text="Offer list" AnchorPane.leftAnchor="10" AnchorPane.topAnchor="15.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
<ComboBox fx:id="currencyComboBox" onAction="#selectCurrency" prefWidth="100" AnchorPane.rightAnchor="405" AnchorPane.topAnchor="10.0"/>
|
||||
<TableView fx:id="offerTable" prefHeight="200.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="405"
|
||||
AnchorPane.topAnchor="40.0">
|
||||
<columns>
|
||||
<TableColumn text="Offer" fx:id="offerColumn" minWidth="120">
|
||||
<cellValueFactory>
|
||||
<PropertyValueFactory property="offer"/>
|
||||
</cellValueFactory>
|
||||
</TableColumn>
|
||||
<TableColumn text="Peer PubKey" fx:id="pubKeyColumn" minWidth="80" prefWidth="80">
|
||||
<cellValueFactory>
|
||||
<PropertyValueFactory property="pubKey"/>
|
||||
</cellValueFactory>
|
||||
</TableColumn>
|
||||
<TableColumn text="" fx:id="removeOfferColumn" minWidth="80" sortable="false"/>
|
||||
<TableColumn text="" fx:id="connectToPeerColumn" minWidth="80" sortable="false"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
|
||||
<Label text="Chat with peer" AnchorPane.bottomAnchor="210.0" AnchorPane.leftAnchor="10.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
<TextArea fx:id="chatTextArea" editable="false" prefHeight="160.0" AnchorPane.bottomAnchor="45.0" AnchorPane.leftAnchor="10.0"
|
||||
AnchorPane.rightAnchor="10.0"/>
|
||||
<TextField fx:id="chatInputField" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="120.0"/>
|
||||
<Button fx:id="sendButton" onAction="#sendChatMsg" disable="true" defaultButton="true" prefWidth="100.0" text="Send" AnchorPane.bottomAnchor="10.0"
|
||||
AnchorPane.rightAnchor="10"/>
|
||||
|
||||
|
||||
<GridPane hgap="5.0" prefWidth="385.0" vgap="5.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="40.0">
|
||||
<children>
|
||||
<Label layoutX="418.0" text="Add new Offer" AnchorPane.topAnchor="10.0" GridPane.columnSpan="2" GridPane.halignment="LEFT"
|
||||
GridPane.rowIndex="0">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="Peer ID:" GridPane.rowIndex="1"/>
|
||||
<Label text="Currency:" GridPane.rowIndex="2"/>
|
||||
<Label text="Offer data:" GridPane.rowIndex="3"/>
|
||||
<TextField fx:id="peerIDTextField" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
|
||||
<TextField fx:id="currencyTextField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
|
||||
<TextField fx:id="offerDataTextField" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
|
||||
<Button onAction="#publishOffer" text="Add Offer" GridPane.columnIndex="1" GridPane.rowIndex="4"/>
|
||||
</children>
|
||||
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" minWidth="10.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
|
||||
<RowConstraints minHeight="10.0" vgrow="ALWAYS"/>
|
||||
</rowConstraints>
|
||||
</GridPane>
|
||||
|
||||
</children>
|
||||
</AnchorPane>
|
||||
|
40
src/main/java/io/bitsquare/gui/msg/OfferListItem.java
Normal file
40
src/main/java/io/bitsquare/gui/msg/OfferListItem.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -26,5 +26,11 @@ public class OrdersController implements Initializable, ChildController
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -39,5 +39,11 @@ public class SettingsController implements Initializable, ChildController
|
||||
this.navigationController = navigationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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<ProcessStepItem> 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();
|
||||
|
24
src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java
Executable file
24
src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java
Executable file
@ -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;
|
||||
}
|
||||
}
|
@ -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<MessageListener> 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<BaseFuture>()
|
||||
{
|
||||
@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<BaseFuture>()
|
||||
{
|
||||
@Override
|
||||
public void operationComplete(BaseFuture future) throws Exception
|
||||
{
|
||||
final Map<Number160, Data> dataMap = getOffersFuture.getDataMap();
|
||||
Platform.runLater(() -> onOffersReceived(dataMap, future.isSuccess()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onOffersReceived(Map<Number160, Data> 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<BaseFuture>()
|
||||
{
|
||||
@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<BaseFuture>()
|
||||
{
|
||||
@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<BaseFuture>()
|
||||
{
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
|
26
src/main/java/io/bitsquare/msg/MessageListener.java
Normal file
26
src/main/java/io/bitsquare/msg/MessageListener.java
Normal file
@ -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<Number160, Data> dataMap, boolean success);
|
||||
|
||||
void onOfferRemoved(boolean success);
|
||||
}
|
131
src/main/java/io/bitsquare/msg/MsgKeyUtil.java
Executable file
131
src/main/java/io/bitsquare/msg/MsgKeyUtil.java
Executable file
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -13,14 +13,17 @@
|
||||
<appender-ref ref="CONSOLE_APPENDER"/>
|
||||
</root>
|
||||
|
||||
<logger name="io.bitsquare" level="DEBUG"/>
|
||||
<logger name="io.bitsquare" level="INFO"/>
|
||||
|
||||
<logger name="com.google.bitcoin" level="ERROR"/>
|
||||
<logger name="net.tomp2p" level="INFO"/>
|
||||
|
||||
<logger name="com.google.bitcoin" level="INFO"/>
|
||||
|
||||
<logger name="com.google.bitcoin.core.Peer" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.core.PeerGroup" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.net.NioClientManager" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.net.ConnectionHandler" level="ERROR" additivity="false"/>
|
||||
<logger name="com.google.bitcoin.net.discovery.DnsDiscovery" level="OFF" additivity="false"/>
|
||||
|
||||
<!--
|
||||
-->
|
||||
|
Loading…
x
Reference in New Issue
Block a user