1
0
mirror of https://github.com/ACINQ/eclair.git synced 2024-11-19 01:43:22 +01:00

Added simple plugin support (#927)

Using org.clapper:classutil library and a very simple `Plugin` interface.
This commit is contained in:
Pierre-Marie Padiou 2019-04-19 18:10:47 +02:00 committed by GitHub
parent f563ca0897
commit c530b23175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 3 deletions

View File

@ -152,6 +152,17 @@ If you want to persist the data directory, you can make the volume to your host
docker run -ti --rm -v "/path_on_host:/data" -e "JAVA_OPTS=-Declair.printToConsole" acinq/eclair
```
## Plugins
For advanced usage, Eclair supports plugins written in Scala, Java, or any JVM-compatible language.
A valid plugin is a jar that contains an implementation of the [Plugin](eclair-node/src/main/scala/fr/acinq/eclair/Plugin.scala) interface.
Here is how to run Eclair with plugins:
```shell
java -jar eclair-node-<version>-<commit_id>.jar <plugin1.jar> <plugin2.jar> <...>
```
## Mainnet usage
Following are the minimum configuration files you need to use for Bitcoin Core and Eclair.

View File

@ -74,6 +74,12 @@
<artifactId>eclair-core_${scala.version.short}</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<!-- for plugins -->
<groupId>org.clapper</groupId>
<artifactId>classutil_${scala.version.short}</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>

View File

@ -22,6 +22,7 @@ import akka.actor.ActorSystem
import grizzled.slf4j.Logging
import scala.concurrent.ExecutionContext
import scala.util.{Failure, Success}
/**
* Created by PM on 25/01/2016.
@ -31,10 +32,15 @@ object Boot extends App with Logging {
val datadir = new File(System.getProperty("eclair.datadir", System.getProperty("user.home") + "/.eclair"))
try {
val plugins = Plugin.loadPlugins(args.map(new File(_)))
plugins.foreach(plugin => logger.info(s"loaded plugin ${plugin.getClass.getSimpleName}"))
implicit val system: ActorSystem = ActorSystem("eclair-node")
implicit val ec: ExecutionContext = system.dispatcher
new Setup(datadir).bootstrap onFailure {
case t: Throwable => onError(t)
val setup = new Setup(datadir)
plugins.foreach(_.onSetup(setup))
setup.bootstrap onComplete {
case Success(kit) => plugins.foreach(_.onKit(kit))
case Failure(t) => onError(t)
}
} catch {
case t: Throwable => onError(t)
@ -47,4 +53,3 @@ object Boot extends App with Logging {
System.exit(1)
}
}

View File

@ -0,0 +1,29 @@
package fr.acinq.eclair
import java.io.File
import java.net.{URL, URLClassLoader}
import org.clapper.classutil.ClassFinder
trait Plugin {
def onSetup(setup: Setup): Unit
def onKit(kit: Kit): Unit
}
object Plugin {
def loadPlugins(jars: Seq[File]): Seq[Plugin] = {
val finder = ClassFinder(jars)
val classes = finder.getClasses
val urls = jars.map(f => new URL(s"file:${f.getCanonicalPath}"))
val loader = new URLClassLoader(urls.toArray, ClassLoader.getSystemClassLoader)
classes
.filter(_.isConcrete)
.filter(_.implements(classOf[Plugin].getName))
.map(c => Class.forName(c.name, true, loader).getDeclaredConstructor().newInstance().asInstanceOf[Plugin])
.toList
}
}