Skip to content

Instantly share code, notes, and snippets.

@justgook
Last active June 22, 2016 21:45
Show Gist options
  • Save justgook/870f42dd91e90c11cf380e23f2149955 to your computer and use it in GitHub Desktop.
Save justgook/870f42dd91e90c11cf380e23f2149955 to your computer and use it in GitHub Desktop.
package actors
/**
* Created by Roman Potashow on 17.06.2016.
*/
import actors.HardwareProtocolsSupportActor.Protocol
import akka.actor.{Actor, ActorLogging, ActorRef, Props}
import gnieh.diffson.playJson._
import play.api.Logger
import play.api.libs.json.Reads._
import play.api.libs.json._
import play.api.mvc.WebSocket.MessageFlowTransformer
class ClientConnectionActor(out: ActorRef, connectionRegistry: ActorRef, hardwareProtocolsSupport: ActorRef) extends Actor with ActorLogging {
import ClientConnectionActor._
override def preStart: Unit = {
connectionRegistry ! self
// hardwareProtocolsSupport ! self
}
//TODO find why it cannot be inside ClientConnectionActor
case class State(patchId: Int = 0, connections: Int = 0, protocols: Option[Seq[Protocol]] = None) {
def withProtocols(p: Seq[Protocol]): State = copy(protocols = Some(p))
def withConnections(c: Int): State = copy(connections = c)
}
object State {
implicit val stateFormat = Json.format[State]
}
private var state = State()
def patchState(old: State, update: State): Unit = {
val patch = JsonDiff.diff(state, update, remember = false)
Logger.info(s"$patch ")
out ! Patch(patch)
state = update
}
def receive = {
case Ping => out ! Pong
case SimpleCommandNoArgs => out ! Fail("not implemented")
case XXX(a) => out ! ZZZ(a)
case YYY(a) => out ! ZZZ(a + " hm-hm-hm")
case Unknown(t) => out ! Fail(s"Unknown type $t")
case c: Int if sender() == connectionRegistry => patchState(state, state.withConnections(c)); out ! Fail(s"$c")
case _ => Logger.warn("ClientConnectionActor got unknown message")
}
}
// Combinator syntax
object ClientConnectionActor {
sealed trait Message
sealed trait In extends Message
case class XXX(a: String) extends In
case class YYY(b: String) extends In
case class Unknown(msg: String) extends In
case object SimpleCommandNoArgs extends In
case object Ping extends In
sealed trait Out extends Message
case class ZZZ(b: String) extends Out
case class Fail(error: String) extends Out
case class Patch(patch: JsonPatch) extends Out //Here is problem play.sbt.PlayExceptions$CompilationException: Compilation error[No implicit format for gnieh.diffson.playJson.JsonPatch available.]
case object Pong extends Out
object Formats {
// in
implicit val xxxReads = Json.reads[XXX]
implicit val yyyReads = Json.reads[YYY]
implicit val inReads = new Reads[In]() {
override def reads(json: JsValue): JsResult[In] = {
def read[T: Reads] = implicitly[Reads[T]].reads((json \ "args").get)
(json \ "type").as[String] match {
case "xxx" => read[XXX]
case "yyy" => read[YYY]
case "simple.command.no.args" => JsSuccess(SimpleCommandNoArgs)
case "ping" => JsSuccess(Ping)
case t => JsSuccess(Unknown(t)) // TODO change it to JsError and find way how send it to client .fold()
}
}
}
// out
implicit val zzzWrites = Json.writes[ZZZ]
implicit val failWrites = Json.writes[Fail]
implicit val patchWrites = Json.writes[Patch]
implicit val outWrites = new Writes[Out] {
override def writes(o: Out): JsValue = {
def write[T: Writes](x: T) = implicitly[Writes[T]].writes(x)
val (t, args) = o match {
case x: ZZZ => ("xxx", Some(write(x)))
case error: Fail => ("fail", Some(write(error)))
case Pong => ("pong", None)
case p: Patch => ("patch", Some(write(p)))
}
Json.obj("type" -> t) ++ {
args.map(args => Json.obj("args" -> args)) getOrElse Json.obj()
}
}
}
implicit val messageFlowTransformer = MessageFlowTransformer.jsonMessageFlowTransformer[In, Out]
}
def props(out: ActorRef, connectionRegistry: ActorRef, hardwareProtocolsSupport: ActorRef) = Props(new ClientConnectionActor(out, connectionRegistry, hardwareProtocolsSupport))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment