Skip to content

Commit 2b1f339

Browse files
authored
Merge pull request #19 from delphi-hub/feature/config_ip_for_IR
Webapp connection to instance registry
2 parents 6c39e31 + c478d54 commit 2b1f339

File tree

10 files changed

+395
-2
lines changed

10 files changed

+395
-2
lines changed

app/EagerLoaderModule.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package app
2+
import com.google.inject.AbstractModule
3+
import services.StartUpService
4+
5+
/**
6+
* Run functions during request
7+
*/
8+
class EagerLoaderModule extends AbstractModule {
9+
override def configure() = {
10+
//startupservice will run during request
11+
bind(classOf[StartUpService]).asEagerSingleton
12+
}
13+
}

app/services/StartUpService.scala

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package services
2+
3+
import java.util.concurrent.TimeUnit
4+
5+
import javax.inject.{Singleton, _}
6+
import play.api.inject.ApplicationLifecycle
7+
import utils.Configuration
8+
import utils.instancemanagement.InstanceRegistry
9+
10+
import scala.concurrent.duration.Duration
11+
import scala.concurrent.{Await, Future}
12+
import scala.util.{Failure, Success}
13+
14+
/**
15+
* functions that will be run during request
16+
*/
17+
@Singleton
18+
class StartUpService @Inject()(appLifecycle: ApplicationLifecycle){
19+
20+
private val configuration = new Configuration()
21+
22+
/**
23+
* Will register at the Instance Registry, get an matching WebApi instance and try to connect to it using the
24+
* /version endpoint. If successful, it will post the matching result true to the IR, otherwise false.
25+
*/
26+
def doStartUpChecks(): Unit = {
27+
InstanceRegistry.getWebApiVersion(configuration) match {
28+
case Success(_) => {
29+
InstanceRegistry.sendWebApiMatchingResult(true, configuration)
30+
}
31+
case Failure(_) => {
32+
InstanceRegistry.sendWebApiMatchingResult(false, configuration)
33+
//Cannot connect to WebApi on startup, so stop execution
34+
Await.ready(appLifecycle.stop(), Duration(5, TimeUnit.SECONDS))
35+
System.exit(1)
36+
}
37+
}
38+
}
39+
40+
appLifecycle.addStopHook { () =>
41+
InstanceRegistry.deregister(configuration)
42+
Future.successful(())
43+
}
44+
45+
doStartUpChecks()
46+
}

app/utils/AppLogging.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package utils
2+
3+
import akka.actor.{ActorSystem, ExtendedActorSystem}
4+
import akka.event.{BusLogging, LoggingAdapter}
5+
6+
trait AppLogging {
7+
def log(implicit system: ActorSystem): LoggingAdapter = new BusLogging(system.eventStream, this.getClass.getName, this.getClass, system.asInstanceOf[ExtendedActorSystem].logFilter)
8+
}

app/utils/BlockingHttpClient.scala

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package utils
33

44
import akka.actor.ActorSystem
55
import akka.http.scaladsl.Http
6-
import akka.http.scaladsl.model.{HttpMethods, HttpRequest, HttpResponse, Uri}
6+
import akka.http.scaladsl.model.{HttpEntity, HttpMethods, HttpRequest, HttpResponse, MediaTypes, Uri}
77
import akka.stream.{ActorMaterializer, ActorMaterializerSettings}
88
import akka.util.ByteString
99

1010
import scala.concurrent.{Await, Future}
1111
import scala.concurrent.duration.Duration
1212
import scala.util.{Failure, Success, Try}
13+
import MediaTypes._
14+
1315

1416
/***
1517
* A blocking http client implemented using Akka HTTP
@@ -38,11 +40,44 @@ object BlockingHttpClient {
3840

3941
}
4042

43+
// data parameter will be """{"name":"Hello"}"""
44+
def doPost(uri: Uri, data: String) = {
45+
implicit val system = ActorSystem()
46+
implicit val executionContext = system.dispatcher
47+
implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(system))
48+
val bdata = ByteString(data)
49+
try {
50+
val req: Future[HttpResponse] = Http(system).singleRequest(HttpRequest(
51+
method = HttpMethods.POST,
52+
uri = uri,
53+
entity = HttpEntity(`application/json`, bdata)
54+
))
55+
Await.result(req, Duration.Inf)
56+
57+
val f = req.value.get.get.entity.dataBytes.runFold(ByteString(""))(_ ++ _)
58+
Await.result(f, Duration.Inf)
59+
60+
Success(f.value.get.get.utf8String)
61+
} catch {
62+
case e : Exception => Failure(e)
63+
} finally {
64+
system.terminate()
65+
Await.result(system.whenTerminated, Duration.Inf)
66+
}
67+
}
68+
4169
def executeGet(target: String, server: String) : Try[String] = {
4270

4371
val uri = Uri(server)
4472
doGet(uri.withPath(uri.path + target))
4573

4674
}
4775

76+
def executePost(target: String, server: String, data: String) : Try[String] = {
77+
78+
val uri = Uri(server)
79+
doPost(uri.withPath(uri.path + target), data)
80+
81+
}
82+
4883
}

app/utils/Configuration.scala

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package utils
2+
3+
import com.typesafe.config.ConfigFactory
4+
import utils.instancemanagement.InstanceEnums.ComponentType
5+
import utils.instancemanagement.{Instance, InstanceRegistry}
6+
7+
import scala.util.{Failure, Success, Try}
8+
9+
class Configuration(val bindPort: Int = ConfigFactory.load().getInt("app.portWebapp")) {
10+
11+
val defaultWebApiPort : Int = ConfigFactory.load().getInt("webapi.port")
12+
val defaultWebApiHost : String = ConfigFactory.load().getString("webapi.host")
13+
val instanceName = "WebAppInstance"
14+
val instanceRegistryUri : String = sys.env.getOrElse("DELPHI_WEBAPI_URI", ConfigFactory.load().getString("instance.registry.path"))
15+
16+
lazy val webApiUri:String = webApiInstance.host + ":" + webApiInstance.portNumber
17+
18+
lazy val webApiInstance : Instance = InstanceRegistry.retrieveWebApiInstance(this) match {
19+
case Success(instance) => instance
20+
case Failure(_) => Instance(
21+
None,
22+
fallbackWebApiHost,
23+
fallbackWebApiPort,
24+
"Default WebApi instance",
25+
ComponentType.WebApi)
26+
27+
}
28+
29+
lazy val usingInstanceRegistry : Boolean = assignedID match {
30+
case Some(_) => true
31+
case None => false
32+
}
33+
lazy val assignedID : Option[Long] = InstanceRegistry.register(this) match {
34+
case Success(id) => Some(id)
35+
case Failure(_) => None
36+
}
37+
38+
lazy val fallbackWebApiPort : Int = sys.env.get("DELPHI_WEBAPI_URI") match {
39+
case Some(hostString) => if(hostString.count(c => c == ':') == 2){
40+
Try(hostString.split(":")(2).toInt) match {
41+
case Success(port) => port
42+
case Failure(_) => defaultWebApiPort
43+
}
44+
} else {
45+
defaultWebApiPort
46+
}
47+
case None => defaultWebApiPort
48+
}
49+
50+
lazy val fallbackWebApiHost : String = sys.env.get("DELPHI_WEBAPI_URI") match {
51+
case Some(hostString) =>
52+
if(hostString.count(c => c == ':') == 2){
53+
hostString.substring(0,hostString.lastIndexOf(":"))
54+
} else {
55+
defaultWebApiHost
56+
}
57+
case None => defaultWebApiHost
58+
59+
}
60+
}

app/utils/JsonSupport.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package utils
2+
3+
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
4+
import spray.json._
5+
6+
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package utils.instancemanagement
2+
3+
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
4+
import spray.json.{DefaultJsonProtocol, JsString, JsValue, JsonFormat}
5+
6+
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
7+
implicit val componentTypeFormat = new JsonFormat[InstanceEnums.ComponentType] {
8+
def write(compType : InstanceEnums.ComponentType) = JsString(compType.toString)
9+
10+
def read(value: JsValue) = value match {
11+
case JsString(s) => s match {
12+
case "Crawler" => InstanceEnums.ComponentType.Crawler
13+
case "WebApi" => InstanceEnums.ComponentType.WebApi
14+
case "WebApp" => InstanceEnums.ComponentType.WebApp
15+
case "DelphiManagement" => InstanceEnums.ComponentType.DelphiManagement
16+
case "ElasticSearch" => InstanceEnums.ComponentType.ElasticSearch
17+
case x => throw new RuntimeException(s"Unexpected string value $x for component type.")
18+
}
19+
case y => throw new RuntimeException(s"Unexpected type $y while deserializing component type.")
20+
}
21+
}
22+
implicit val instanceFormat = jsonFormat5(Instance)
23+
}
24+
25+
final case class Instance (
26+
id: Option[Long],
27+
host: String,
28+
portNumber: Int,
29+
name: String,
30+
/* Component Type */
31+
componentType: InstanceEnums.ComponentType
32+
33+
)
34+
35+
object InstanceEnums {
36+
37+
type ComponentType = ComponentType.Value
38+
object ComponentType extends Enumeration {
39+
val Crawler = Value("Crawler")
40+
val WebApi = Value("WebApi")
41+
val WebApp = Value("WebApp")
42+
val DelphiManagement = Value("DelphiManagement")
43+
val ElasticSearch = Value("ElasticSearch")
44+
}
45+
46+
}

0 commit comments

Comments
 (0)