Skip to content

Commit

Permalink
feat: 🎸 automatically reload the page when the content change
Browse files Browse the repository at this point in the history
automatically reload the page when the content change
  • Loading branch information
MaethorNaur committed Sep 23, 2020
1 parent 8c7d0b2 commit 807837c
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 46 deletions.
9 changes: 8 additions & 1 deletion core/src/main/scala/restui/models/Event.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package restui.models
import io.circe.{Encoder, Json}

sealed trait Event {
sealed trait Event extends Product with Serializable {
val id: String
}

object Event {

final case class ServiceUp(id: String, name: String, metadata: Map[String, String] = Map.empty) extends Event
final case class ServiceDown(id: String) extends Event
final case class ServiceContentChanged(id: String) extends Event

implicit val encoder: Encoder[Event] = (event: Event) =>
event match {
Expand All @@ -24,6 +25,12 @@ object Event {
"event" -> Json.fromString("serviceDown"),
"id" -> Json.fromString(id)
)
case ServiceContentChanged(id) =>
Json.obj(
"event" -> Json.fromString("serviceChanged"),
"id" -> Json.fromString(id)
)

}

implicit val listEncoder: Encoder[List[ServiceUp]] = (events: List[ServiceUp]) => Json.arr(events.map(encoder(_)): _*)
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/restui/models/Service.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package restui.models

final case class Service(id: String, name: String, file: String, metadata: Map[String, String] = Map.empty)
final case class Service(id: String, name: String, file: String, metadata: Map[String, String] = Map.empty, hash: String = "")
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class GitSpec extends TestBase with Inside {
Git.fromSource(duration, Source.single(repo)).to(Sink.actorRef(probe.ref, "completed", _ => ())).run()
val result = probe.expectMsgType[Service]
inside(result) {
case Service(_, _, file, _) =>
case Service(_, _, file, _, _) =>
file shouldBe "test"
}
}
Expand All @@ -83,14 +83,14 @@ class GitSpec extends TestBase with Inside {
Git.fromSource(duration, Source.single(repo)).to(Sink.actorRef(probe.ref, "completed", _ => ())).run()

inside(probe.expectMsgType[Service]) {
case Service(_, _, file, _) =>
case Service(_, _, file, _, _) =>
file shouldBe "test"
}

fixture.commit("test", "test2")

inside(probe.expectMsgType[Service]) {
case Service(_, _, file, _) =>
case Service(_, _, file, _, _) =>
file shouldBe "test2"
}

Expand Down
1 change: 1 addition & 0 deletions rest-ui/.eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ plugins:
- react
rules:
"react/prop-types": "off"
"react/display-name": "off"
settings:
react:
version: detect
79 changes: 46 additions & 33 deletions rest-ui/src/main/js/components/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,47 @@ export default class App extends Component {
}

handleEndpoint (data) {
let services
if (data.event === 'serviceUp') {
services = this.state.services
if (!services[data.name]) {
services[data.name] = []
}
let services = this.state.services
switch (data.event) {
case 'serviceUp':
if (!services[data.name]) {
services[data.name] = []
}

if (!services[data.name].find(item => item.id === data.id)) {
services[data.name].push({
id: data.id,
name: data.name,
metadata: data.metadata
})
} else {
services[data.name] = services[data.name].map(service => {
if (service.id !== data.id) return service
else return { id: data.id, name: data.name, metadata: data.metadata }
})
}
} else {
services = Object.entries(this.state.services).reduce(
(obj, [name, services]) => {
const filteredServices = services.filter(item => item.id !== data.id)
if (filteredServices.length) {
obj[name] = filteredServices
}
return obj
},
{}
)
if (!services[data.name].find(item => item.id === data.id)) {
services[data.name].push({
id: data.id,
name: data.name,
metadata: data.metadata
})
} else {
services[data.name] = services[data.name].map(service => {
if (service.id !== data.id) return service
else {
return { id: data.id, name: data.name, metadata: data.metadata }
}
})
}
break
case 'serviceDown':
services = Object.entries(this.state.services).reduce(
(obj, [name, services]) => {
const filteredServices = services.filter(
item => item.id !== data.id
)
if (filteredServices.length) {
obj[name] = filteredServices
}
return obj
},
{}
)
break
case 'serviceChanged':
if (`#/${data.id}` === history.location.hash) {
return history.go(0)
}
break
}
this.setState({ services })
this.search(document.getElementById('search').value)
Expand Down Expand Up @@ -117,7 +128,11 @@ export default class App extends Component {
)
})
} else {
items.push(<h1 key="0" style={{ padding: '0.5em' }}>No services available</h1>)
items.push(
<h1 key="0" style={{ padding: '0.5em' }}>
No services available
</h1>
)
}
return items
}
Expand Down Expand Up @@ -147,9 +162,7 @@ export default class App extends Component {
}

getNavLinkClass (services) {
return services.some(
service => history.location.hash === `#/${service.id}`
)
return services.some(service => history.location.hash === `#/${service.id}`)
? 'active'
: ''
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ object Services {
val response =
(serviceActorRef ? GetAll)
.mapTo[List[Service]]
.map(_.map { case Service(id, name, _, metadata) => Event.ServiceUp(id, name, metadata) })
.map(_.map { case Service(id, name, _, metadata, _) => Event.ServiceUp(id, name, metadata) })
complete(response)
} ~ (path("services" / Remaining) & get) { service =>
val response = (serviceActorRef ? Get(service))
.mapTo[Option[Service]]
.map {
case None => StatusCodes.NotFound -> HttpEntity(ContentTypes.`text/plain(UTF-8)`, s"$service is not registered")
case Some(Service(_, _, content, _)) =>
case Some(Service(_, _, content, _, _)) =>
StatusCodes.OK -> HttpEntity(ContentTypes.`text/plain(UTF-8)`, content)

}
Expand Down
27 changes: 21 additions & 6 deletions rest-ui/src/main/scala/restui/server/service/ServiceActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ class ServiceActor(queue: SourceQueueWithComplete[Event]) extends Actor with Act
sender() ! Ack
case (provider: String, ServiceEvent.ServiceUp(service)) =>
log.debug("{} got a new service", provider)

val serviceNameChanged = hasServiceNameChanged(services, service)
val serviceWithHash = computeSha1(service)
val serviceNameChanged = hasServiceNameChanged(services, serviceWithHash)

if (serviceNameChanged)
queue.offer(Event.ServiceDown(service.id))
queue.offer(Event.ServiceDown(serviceWithHash.id))

if (isNewService(services, serviceWithHash) || serviceNameChanged)
queue.offer(Event.ServiceUp(serviceWithHash.id, serviceWithHash.name, serviceWithHash.metadata))

if (isNewService(services, service) || serviceNameChanged)
queue.offer(Event.ServiceUp(service.id, service.name, service.metadata))
context.become(handleReceive(services + (service.id -> service)))
if (hasContentChanged(services, serviceWithHash))
queue.offer(Event.ServiceContentChanged(serviceWithHash.id))

context.become(handleReceive(services + (serviceWithHash.id -> serviceWithHash)))
sender() ! Ack

case (provider: String, ServiceEvent.ServiceDown(serviceId)) =>
Expand All @@ -44,7 +48,18 @@ class ServiceActor(queue: SourceQueueWithComplete[Event]) extends Actor with Act
id == service.id && currentService.name != service.name
}

private def computeSha1(service: Service): Service = {
val md = java.security.MessageDigest.getInstance("SHA-1")
val sha1Hash = md.digest(service.file.getBytes("UTF-8")).map("%02x".format(_)).mkString
service.copy(hash = sha1Hash)
}

private def isNewService(services: Map[String, Service], service: Service): Boolean = !services.contains(service.id)

private def hasContentChanged(services: Map[String, Service], service: Service): Boolean =
services.exists {
case (id, Service(_, _, _, _, hash)) => id == service.id && hash != service.hash
}
}

object ServiceActor {
Expand Down

0 comments on commit 807837c

Please sign in to comment.