diff --git a/federation-controller-backend/build.sbt b/federation-controller-backend/build.sbt index c8a11412cdc9afb2fc34d9b9d071bfa7dbc36040..01e60f89db602cc50ab5cb0a90168fd4e44b07c2 100644 --- a/federation-controller-backend/build.sbt +++ b/federation-controller-backend/build.sbt @@ -44,7 +44,7 @@ libraryDependencies ++= Seq( ) Docker / packageName := "triledotlink/federation-controller-backend" -dockerExposedPorts ++= Seq(8078) +dockerExposedPorts ++= Seq(8078, 7078) lazy val trileFederationControllerBackend = (project in file(".")) .settings( diff --git a/federation-controller-backend/src/main/resources/application.conf b/federation-controller-backend/src/main/resources/application.conf index 92f274203f44c6f7177ece05ab5eb02d6ba7709d..d4c458287d338cadd00f027edb74ae6265566180 100644 --- a/federation-controller-backend/src/main/resources/application.conf +++ b/federation-controller-backend/src/main/resources/application.conf @@ -1,17 +1,23 @@ app { http { port = 8078 - port = ${?HTTP_PORT} + port = ${?TRILE_FEDERATION_CONTROLLER_HTTP_PORT} } ipfs { api-url = "http://127.0.0.1:5001/api/v0/" - api-url = ${?IPFS_API_URL} + api-url = ${?TRILE_FEDERATION_CONTROLLER_IPFS_API_URL} swarm-key-value = "" - swarm-key-value = ${?IPFS_SWARM_KEY_VALUE} + swarm-key-value = ${?TRILE_FEDERATION_CONTROLLER_IPFS_SWARM_KEY_VALUE} } ipfs-cluster { api-url = "http://127.0.0.1:9094/" - api-url = ${?IPFS_CLUSTER_API_URL} + api-url = ${?TRILE_FEDERATION_CONTROLLER_IPFS_CLUSTER_API_URL} + } + p2p { + private-key = "" + private-key = ${?TRILE_FEDERATION_CONTROLLER_P2P_PRIVATE_KEY} + swarm-port = 7078 + swarm-port = ${?TRILE_FEDERATION_CONTROLLER_P2P_PORT} } } @@ -27,9 +33,9 @@ akka-http-cors { redis { host = "127.0.0.1" - host = ${?REDIS_HOST} - port = "6380" - port = ${?REDIS_PORT} + host = ${?TRILE_FEDERATION_CONTROLLER_REDIS_HOST} + port = 6379 + port = ${?TRILE_FEDERATION_CONTROLLER_REDIS_PORT} } handlers= java.util.logging.ConsoleHandler diff --git a/federation-controller-backend/src/main/resources/logback.xml b/federation-controller-backend/src/main/resources/logback.xml index 4b1cdb2f7ef4e9495e44493191b3a7d7a488d640..be2c8610718a0df41bdc760598cd4da852d3dc67 100644 --- a/federation-controller-backend/src/main/resources/logback.xml +++ b/federation-controller-backend/src/main/resources/logback.xml @@ -7,7 +7,7 @@ <logger name="acab.devcon0.boot.ioc.CommonsIoC.InputOutput" level="WARN"/> <logger name="acab.devcon0.output.publisher.RedisPubSubMessagePublisherImpl" level="WARN"/> - <root level="INFO"> + <root level="INFO"> <appender-ref ref="STDOUT"/> </root> </configuration> diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/boot/Main.scala b/federation-controller-backend/src/main/scala/acab/devcon0/boot/Main.scala index d65538c2f3c16cc16862dc50a43a4d488e32588e..e46a24c4546b7dd2ddfbdd5d8bd11f6635b5fb8c 100644 --- a/federation-controller-backend/src/main/scala/acab/devcon0/boot/Main.scala +++ b/federation-controller-backend/src/main/scala/acab/devcon0/boot/Main.scala @@ -4,6 +4,7 @@ import acab.devcon0.boot.ioc.CommonsIoC import acab.devcon0.boot.ioc.FederationIoC import acab.devcon0.boot.ioc.FederationMemberIoC import acab.devcon0.boot.ioc.IpfsIoC +import acab.devcon0.configuration.Configuration import acab.devcon0.configuration.ConfigurationCodecs import acab.devcon0.configuration.ConfigurationCodecs.Encoders._ import cats.effect.ExitCode @@ -18,6 +19,9 @@ import org.typelevel.log4cats.slf4j.Slf4jLogger object Main extends IOApp.Simple { + private val logger: Logger[IO] = Slf4jLogger.getLogger[IO] + private val trileConfiguration: Configuration = CommonsIoC.Configuration.configuration + val run: IO[Unit] = Supervisor[IO](await = false).use { _ => logConfiguration() >> IO(IpfsIoC.Input.redisIndexesBootstrap.run()) >> @@ -31,11 +35,10 @@ object Main extends IOApp.Simple { IO(FederationIoC.Input.ipfsCidDeltaUpdateRedisListener.run()) >> runHttpServer } - private val logger: Logger[IO] = Slf4jLogger.getLogger[IO] private def logConfiguration(): IO[Unit] = { ConfigurationCodecs.Encoders - .Configuration(CommonsIoC.Configuration.configuration) + .Configuration(trileConfiguration) .flatMap(str => logger.warn(s"Configuration=$str")) } @@ -43,7 +46,7 @@ object Main extends IOApp.Simple { EmberServerBuilder .default[IO] .withHost(host"0.0.0.0") - .withPort(Port.fromInt(CommonsIoC.Configuration.configuration.http.port).get) + .withPort(Port.fromInt(trileConfiguration.http.port).get) .withHttpApp(CommonsIoC.Input.routes.httpApp) .build .use(_ => IO.never) diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala b/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala index 30b14a027de59caae3545436c9b3a56b7b257dc9..67cec32b73e90eae48566874c19f52eccb023e60 100644 --- a/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala +++ b/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala @@ -35,13 +35,14 @@ object CommonsIoC { implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO] private val stringCodec: RedisCodec[String, String] = RedisCodec.Utf8 private val redisConfiguration: RedisConfiguration = Configuration.configuration.redis - private val host: String = redisConfiguration.host - private val port: Int = redisConfiguration.port - def redisClientFactory(): Resource[IO, RedisClient] = RedisClient[IO].from(s"redis://$host:$port") + private val redisHost = s"redis://${redisConfiguration.host}:${redisConfiguration.port}" + def redisClientFactory(): Resource[IO, RedisClient] = { + RedisClient[IO].from(redisHost) + } def redisCommandsFactory(): Resource[IO, RedisCommands[IO, String, String]] = { RedisClient[IO] - .from(s"redis://$host:$port") + .from(redisHost) .flatMap(dev.profunktor.redis4cats.Redis[IO].fromClient(_, stringCodec)) } @@ -56,7 +57,7 @@ object CommonsIoC { } object Input { - val p2pHost: P2pHost = new P2pHost() + val p2pHost: P2pHost = new P2pHost(p2pConfiguration = Configuration.configuration.p2p) val p2pPubSubListener: ipfspubsub.P2pListener = new ipfspubsub.P2pListener( p2pHostResources = p2pHost.getResources @@ -83,7 +84,14 @@ object CommonsIoC { val federationMembersRoute: FederationMembersRoute = FederationMembersRoute( informationQueryHandler = FederationMemberIoC.Domain.Port.federationMembersInformationQueryHandler ) - val routes: Routes = Routes(nodeRoute, federationMembersRoute, ipfsCidRoute) + + val p2pRoute: P2pRoute = new P2pRoute(Configuration.configuration.p2p) + val routes: Routes = new Routes( + nodeRoute = nodeRoute, + federationMembersRoute = federationMembersRoute, + ipfsCidRoute = ipfsCidRoute, + p2pRoute = p2pRoute + ) def websocketRoute: WebsocketRoute = new WebsocketRoute() diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala b/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala index 8897436229d0273e5da90556c2f21f3a2a984f8b..fd845f65819f45c28eca356b991103fbf2bb2189 100644 --- a/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala +++ b/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala @@ -1,28 +1,36 @@ package acab.devcon0 package configuration +import java.util.Base64 import com.typesafe.config.Config import com.typesafe.config.ConfigFactory +import io.libp2p.core.PeerId +import io.libp2p.core.crypto.PrivKey +import io.libp2p.core.crypto.PubKey +import io.libp2p.crypto.keys.Ed25519Kt -final case class RedisConfiguration(host: String, port: Int) +final case class P2pConfiguration(privateKey: PrivKey, peerId: PeerId, swarmPort: Integer) +final case class RedisConfiguration(host: String, port: Integer) final case class IpfsClusterConfiguration(apiUrl: String) final case class IpfsConfiguration(apiUrl: String, swarmKeyValue: String) -final case class HttpConfiguration(port: Int) +final case class HttpConfiguration(port: Integer) final case class Configuration( ipfs: IpfsConfiguration, ipfsCluster: IpfsClusterConfiguration, http: HttpConfiguration, - redis: RedisConfiguration + redis: RedisConfiguration, + p2p: P2pConfiguration ) object TrileControllerBackendConfigFactory { private val rawConfig: Config = ConfigFactory.load("application.conf") - private val conf: Config = rawConfig.getConfig("app") - private val ipfsConfig: Config = conf.getConfig("ipfs") - private val ipfsClusterConfig: Config = conf.getConfig("ipfs-cluster") private val redisConfig: Config = rawConfig.getConfig("redis") - private val httpConfig: Config = conf.getConfig("http") + private val appConfig: Config = rawConfig.getConfig("app") + private val ipfsConfig: Config = appConfig.getConfig("ipfs") + private val ipfsClusterConfig: Config = appConfig.getConfig("ipfs-cluster") + private val httpConfig: Config = appConfig.getConfig("http") + private val p2pConfig: Config = appConfig.getConfig("p2p") def build(): Configuration = { val ipfsConfiguration: IpfsConfiguration = IpfsConfiguration( @@ -43,11 +51,26 @@ object TrileControllerBackendConfigFactory { port = redisConfig.getInt("port") ) + val p2pConfiguration: P2pConfiguration = getP2pConfiguration + Configuration( ipfs = ipfsConfiguration, ipfsCluster = ipfsClusterConfiguration, http = httpConfiguration, - redis = redisConfiguration + redis = redisConfiguration, + p2p = p2pConfiguration + ) + } + + private def getP2pConfiguration: P2pConfiguration = { + val p2pPrivateKeyValue: String = p2pConfig.getString("private-key") + val p2pPrivateKey: PrivKey = Ed25519Kt.unmarshalEd25519PrivateKey(Base64.getDecoder.decode(p2pPrivateKeyValue)) + val p2pPublicKey: PubKey = p2pPrivateKey.publicKey() + val p2pPeerId: PeerId = PeerId.fromPubKey(p2pPublicKey) + P2pConfiguration( + privateKey = p2pPrivateKey, + peerId = p2pPeerId, + swarmPort = p2pConfig.getInt("swarm-port") ) } } diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/configuration/ConfigurationCodecs.scala b/federation-controller-backend/src/main/scala/acab/devcon0/configuration/ConfigurationCodecs.scala index 4a30b1e6ff7888ba2ea93126810288852d26bb6e..77889799b39724a8df1e5e2a1b62662f40c63921 100644 --- a/federation-controller-backend/src/main/scala/acab/devcon0/configuration/ConfigurationCodecs.scala +++ b/federation-controller-backend/src/main/scala/acab/devcon0/configuration/ConfigurationCodecs.scala @@ -3,11 +3,21 @@ package configuration import cats.effect.IO import io.circe.Encoder +import io.circe.Json import io.circe.generic.semiauto.deriveEncoder import io.circe.syntax.EncoderOps +import io.libp2p.core.crypto.PrivKey object ConfigurationCodecs { object Encoders { + implicit val privateKey: Encoder[PrivKey] = (* : PrivKey) => Json.fromString("***") + implicit val p2p: Encoder[P2pConfiguration] = (p2pConfiguration: P2pConfiguration) => { + Json.obj( + ("privateKey", Json.fromString("***")), + ("swarmPort", Json.fromString(p2pConfiguration.swarmPort.toString)), + ("peerId", Json.fromString(p2pConfiguration.peerId.toBase58)) + ) + } implicit val ipfs: Encoder[IpfsConfiguration] = deriveEncoder[IpfsConfiguration] implicit val ipfsCluster: Encoder[IpfsClusterConfiguration] = deriveEncoder[IpfsClusterConfiguration] implicit val http: Encoder[HttpConfiguration] = deriveEncoder[HttpConfiguration] diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/domain/codecs/P2pCodecs.scala b/federation-controller-backend/src/main/scala/acab/devcon0/domain/codecs/P2pCodecs.scala new file mode 100644 index 0000000000000000000000000000000000000000..22a49f8c7ee9fdb3b9fdb3e598f72a74b581ee33 --- /dev/null +++ b/federation-controller-backend/src/main/scala/acab/devcon0/domain/codecs/P2pCodecs.scala @@ -0,0 +1,11 @@ +package acab.devcon0.domain.codecs + +import io.circe.Encoder +import io.circe.Json +import io.libp2p.core.PeerId + +object P2pCodecs { + object Encoders { + implicit val peerId: Encoder[PeerId] = (peerId: PeerId) => Json.obj(("peerId", Json.fromString(peerId.toString))) + } +} diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/P2pRoute.scala b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/P2pRoute.scala new file mode 100644 index 0000000000000000000000000000000000000000..6ec5d4c96ef1108219a6259972ae978a215a3d47 --- /dev/null +++ b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/P2pRoute.scala @@ -0,0 +1,21 @@ +package acab.devcon0.input.http + +import acab.devcon0.configuration.P2pConfiguration +import cats.effect._ +import org.http4s._ +import org.http4s.circe.CirceEntityEncoder.circeEntityEncoder +import org.http4s.dsl.io._ +import org.typelevel.log4cats.Logger +import org.typelevel.log4cats.slf4j.Slf4jLogger + +class P2pRoute(p2pConfiguration: P2pConfiguration) { + + implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO] + + val routes: HttpRoutes[IO] = HttpRoutes + .of[IO] { case GET -> Root / "id" => + (for response <- Ok(p2pConfiguration.peerId.toBase58) + yield response).handleErrorWith(_ => BadRequest()) + + } +} diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala index f6a6b8ca635374a42bb6d730cd1af0b712a00972..b29e0fb5ee26865456d5b2a0a1aeeca19d66a07e 100644 --- a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala +++ b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala @@ -8,14 +8,16 @@ import org.http4s.server.middleware.CORS class Routes( nodeRoute: FederationMemberRoute, federationMembersRoute: FederationMembersRoute, - ipfsCidRoute: IpfsCidRoute + ipfsCidRoute: IpfsCidRoute, + p2pRoute: P2pRoute ) { val httpApp: Http[IO, IO] = CORS.policy.withAllowOriginAll( Router( "/api/federation/members" -> federationMembersRoute.rootRoutes, "/api/federation/members" -> nodeRoute.routes, - "/api/ipfs/" -> ipfsCidRoute.routes + "/api/ipfs/" -> ipfsCidRoute.routes, + "/api/p2p/" -> p2pRoute.routes ).orNotFound ) diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/input/ipfspubsub/P2pHost.scala b/federation-controller-backend/src/main/scala/acab/devcon0/input/ipfspubsub/P2pHost.scala index 73a5e044d2ac3b2e79cd2db0ece4b12c21a17f7d..e79a6b8f40d492683eee8d1cd4bd7c1763783c0e 100644 --- a/federation-controller-backend/src/main/scala/acab/devcon0/input/ipfspubsub/P2pHost.scala +++ b/federation-controller-backend/src/main/scala/acab/devcon0/input/ipfspubsub/P2pHost.scala @@ -1,17 +1,15 @@ package acab.devcon0.input.ipfspubsub -import java.util.Base64 import java.util.concurrent.TimeUnit import scala.concurrent.duration.Duration import scala.concurrent.duration.FiniteDuration +import acab.devcon0.configuration.P2pConfiguration import cats.effect._ import io.libp2p.core.Host -import io.libp2p.core.crypto.PrivKey import io.libp2p.core.dsl.BuilderJ import io.libp2p.core.dsl.HostBuilder import io.libp2p.core.mux.StreamMuxerProtocol -import io.libp2p.crypto.keys.Ed25519Kt import io.libp2p.pubsub.gossip.Gossip import io.libp2p.pubsub.gossip.GossipParams import io.libp2p.pubsub.gossip.GossipRouter @@ -23,15 +21,7 @@ import org.typelevel.log4cats.slf4j.Slf4jLogger final case class P2pHostResources(host: Host, gossipRouter: GossipRouter, gossip: Gossip) -class P2pHost { - - private val p2pSwarmPort: Int = 40001 - private val privateKey: PrivKey = Ed25519Kt - .unmarshalEd25519PrivateKey( - Base64.getDecoder.decode( - "CAESQKu4I59ZxOZtcYnVjUE9W1pTIFP0aNmdECNOepHzksl4DC7EMPcNBthQXtVOWQ/FuUeWgUJkUkfOmirl22WyrQc=" - ) - ) +class P2pHost(p2pConfiguration: P2pConfiguration) { private val maxConnectionDuration: FiniteDuration = Duration(5, TimeUnit.SECONDS) private val logger: Logger[IO] = Slf4jLogger.getLogger[IO] @@ -65,7 +55,7 @@ class P2pHost { new HostBuilder() .builderModifier((builderJ: BuilderJ) => { builderJ.identity(identityBuilder => { - identityBuilder.setFactory(() => privateKey) + identityBuilder.setFactory(() => p2pConfiguration.privateKey) kotlin.Unit.INSTANCE }) }) @@ -73,7 +63,7 @@ class P2pHost { .secureChannel((privateKey, muxers) => new NoiseXXSecureChannel(privateKey, muxers)) .muxer(() => StreamMuxerProtocol.getYamux) .protocol(gossip) - .listen(s"/ip4/127.0.0.1/tcp/$p2pSwarmPort") + .listen(s"/ip4/0.0.0.0/tcp/${p2pConfiguration.swarmPort}/p2p/${p2pConfiguration.peerId}") .build } }