1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-03-13 19:37:35 +01:00

Bugfix: regression in init

Eclair wasn't stopping anymore when two instances were started with the
same ports.

Note: we should probably go one step further and put a lock in the datadir
directory.

Set version to 0.2-spv-d
This commit is contained in:
pm47 2017-08-21 18:12:37 +02:00
parent b4b1d75c53
commit 9f060a5d27
8 changed files with 103 additions and 62 deletions

View file

@ -5,7 +5,7 @@
<parent>
<groupId>fr.acinq.eclair</groupId>
<artifactId>eclair_2.11</artifactId>
<version>0.2-spv-c</version>
<version>0.2-spv-d</version>
</parent>
<artifactId>eclair-core_2.11</artifactId>

View file

@ -0,0 +1,26 @@
package fr.acinq.eclair
import java.net.{InetAddress, ServerSocket}
import scala.util.{Failure, Success, Try}
object PortChecker {
/**
* Tests if a port is open
* See https://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java#435579
*
* @return
*/
def checkAvailable(host: String, port: Int): Unit = {
Try(new ServerSocket(port, 50, InetAddress.getByName(host))) match {
case Success(socket) =>
Try(socket.close())
case Failure(_) =>
throw TCPBindException(port)
}
}
}
case class TCPBindException(port: Int) extends RuntimeException

View file

@ -38,6 +38,9 @@ class Setup(datadir: File, overrideDefaults: Config = ConfigFactory.empty(), act
val spv = config.getBoolean("spv")
// early check
PortChecker.checkAvailable(config.getString("server.binding-ip"), config.getInt("server.port"))
logger.info(s"initializing secure random generator")
// this will force the secure random instance to initialize itself right now, making sure it doesn't hang later (see comment in package.scala)
secureRandom.nextInt()
@ -170,8 +173,6 @@ case class Kit(nodeParams: NodeParams,
paymentInitiator: ActorRef,
server: ActorRef)
case class TCPBindException(port: Int) extends RuntimeException
case object BitcoinZMQConnectionTimeoutException extends RuntimeException("could not connect to bitcoind using zeromq")
case object BitcoinRPCConnectionException extends RuntimeException("could not connect to bitcoind using json-rpc")

View file

@ -5,7 +5,7 @@
<parent>
<groupId>fr.acinq.eclair</groupId>
<artifactId>eclair_2.11</artifactId>
<version>0.2-spv-c</version>
<version>0.2-spv-d</version>
</parent>
<artifactId>eclair-node-javafx_2.11</artifactId>

View file

@ -19,7 +19,7 @@ import fr.acinq.eclair.router.NetworkEvent
import grizzled.slf4j.Logging
import scala.concurrent.Promise
import scala.util.{Success, Failure}
import scala.util.{Failure, Success}
/**
@ -31,59 +31,67 @@ class FxApp extends Application with Logging {
logger.debug("initializing application...")
}
def onError(t: Throwable): Unit = t match {
case TCPBindException(port) =>
notifyPreloader(new ErrorNotification("Setup", s"Could not bind to port $port", null))
case BitcoinRPCConnectionException =>
notifyPreloader(new ErrorNotification("Setup", "Could not connect to Bitcoin Core using JSON-RPC.", null))
notifyPreloader(new AppNotification(InfoAppNotification, "Make sure that Bitcoin Core is up and running and RPC parameters are correct."))
case BitcoinZMQConnectionTimeoutException =>
notifyPreloader(new ErrorNotification("Setup", "Could not connect to Bitcoin Core using ZMQ.", null))
notifyPreloader(new AppNotification(InfoAppNotification, "Make sure that Bitcoin Core is up and running and ZMQ parameters are correct."))
case t: Throwable =>
notifyPreloader(new ErrorNotification("Setup", s"Internal error: ${t.toString}", t))
}
override def start(primaryStage: Stage): Unit = {
new Thread(new Runnable {
override def run(): Unit = {
val icon = new Image(getClass.getResource("/gui/commons/images/eclair-square.png").toExternalForm, false)
primaryStage.getIcons.add(icon)
val mainFXML = new FXMLLoader(getClass.getResource("/gui/main/main.fxml"))
val pKit = Promise[Kit]()
val handlers = new Handlers(pKit.future)
val controller = new MainController(handlers, getHostServices)
mainFXML.setController(controller)
val mainRoot = mainFXML.load[Parent]
val datadir = new File(getParameters.getUnnamed.get(0))
implicit val system = ActorSystem("system")
val setup = new Setup(datadir)
val guiUpdater = setup.system.actorOf(SimpleSupervisor.props(Props(classOf[GUIUpdater], controller), "gui-updater", SupervisorStrategy.Resume))
setup.system.eventStream.subscribe(guiUpdater, classOf[ChannelEvent])
setup.system.eventStream.subscribe(guiUpdater, classOf[NetworkEvent])
setup.system.eventStream.subscribe(guiUpdater, classOf[PaymentEvent])
setup.system.eventStream.subscribe(guiUpdater, classOf[ZMQEvents])
pKit.completeWith(setup.bootstrap)
import scala.concurrent.ExecutionContext.Implicits.global
pKit.future.onComplete {
case Success(_) =>
Platform.runLater(new Runnable {
override def run(): Unit = {
val scene = new Scene(mainRoot)
primaryStage.setTitle("Eclair")
primaryStage.setMinWidth(600)
primaryStage.setWidth(960)
primaryStage.setMinHeight(400)
primaryStage.setHeight(640)
primaryStage.setOnCloseRequest(new EventHandler[WindowEvent] {
override def handle(event: WindowEvent) {
System.exit(0)
}
})
controller.initInfoFields(setup)
primaryStage.setScene(scene)
primaryStage.show
notifyPreloader(new AppNotification(SuccessAppNotification, "Init successful"))
initNotificationStage(primaryStage, handlers)
}
})
case Failure(TCPBindException(port)) =>
notifyPreloader(new ErrorNotification("Setup", s"Could not bind to port $port", null))
case Failure(BitcoinRPCConnectionException) =>
notifyPreloader(new ErrorNotification("Setup", "Could not connect to Bitcoin Core using JSON-RPC.", null))
notifyPreloader(new AppNotification(InfoAppNotification, "Make sure that Bitcoin Core is up and running and RPC parameters are correct."))
case Failure(BitcoinZMQConnectionTimeoutException) =>
notifyPreloader(new ErrorNotification("Setup", "Could not connect to Bitcoin Core using ZMQ.", null))
notifyPreloader(new AppNotification(InfoAppNotification, "Make sure that Bitcoin Core is up and running and ZMQ parameters are correct."))
case Failure(t) =>
notifyPreloader(new ErrorNotification("Setup", s"Internal error: ${t.toString}", t))
try {
val icon = new Image(getClass.getResource("/gui/commons/images/eclair-square.png").toExternalForm, false)
primaryStage.getIcons.add(icon)
val mainFXML = new FXMLLoader(getClass.getResource("/gui/main/main.fxml"))
val pKit = Promise[Kit]()
val handlers = new Handlers(pKit.future)
val controller = new MainController(handlers, getHostServices)
mainFXML.setController(controller)
val mainRoot = mainFXML.load[Parent]
val datadir = new File(getParameters.getUnnamed.get(0))
implicit val system = ActorSystem("system")
val setup = new Setup(datadir)
val guiUpdater = setup.system.actorOf(SimpleSupervisor.props(Props(classOf[GUIUpdater], controller), "gui-updater", SupervisorStrategy.Resume))
setup.system.eventStream.subscribe(guiUpdater, classOf[ChannelEvent])
setup.system.eventStream.subscribe(guiUpdater, classOf[NetworkEvent])
setup.system.eventStream.subscribe(guiUpdater, classOf[PaymentEvent])
setup.system.eventStream.subscribe(guiUpdater, classOf[ZMQEvents])
pKit.completeWith(setup.bootstrap)
import scala.concurrent.ExecutionContext.Implicits.global
pKit.future.onComplete {
case Success(_) =>
Platform.runLater(new Runnable {
override def run(): Unit = {
val scene = new Scene(mainRoot)
primaryStage.setTitle("Eclair")
primaryStage.setMinWidth(600)
primaryStage.setWidth(960)
primaryStage.setMinHeight(400)
primaryStage.setHeight(640)
primaryStage.setOnCloseRequest(new EventHandler[WindowEvent] {
override def handle(event: WindowEvent) {
System.exit(0)
}
})
controller.initInfoFields(setup)
primaryStage.setScene(scene)
primaryStage.show
notifyPreloader(new AppNotification(SuccessAppNotification, "Init successful"))
initNotificationStage(primaryStage, handlers)
}
})
case Failure(t) => onError(t)
}
} catch {
case t: Throwable => onError(t)
}
}
}).start

View file

@ -5,7 +5,7 @@
<parent>
<groupId>fr.acinq.eclair</groupId>
<artifactId>eclair_2.11</artifactId>
<version>0.2-spv-c</version>
<version>0.2-spv-d</version>
</parent>
<artifactId>eclair-node_2.11</artifactId>

View file

@ -21,14 +21,20 @@ object Boot extends App with Logging {
parser.parse(args, CmdLineConfig()) match {
case Some(config) =>
LogSetup.logTo(config.datadir)
new Setup(config.datadir).bootstrap
import scala.concurrent.ExecutionContext.Implicits.global
new Setup(config.datadir).bootstrap onFailure {
case t: Throwable => onError(t)
}
case None => System.exit(0)
}
} catch {
case t: Throwable =>
System.err.println(s"fatal error: ${t.getMessage}")
logger.error(s"fatal error: ${t.getMessage}")
System.exit(1)
case t: Throwable => onError(t)
}
def onError(t: Throwable): Unit = {
System.err.println(s"fatal error: ${t.getMessage}")
logger.error(s"fatal error: ${t.getMessage}")
System.exit(1)
}
}

View file

@ -4,7 +4,7 @@
<groupId>fr.acinq.eclair</groupId>
<artifactId>eclair_2.11</artifactId>
<version>0.2-spv-c</version>
<version>0.2-spv-d</version>
<packaging>pom</packaging>
<modules>