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:
parent
b4b1d75c53
commit
9f060a5d27
8 changed files with 103 additions and 62 deletions
|
@ -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>
|
||||
|
|
26
eclair-core/src/main/scala/fr/acinq/eclair/PortChecker.scala
Normal file
26
eclair-core/src/main/scala/fr/acinq/eclair/PortChecker.scala
Normal 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
|
|
@ -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")
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue