Private Communication between client and server using websockets play 2.3.x - scala

I am newbie to scala and can't figure out sending private message to client using websocket.
Here is my controller:
object Client extends Controller {
def socket(uuid: String) = WebSocket.acceptWithActor[String, String] { request =>
out => ClientWebSocket.props(uuid)
}
// Test Method to send message to websocket connected client
def sendMessage(guid: String) = Action { implicit request =>
val system = ActorSystem("default")
val out = system.actorOf(Props(classOf[ClientWebSocket], guid))
out ! SendUpdate("Message Recieved")
Ok
}
}
Here is my actor class:
object ClientWebSocket {
def props(uuid: String) = Props(new ClientWebSocket(uuid))
case class SendUpdate(msg:String)
}
class ClientWebSocket(uuid: String) extends Actor {
import ClientWebSocket._
def receive = {
case SendUpdate(msg:String) =>
sender ! "Message is " + msg
}
}
When I call sendMessage with uuid of client, I am getting akka dead letters encountered error.
Any help is really appreciated.

First off, in your WebSocket method, you need to use the provided ActorRef instead of sender. sender is probably something else in the hierarchy.
class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
import ClientWebSocket._
def receive = {
case SendUpdate(msg: String) =>
out ! s"Message is $msg"
}
}
Second, you are receiving dead letters in sendMessage because you are replying to your controller, which unfortunately is not an Actor.
The problem is that you cannot get hold of the ActorRef and since you don't know the name of the actor, you cannot use an ActorSelection. So you would need to make a WebSocket call to your own app, call it from web browser / JavaScript or do some hacking with the action to get to the actor.
Edit
Your ClientWebSocket could register (e.g. in preStart via ActorSelection or via an ActorRef as props parameter) with another actor that keeps a Map[String, ActorRef] reference to all websockets and in turn monitors them using death watch. That actor would then forward your SendUpdate to the correct websocket actor. Since you can only return Props in acceptWithActor, you are not able to form a real hierarchy.

The out parameter is an ActorRef, you will use it to send messages to the Client, therefore you need to keep it in your Actor.
object Client extends Controller {
def socket(uuid: String) = WebSocket.acceptWithActor[String, String] { request =>
// out is an actor to what the outbound messages should go to respond to remote client
out => ClientWebSocket.props(uuid, out)
}
}
Your ClientWebSocket actor is as follows:
class ClientWebSocket(uuid: String, out: ActorRef) extends Actor ...
And the companion object is as follows
object ClientWebSocket {
def props(uuid: String, out: ActorRef) = Props(classOf[ClientWebSocket], uuid, out)
}
In the ClientWenSocket you can Register/Deregister the Actor with a CentralWebSocketControl Actor as:
class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
#throws[Exception](classOf[Exception])
override def preStart(): Unit = {
super.preStart()
CentralWebSocketControl.instance ! RegisterMe(uuid)
}
#throws[Exception](classOf[Exception])
override def postStop(): Unit = {
CentralWebSocketControl.instance ! UnregisterMe(uuid)
super.postStop()
}
}
The CentralWebSocketControl Actor can be as:
class CentralWebSocketControl extends Actor {
val clientActors = scala.collection.mutable.HashMap[String, ActorRef]()
override def receive: Actor.Receive = {
case RegisterMe(uuid) =>
clientActors += uuid -> sender()
case UnregisterMe(uuid) =>
clientActors -= uuid
}
}
object CentralWebSocketControl {
val instance = Akka.system.actorOf(Props(classOf[CentralWebSocketControl]), name = "CentralWebSocketControl")
}
To send a message to a given ClientWebSocket identified by an uuid, you can send a message to CentralWebSocketControl that may delegate the message to the registered ClientWebSocket.
class CentralWebSocketControl extends Actor {
val clientActors = scala.collection.mutable.HashMap[String, ActorRef]()
override def receive: Actor.Receive = {
...
case SendUpdateTo(uuid: String, msg: String) =>
clientActors.get(uuid) match {
case Some(actor) =>
actor ! SendUpdate(msg)
case None =>
???
}
}
}
and finally
class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
override def receive: Receive = {
case SendUpdate(msg) =>
out ! msg
}
...
}

Related

unable to create another actor in Akka WebSocket

class HomeController #Inject (implicit actorSystem:ActorSystem, materializer :Materializer) extends Controller
{
case class sendMsg(msg:JsValue)
class MYWSACTOR(out:ActorRef,mainActor:ActorRef) extends Actor
{
def receive =
{
case msg : JsValue =>
mainActor ! sendMsg(msg)
case sendMsg(msg) =>
{
/* validation part */
out ! msg
}
}
}
}
val mainActor = actorSystem.actorOf(Props[MYWSACTOR],"mainActor")
def object MYWSACTOR
{
def props(out:ActorRef) = Props(new MYWSACTOR(out,mainActor))
}
def socket = WebSocket.accept[JsValue,JsValue]
{
request =>
ActorFlow.actorRef(out => MYWSACTOR.props(out))
}
I am new to Akka and Scala . I am trying to make a chat application using Akka in Scala and Play framework 2.5.3 .I used the above code from the official documentation. I just wanted to create another actor (mainActor in above code) so that message from the client is validated first and then be sent back. But the problem is mainActor is unable to send the msg to another class case sendMsg. Also , if i try to create the actor at any different point, it gives me compilation error Unexpected Exception: Provisional Exception
Here is hopefully what you probably wanted:
case class SendMsg(msg: JsValue)
case class ReceivedMessage(wsActor: ActorRef, msg: JsValue)
class MyWsActor(out: ActorRef, mainActor:ActorRef) extends Actor {
def receive = {
case msg : JsValue =>
mainActor ! ReceivedMessage(self, msg)
case SendMsg(msg) =>
out ! msg
}
}
object MyWsActor {
def props(out: ActorRef, mainActor: ActorRef) = Props(new MyWsActor(out, mainActor))
//or if you want to instantiate your Props with reflection
def props2(out: ActorRef, mainActor: ActorRef) = Props(classOf[MyWsActor], out, mainActor)
}
class MainActor() extends Actor {
def receive = {
case ReceivedMessage(wsActor, msg) => {
/*
Do sth with msg
*/
val result = msg
wsActor ! SendMsg(result) //here sender is your MyWsActor
}
}
}
class HomeController #Inject() (
actorSystem: ActorSystem,
materializer: Materializer
) extends Controller {
val mainActor = actorSystem.actorOf(Props[MainActor], "mainActor")
def socket = WebSocket.accept[JsValue,JsValue] {
request =>
ActorFlow.actorRef(out => MyWsActor.props(out, mainActor))
}
}
The key is that you can send, with actual message, also ActorRef (or by default you can get a sender ActorRef calling sender()) and then you can replay to this ActorRef.

Expect message on mocked actor when testing with TestKit

I am trying to test an actor, that depends on another actor. In the following test ActorA sends MessageA to ActorB and expects a MessageB in return.
Since this is a Unit test for ActorB, I am mocking ActorA. My problem now is, that i want to be sure that ActorA gets MessageA, but when i call the expectMsg (see the commented line) the whole autopilot does not seem to work anymore.
Am I doing something wrong here?
class MyTest(_system: ActorSystem) extends TestKit(_system)
with WordSpecLike
with BeforeAndAfterAll {
object Start
object MessageA
object MessageB
def this() = this(ActorSystem("TestSpec"))
override def afterAll() {
system.shutdown()
}
// will later be mocked
class ActorA extends Actor {
def receive = {
case MessageA => sender() ! MessageB
}
}
class ActorB(actorA: ActorRef) extends Actor {
def receive = {
case Start => actorA ! MessageA
case MessageB => println("Got MessageB")
}
}
"" should {
"work" in {
val actorA = TestProbe()
actorA.setAutoPilot(new AutoPilot {
override def run(sender: ActorRef, msg: Any): AutoPilot = {
msg match {
case MessageA => sender ! MessageB
}
TestActor.KeepRunning
}
})
// this will break the test
//actorA.expectMsg(MessageA)
val actor = system.actorOf(Props(new ActorB(actorA.ref)))
actor ! Start
}
}
}
You should expect MessageA after sending start to your ActorB.
val actor = system.actorOf(Props(new ActorB(actorA.ref)))
actor ! Start
// this will not break the test
actorA.expectMsg(MessageA)

How to mock an Akka Actor to Unit Test a class?

I have a Controller class which controls the requests sent to a Akka actor which is injected in to the controller.
Controller's code:
class Controller(actor: ActorRef) {
def control(msg: String): Future[String] = {
actor.ask(msg)(Timeout(2 seconds)).mapTo[String]
}
}
And my Actor's code is:
class ActorA extends Actor {
override def receive: Receive = {
case msg: String => sender ! msg
case msg: Int => sender ! msg.toString
case _ => "Invalid command!"
}
Now I need to mock ActorA's behaviour to unit test Controller. Is there a way to do so via Akka TestKit ?
Use a TestProbe. From the testing documentation:
val probe = TestProbe()
val future = probe.ref ? "hello"
probe.expectMsg(0 millis, "hello")
probe.reply("world")
assert(future.isCompleted && future.value == Some(Success("world")))

How could actor know if it has all the responses it needs in order to proceed?

I am fairly new to akka and not sure about approaching this problem.
I have a Monitor actor that spawns 2 other actors as DiskMonitor and MemoryMonitor
DiskMonitor checks the diskUsage and report DiskReport message
MemoryMonitor checks the diskUsage and report MemoryReport message
I want to combine the DiskReport and MemoryReport into Report Object and send to to remote machine via an API.
Questions
Since DiskMonitor and MemoryMonitor both are actors they send the response back to caller once they are done with their work
Monitor
diskMonitor ! DiskMonitorRequest
memoryMonitor ! MemoryMonitorRequest
How would Monitor know that it has all the results that it needs so that it can create Report object and send it via API?
Are actors good way to approach this problem?
I also read about future but I don't understand them well and not sure if they would be helpful in this problem context
This is a simple way of doing these things. Other options can be through using context.become or the trait FSM.
class Monitor extends Actor {
// Somewhere do this:
diskMonitor ! DiskMonitorRequest
memoryMonitor ! MemoryMonitorRequest
var diskMonitorResult = Option.empty[DiskMonitor]
var memoryMonitorResult = Option.empty[MemoryMonitor]
def recieve = {
case d: DiskMonitor =>
diskMonitorResult = Some(d)
checkIfCompleted()
case m: MemoryMonitor =>
memoryMonitorResult = Some(m)
checkIfCompleted()
}
def checkIfCompleted = {
(diskMonitorResult, memoryMonitorResult) match {
case (Some(diskMonitor), Some(memoryMonitor)) =>
// send to external API
externalApi ! Report(diskMonitor, memoryMonitor)
// Possibly stop this actor
case _ => // do nothing
}
}
}
You can use ask pattern and combine futures..
import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.ExecutionContextExecutor
import scala.concurrent.duration._
import scala.language.postfixOps
class Monitor extends Actor with ActorLogging {
implicit val timeout: Timeout = Timeout(5 seconds)
implicit val ec: ExecutionContextExecutor = context.dispatcher
val diskM: ActorRef = context.system.actorOf(Props[DiskMonitor])
val memoryM: ActorRef = context.system.actorOf(Props[MemoryMonitor])
val remoteM: ActorRef = context.system.actorOf(Props[RemoteMachine])
override def preStart: Unit = {
log.info("Monitor Created..")
self ! GenerateReport
}
override def receive: Receive = {
case GenerateReport =>
(diskM ? MakeDiskReport).mapTo[DiskReport].zip((memoryM ? MakeMemoryReport)
.foreach { case (diskR, memR) =>
remoteM ! Report(memR.report, diskR.report)
}
}
}
class DiskMonitor extends Actor with ActorLogging {
override def receive: Receive = {
case MakeDiskReport =>
log.info("Creating DiskReport..")
val client = sender
client ! DiskReport("DiskReport")
}
}
class MemoryMonitor extends Actor with ActorLogging {
override def receive: Receive = {
case MakeMemoryReport =>
log.info("Creating MemoryReport..")
val client = sender
client ! MemoryReport("MemoryReport")
}
}
class RemoteMachine extends Actor with ActorLogging {
override def receive: Receive = {
case Report(memr, diskr) =>
log.info(s"Final Report.. $memr, $diskr")
}
}
object Main extends App {
val sys = ActorSystem()
sys.actorOf(Props[Monitor])
}
sealed trait Message
case object GenerateReport extends Message
case object MakeDiskReport extends Message
case object MakeMemoryReport extends Message
case class DiskReport(report: String) extends Message
case class MemoryReport(report: String) extends Message
case class Report(memReport: String, diskReport: String) extends Message

Composing trait behavior in Scala in an Akka receive method

Consider these two traits:
trait Poked extends Actor {
override def receive = {
case Poke(port, x) => ReceivePoke(port, x)
}
def ReceivePoke(port: String, x: Any)
}
trait Peeked extends Actor {
override def receive = {
case Peek(port) => ReceivePeek(port)
}
def ReceivePeek(port: String)
}
Now consider I can create a new Actor that implements both traits:
val peekedpoked = actorRef(new Actor extends Poked with Peeked)
How do I compose the receive handlers? i.e., the receiver should be something like the following code, though "automatically generated" (i.e., all traits should compose):
def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
You can use super[T] to reference members of particular super classes/traits.
For example:
trait IntActor extends Actor {
def receive = {
case i: Int => println("Int!")
}
}
trait StringActor extends Actor {
def receive = {
case s: String => println("String!")
}
}
class IntOrString extends Actor with IntActor with StringActor {
override def receive = super[IntActor].receive orElse super[StringActor].receive
}
val a = actorOf[IntOrString].start
a ! 5 //prints Int!
a ! "Hello" //prints String!
Edit:
In response to Hugo's comment, here's a solution that allows you to compose the mixins without having to manually wire their receives together. Essentially it involves a base trait with a mutable List[Receive], and each mixed-in trait calls a method to add its own receive to the list.
trait ComposableActor extends Actor {
private var receives: List[Receive] = List()
protected def registerReceive(receive: Receive) {
receives = receive :: receives
}
def receive = receives reduce {_ orElse _}
}
trait IntActor extends ComposableActor {
registerReceive {
case i: Int => println("Int!")
}
}
trait StringActor extends ComposableActor {
registerReceive {
case s: String => println("String!")
}
}
val a = actorOf(new ComposableActor with IntActor with StringActor).start
a ! 5 //prints Int!
a ! "test" //prints String!
The only thing to keep in mind is that the order of the receives should not be important, since you won't be able to easily predict which one is first in the chain, though you could solve that by using a mutable hashmap instead of a list.
You can use empty Receive in base actor class and chain receives in their definitions.
Sample for Akka 2.0-M2:
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
class Logger extends Actor {
val log = Logging(context.system, this)
override def receive = new Receive {
def apply(any: Any) = {}
def isDefinedAt(any: Any) = false
}
}
trait Errors extends Logger {
override def receive = super.receive orElse {
case "error" => log.info("received error")
}
}
trait Warns extends Logger {
override def receive = super.receive orElse {
case "warn" => log.info("received warn")
}
}
object Main extends App {
val system = ActorSystem("mysystem")
val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
actor ! "error"
actor ! "warn"
}