Last active
May 12, 2016 14:13
-
-
Save stanislav-chetvertkov/506c5196a4df56f88cf5c62b308df941 to your computer and use it in GitHub Desktop.
Actors with protocols
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
//Requires scalaz core and shapeless | |
import akka.actor.Actor.Receive | |
import akka.actor._ | |
import shapeless.{Coproduct, :+:, CNil} | |
import scalaz.{Tag, @@} | |
object Test extends App { | |
import scala.reflect.ClassTag | |
trait ActorWithProtocol[T] extends Actor { | |
def process(input: T): Unit | |
override def receive: Receive = { | |
case x => process(x.asInstanceOf[T]) | |
} | |
} | |
type TypedProps[Protocol] = Props @@ ActorProtocol[Protocol] | |
implicit class ProtocolOps[T](it: TypedProps[T]) { | |
def spawnRoot(implicit system: ActorSystem): ActorRef @@ ActorProtocol[T] = { | |
val props: Props = Tag.unwrap(it) | |
val ref: ActorRef = system.actorOf(props) | |
Tag[ActorRef, ActorProtocol[T]](ref) | |
} | |
def spawn(implicit context: ActorContext): ActorRef @@ ActorProtocol[T] = { | |
val props: Props = Tag.unwrap(it) | |
val ref: ActorRef = context.actorOf(props) | |
Tag[ActorRef, ActorProtocol[T]](ref) | |
} | |
} | |
trait ActorProtocol[T] | |
type ISB = Int :+: String :+: Boolean :+: CNil | |
implicit class ProtoOps[T](it: ActorRef @@ ActorProtocol[T]) { | |
def $(message: T)(implicit sender: ActorRef): Unit = { | |
val sendTo: ActorRef = Tag.unwrap(it) | |
sendTo.tell(message, sender) | |
} | |
} | |
//------------------------------// | |
class ActorB extends ActorWithProtocol[ISB] { | |
override def process(input: ISB): Unit = { | |
input.select[Int].foreach { i: Int => | |
println(s"GOT int: $i") | |
} | |
input.select[String].foreach { i: String => | |
println(s"GOT String: $i") | |
} | |
} | |
} | |
object ActorB { | |
def props:TypedProps[ISB] = { | |
Tag[Props, ActorProtocol[ISB]](Props(classOf[ActorB])) | |
} | |
} | |
//------------------------------// | |
class ActorC extends ActorWithProtocol[List[String]] { | |
override def process(input: List[String]): Unit = { | |
println(input) | |
} | |
} | |
object ActorC { | |
def props:TypedProps[List[String]] = { | |
Tag[Props, ActorProtocol[List[String]]](Props(classOf[ActorC])) | |
} | |
} | |
//------------------------------// | |
class MainActor(replyTo: ActorRef @@ ActorProtocol[ISB], | |
replyTo2: ActorRef @@ ActorProtocol[List[String]]) extends Actor { | |
override def preStart(): Unit = { | |
replyTo $ Coproduct[ISB]("123") | |
replyTo2 $ List("first", "second") | |
// will fail | |
// replyTo2 $ Some("123") | |
} | |
override def receive: Receive = { | |
case _ => | |
} | |
} | |
object ActorA { | |
def props(replyTo: ActorRef @@ ActorProtocol[ISB], | |
replyTo2: ActorRef @@ ActorProtocol[List[String]]): Props = { | |
Props(classOf[MainActor], replyTo, replyTo2) | |
} | |
} | |
implicit val system: ActorSystem = ActorSystem() | |
val ref: ActorRef @@ ActorProtocol[ISB] = ActorB.props.spawnRoot | |
val ref2: ActorRef @@ ActorProtocol[List[String]] = ActorC.props.spawnRoot | |
system.actorOf(ActorA.props(ref,ref2)) //untyped | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment