soc
soc

Reputation: 28451

How to send messages between Akka remote actors?

I want to build a very simple chat application which should work without some central server using Akka remote actors.

I basically want to start up one instance of the application with IP address A. Then I want to start an instance of the application with IP address A and telling it that the remote instance is at IP address B.

How would I set that that up? The Akka documentation usually covers only client/server use cases and even basic things left me completely confused, e. g. where to use Actor.actorOf vs. Actor.register vs. Actor.remote.

My code looks currently like this:

import collection.mutable.{ArrayBuffer, HashSet}
import akka.actor.Actor

sealed trait Event    
/** Join tells the peer that there is a new peer and 
  * requests a list of known peers and messages. */
case class Join(user: String, ipAddress: String) extends Event
/** Join tells the peer that there is a new peer. */
case class Register(user: String, ipAddress: String) extends Event
case class Leave(user: String, ipAddress: String) extends Event    
case object GetChatLog extends Event
case object GetPeers extends Event
case class ChatLog(log: Seq[Message]) extends Event
case class Peers(peers: Seq[Peer]) extends Event
case class Message(sender: String, time: Long, message: String) extends Event

class ChatPeer(val name: String, ipAddress: String) extends Actor {
  val chat = Actor.remote.actorFor("chat:service", ipAddress, 2552) //This is not what I want...
  val messages = ArrayBuffer[Message]()
  val peers = HashSet[Peer]()

  def join = {
    (chat ? Join(name, ipAddress)).as[(Seq[Peer], Seq[Message])]
  }

  def register = chat ! Register(name, ipAddress)

  def leave = chat ! Leave(name, ipAddress)

  def send(message: String) = {
    val msg = Message(name, System.currentTimeMillis(), message)
    messages += msg
    chat ! msg
  }

  def getMessages = (chat ? GetChatLog).as[ChatLog]
    .getOrElse(throw new Exception("Couldn't get the chat log from ChatServer"))

  def getPeers = (chat ? GetPeers).as[Peers]
    .getOrElse(throw new Exception("Couldn't get the peers from ChatServer"))


  def receive = {
    case msg@Message(from, time, message) =>
      println(msg)
      messages += msg

    case GetChatLog =>
      self reply messages

    case GetPeers =>
      self reply peers

    case Join =>
      peers += Peer(name, ipAddress)
      self reply ((peers, messages))

    case Register(user, ipAddress) =>
      peers += Peer(user, ipAddress)

    case Leave(user, ipAddress) =>
      peers -= Peer(user, ipAddress)

  }
}

case class Peer(name: String, ipAddress: String)

Upvotes: 2

Views: 2542

Answers (1)

Debilski
Debilski

Reputation: 67888

Not sure I understand what you want from your example code.

I think, if you want to make a version without a dedicated server then basically both peers will have to start up and register a remote server

remote.start("localhost", somePort).register("chat-main", actorOf[ChatMain])

and then try to connect to the server of the other peer

val otherActor = remote.actorFor("chat-main", otherHost, somePeer)

Basically you’ll have to make your peers server and client at the same time. The remainder of the setup is some negotiation and chat logic but technically it is not much more complicated than that simple example on the Akka website.

Upvotes: 3

Related Questions