Last active
June 22, 2016 21:45
-
-
Save justgook/870f42dd91e90c11cf380e23f2149955 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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