Reputation: 28451
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
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