Skip to content

Commit

Permalink
Fixes #21821: Refactor without trait
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceMacBuche committed Oct 24, 2022
1 parent 7b4eae3 commit 15797af
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ trait CampaignEventRepository {
def deleteEvent(
id: Option[CampaignEventId] = None,
states: List[String] = Nil,
campaignType: Option[CampaignType] = None,
campaignType: Option[String] = None,
campaignId: Option[CampaignId] = None,
afterDate: Option[DateTime] = None,
beforeDate: Option[DateTime] = None
Expand All @@ -69,7 +69,7 @@ trait CampaignEventRepository {
*/
def getWithCriteria(
states: List[String] = Nil,
campaignType: Option[CampaignType] = None,
campaignType: Option[String] = None,
campaignId: Option[CampaignId] = None,
limit: Option[Int] = None,
offset: Option[Int] = None,
Expand All @@ -91,8 +91,7 @@ class CampaignEventRepositoryImpl(doobie: Doobie, campaignSerializer: CampaignSe

implicit val eventWrite: Write[CampaignEvent] = {
Write[(String, String, String, CampaignEventState, DateTime, DateTime, String)].contramap {
case event =>
(event.id.value, event.campaignId.value, event.name, event.state, event.start, event.end, event.campaignType.value)
case event => (event.id.value, event.campaignId.value, event.name, event.state, event.start, event.end, event.campaignType)
}
}

Expand All @@ -106,7 +105,7 @@ class CampaignEventRepositoryImpl(doobie: Doobie, campaignSerializer: CampaignSe
d._4,
d._5,
d._6,
campaignSerializer.campaignType(d._7)
d._7
)
}
}
Expand All @@ -119,7 +118,7 @@ class CampaignEventRepositoryImpl(doobie: Doobie, campaignSerializer: CampaignSe

def getWithCriteria(
states: List[String] = Nil,
campaignType: Option[CampaignType] = None,
campaignType: Option[String] = None,
campaignId: Option[CampaignId] = None,
limit: Option[Int] = None,
offset: Option[Int] = None,
Expand All @@ -131,7 +130,7 @@ class CampaignEventRepositoryImpl(doobie: Doobie, campaignSerializer: CampaignSe

import cats.syntax.list._
val campaignIdQuery = campaignId.map(c => fr"campaignId = ${c.value}")
val campaignTypeQuery = campaignType.map(c => fr"campaignType = ${c.value}")
val campaignTypeQuery = campaignType.map(c => fr"campaignType = ${c}")
val stateQuery = states.toNel.map(s => Fragments.in(fr"state->>'value'", s))
val afterQuery = afterDate.map(d => fr"endDate >= ${new java.sql.Timestamp(d.getMillis)}")
val beforeQuery = beforeDate.map(d => fr"startDate <= ${new java.sql.Timestamp(d.getMillis)}")
Expand Down Expand Up @@ -174,7 +173,7 @@ class CampaignEventRepositoryImpl(doobie: Doobie, campaignSerializer: CampaignSe
def deleteEvent(
id: Option[CampaignEventId] = None,
states: List[String] = Nil,
campaignType: Option[CampaignType] = None,
campaignType: Option[String] = None,
campaignId: Option[CampaignId] = None,
afterDate: Option[DateTime] = None,
beforeDate: Option[DateTime] = None
Expand All @@ -183,7 +182,7 @@ class CampaignEventRepositoryImpl(doobie: Doobie, campaignSerializer: CampaignSe
import cats.syntax.list._
val eventIdQuery = id.map(c => fr"eventId = ${c.value}")
val campaignIdQuery = campaignId.map(c => fr"campaignId = ${c.value}")
val campaignTypeQuery = campaignType.map(c => fr"campaignType = ${c.value}")
val campaignTypeQuery = campaignType.map(c => fr"campaignType = ${c}")
val stateQuery = states.toNel.map(s => Fragments.in(fr"state->>'value'", s))
val afterQuery = afterDate.map(d => fr"endDate >= ${new java.sql.Timestamp(d.getMillis)}")
val beforeQuery = beforeDate.map(d => fr"startDate <= ${new java.sql.Timestamp(d.getMillis)}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ import zio.json.jsonField
import zio.json.jsonHint

case class CampaignParsingInfo(
campaignType: CampaignType,
campaignType: String,
version: Int
)

trait Campaign {
def info: CampaignInfo
def details: CampaignDetails
def campaignType: CampaignType
def copyWithId(newId: CampaignId): Campaign
def version: Int
def campaignType: String
def version: Int
def copyWithId(campaignId: CampaignId): Campaign
}

case class CampaignInfo(
Expand Down Expand Up @@ -156,16 +156,14 @@ case class OneShot(start: DateTime, end: DateTime) extends CampaignSchedule

trait CampaignDetails

case class CampaignType(value: String)

case class CampaignEvent(
id: CampaignEventId,
campaignId: CampaignId,
name: String,
state: CampaignEventState,
start: DateTime,
end: DateTime,
campaignType: CampaignType
campaignType: String
)
case class CampaignEventId(value: String)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
package com.normation.rudder.campaigns

import com.normation.errors._
import com.normation.errors.Inconsistency
import com.normation.errors.IOResult
import com.normation.utils.DateFormaterService
import org.joda.time.DateTime
Expand All @@ -49,59 +48,43 @@ import zio.json.EncoderOps
import zio.json.JsonDecoder
import zio.json.JsonEncoder
import zio.json.ast.Json
import zio.syntax._

trait JSONTranslateCampaign {

def getRawJson(): PartialFunction[Campaign, IOResult[Json]]
def getRawJson(campaign: Campaign): IOResult[Json]

// serialize the campaign based on its campaignType
def handle(pretty: Boolean) = getRawJson().andThen(r => r.map(json => if (pretty) json.toJsonPretty else json.toJson))
def handle(pretty: Boolean, campaign: Campaign) =
getRawJson(campaign).map(json => if (pretty) json.toJsonPretty else json.toJson)

def read(): PartialFunction[(String, CampaignParsingInfo), IOResult[Campaign]]
def read(json: String, parsingInfo: CampaignParsingInfo): IOResult[Campaign]

def campaignType(): PartialFunction[String, CampaignType]
}

class CampaignSerializer {

private[this] var tranlaters: List[JSONTranslateCampaign] = Nil
private[this] var tranlaters: Map[String, JSONTranslateCampaign] = Map.empty
import CampaignSerializer._

def getJson(campaign: Campaign) = {
tranlaters.map(_.getRawJson()).fold(Jsonbase) { case (a, b) => b orElse a }(campaign).flatMap { json =>
CampaignParsingInfo(campaign.campaignType, campaign.version).toJsonAST.toIO.map(json.merge)

}
}

val Jsonbase: PartialFunction[Campaign, IOResult[Json]] = {
case c: Campaign => Inconsistency(s"No translater for campaign ${c.info.id.value}").fail
getTranslater(campaign.campaignType)
.flatMap(_.getRawJson(campaign))
.flatMap(json => CampaignParsingInfo(campaign.campaignType, campaign.version).toJsonAST.toIO.map(json.merge))
}

val base: PartialFunction[Campaign, IOResult[String]] = {
case c: Campaign => Inconsistency(s"No translater for campaign ${c.info.id.value}").fail
}

val readBase: PartialFunction[(String, CampaignParsingInfo), IOResult[Campaign]] = {
case (_, v) => Inconsistency(s"could not translate into campaign of type ${v.campaignType.value} version ${v.version}").fail
}

val campaignTypeBase: PartialFunction[String, CampaignType] = { case c: String => CampaignType(c) }

def addJsonTranslater(c: JSONTranslateCampaign) = tranlaters = c :: tranlaters
def addJsonTranslater(campaignType: String, c: JSONTranslateCampaign) = tranlaters = tranlaters + ((campaignType, c))

def serialize(campaign: Campaign): IOResult[String] = getJson(campaign).map(_.toJsonPretty)
def parse(string: String): IOResult[Campaign] = {
def getTranslater(campaignType: String): IOResult[JSONTranslateCampaign] =
tranlaters.get(campaignType).notOptional(s"No Json translator found for campaign type ${campaignType}")
def serialize(campaign: Campaign): IOResult[String] = getJson(campaign).map(_.toJsonPretty)
def parse(string: String): IOResult[Campaign] = {
for {
baseInfo <- string.fromJson[CampaignParsingInfo].toIO
res <- tranlaters.map(_.read()).fold(readBase) { case (a, b) => b orElse a }((string, baseInfo))
baseInfo <- string.fromJson[CampaignParsingInfo].toIO
translater <- getTranslater(baseInfo.campaignType)
res <- translater.read(string, baseInfo)
} yield {
res
}
}
def campaignType(string: String): CampaignType =
tranlaters.map(_.campaignType()).fold(campaignTypeBase) { case (a, b) => b orElse a }(string)

}

Expand Down Expand Up @@ -159,14 +142,12 @@ object CampaignSerializer {
implicit val statusInfoDecoder: JsonDecoder[CampaignStatus] = DeriveJsonDecoder.gen
implicit val dayTimeDecoder: JsonDecoder[DayTime] = DeriveJsonDecoder.gen
implicit val scheduleDecoder: JsonDecoder[CampaignSchedule] = DeriveJsonDecoder.gen
implicit val campaignTypeDecoder: JsonDecoder[CampaignType] = JsonDecoder[String].map(CampaignType)
implicit val campaignInfoDecoder: JsonDecoder[CampaignInfo] = DeriveJsonDecoder.gen

implicit val campaignEventIdDecoder: JsonDecoder[CampaignEventId] = JsonDecoder[String].map(CampaignEventId)
implicit val campaignEventStateDecoder: JsonDecoder[CampaignEventState] = DeriveJsonDecoder.gen
implicit val campaignEventDecoder: JsonDecoder[CampaignEvent] = DeriveJsonDecoder.gen

implicit val campaignTypeEncoder: JsonEncoder[CampaignType] = JsonEncoder[String].contramap(_.value)
implicit val campaignEventIdEncoder: JsonEncoder[CampaignEventId] = JsonEncoder[String].contramap(_.value)
implicit val campaignEventStateEncoder: JsonEncoder[CampaignEventState] = DeriveJsonEncoder.gen
implicit val campaignEventEncoder: JsonEncoder[CampaignEvent] = DeriveJsonEncoder.gen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@
package com.normation.rudder.campaigns

import cats.implicits._
import com.normation.errors.Inconsistency
import com.normation.errors.IOResult
import com.normation.errors.RudderError
import com.normation.utils.DateFormaterService
import com.normation.utils.StringUuidGenerator
import com.normation.zio.ZioRuntime
Expand All @@ -53,7 +51,7 @@ import zio.duration._
import zio.syntax._

trait CampaignHandler {
def handle(mainCampaignService: MainCampaignService, event: CampaignEvent): PartialFunction[Campaign, IOResult[CampaignEvent]]
def handle(campaign: Campaign, mainCampaignService: MainCampaignService, event: CampaignEvent): IOResult[CampaignEvent]
}

object MainCampaignService {
Expand All @@ -67,12 +65,16 @@ object MainCampaignService {

class MainCampaignService(repo: CampaignEventRepository, campaignRepo: CampaignRepository, uuidGen: StringUuidGenerator) {

private[this] var services: List[CampaignHandler] = Nil
def registerService(s: CampaignHandler) = {
services = s :: services
private[this] var services: Map[String, CampaignHandler] = Map()
def registerService(campaignType: String, s: CampaignHandler) = {
services = services + ((campaignType, s))
init()
}

import com.normation.errors._
def getService(campaignType: String): IOResult[CampaignHandler] =
services.get(campaignType).notOptional(s"No campaign service found for campaign type ${campaignType}")

private[this] var inner: Option[CampaignScheduler] = None

def saveCampaign(c: Campaign) = {
Expand Down Expand Up @@ -100,34 +102,33 @@ class MainCampaignService(repo: CampaignEventRepository, campaignRepo: CampaignR
}
}

def handle(eventId: CampaignEventId) = {
@nowarn
def failingLog(eventId: CampaignEventId)(err: RudderError) = {
for {
_ <- CampaignLogger.error(
s"An error occurred while treating campaign event ${eventId.value}, error details : ${err.fullMsg} "
)
_ <- err.fail
} yield {
()
}
}

def base(event: CampaignEvent): PartialFunction[Campaign, IOResult[CampaignEvent]] = { case _ => event.succeed }
def wait(eventId: CampaignEventId) = {

val now = DateTime.now()

@nowarn
def failingLog(err: RudderError) = {
for {
_ <- CampaignLogger.error(
s"An error occurred while treating campaign event ${eventId.value}, error details : ${err.fullMsg} "
)
_ <- err.fail
} yield {
()
}
}
(for {

event <- repo.get(eventId)
campaign <- campaignRepo.get(event.campaignId)
_ <- CampaignLogger.debug(s"Got Campaign ${event.campaignId.value} for event ${event.id.value}")

_ <- CampaignLogger.debug(s"Start handling campaign event '${event.id.value}' state is ${event.state.value}")
wait <-
_ <- CampaignLogger.debug(s"Start handling campaign event '${event.id.value}' state is ${event.state.value}")
wait <-
event.state match {
case Finished | Skipped(_) =>
().succeed
handle(event)
case Scheduled =>
campaign.info.status match {
case Disabled(reason) =>
Expand All @@ -149,12 +150,13 @@ class MainCampaignService(repo: CampaignEventRepository, campaignRepo: CampaignR
.serialize(event.start)}"
)
_ <- ZIO.sleep(Duration.fromMillis(event.start.getMillis - now.getMillis))
_ <- handle(event)
} yield {
().succeed
}
} else {
CampaignLogger.debug(
s"${event.id.value} should be treated by ${event.campaignType.value} handler for Scheduled state"
s"${event.id.value} should be treated by ${event.campaignType} handler for Scheduled state"
)
}
}
Expand Down Expand Up @@ -183,38 +185,42 @@ class MainCampaignService(repo: CampaignEventRepository, campaignRepo: CampaignR
.serialize(event.end)}"
)
_ <- ZIO.sleep(Duration.fromMillis(event.end.getMillis - now.getMillis))
_ <- handle(event)
} yield {
()
}
} else {
CampaignLogger.debug(
s"${event.id.value} should be treated by ${event.campaignType.value} handler for Running state"
)
CampaignLogger.debug(s"${event.id.value} should be treated by ${event.campaignType} handler for Running state")
}
}
} yield {
event
}).provide(zclock).catchAll(failingLog(eventId))
}

// Get updated event and campaign, state of the event could have changed, campaign parameter also
def handle(event: CampaignEvent) = {
// Get updated event and campaign, state of the event could have changed, campaign parameter also
(for {
updatedEvent <- repo.get(event.id)
updatedCampaign <- campaignRepo.get(event.campaignId)
_ <- CampaignLogger.debug(s"Got Updated campaign and event for event ${event.id.value}")

handle =
services.map(_.handle(main, updatedEvent)).foldLeft(base(updatedEvent)) { case (base, handler) => handler orElse base }
newCampaign <- handle
.apply(updatedCampaign)
.catchAll(err => {
for {
_ <- CampaignLogger.error(err.fullMsg)
} yield {
event
newCampaign <- getService(updatedCampaign.campaignType).flatMap { handler =>
handler
.handle(updatedCampaign, main, updatedEvent)
.catchAll(err => {
for {
_ <- CampaignLogger.error(err.fullMsg)
} yield {
event
}
})
}
})
_ <-
_ <-
CampaignLogger.debug(
s"Campaign event ${newCampaign.id.value} update, previous state was ${event.state.value} new state${newCampaign.state.value}"
)
save <- repo.saveCampaignEvent(newCampaign)
post <-
save <- repo.saveCampaignEvent(newCampaign)
post <-
newCampaign.state match {
case Finished | Skipped(_) =>
for {
Expand All @@ -232,14 +238,13 @@ class MainCampaignService(repo: CampaignEventRepository, campaignRepo: CampaignR
}
} yield {
()
}).provide(zclock).catchAll(failingLog)

}).catchAll(failingLog(event.id))
}

def loop() = {
for {
c <- queue.take
_ <- handle(c).forkDaemon
_ <- wait(c).forkDaemon
} yield {
()
}
Expand Down
Loading

0 comments on commit 15797af

Please sign in to comment.