我刚刚开始使用Akka和Scala,我尝试使用Akka Streams连接到WebSocket。我在下面创建了我的SocketActor
,并尝试从main方法实例化。
这是我的package com.lightbend.akka.sample
import akka.actor.{Actor, Props}
import akka.Done
import akka.http.scaladsl.Http
import akka.stream.scaladsl._
import akka.http.scaladsl.model.ws._
import scala.concurrent.Future
object SocketActor {
def props(coinApiIdentifier: String): Props = Props(new SocketActor(coinApiIdentifier))
case object Start
case object Stop
}
class SocketActor(val ticker: String) extends Actor {
import SocketActor._
// Future[Done] is the materialized value of Sink.foreach,
// emitted when the stream completes
private val incoming: Sink[Message, Future[Done]] =
Sink.foreach[Message] {
case message: TextMessage.Strict =>
println(message.text)
}
// send this as a message over the WebSocket
private val outgoing = Source.single(TextMessage("hello world!"))
// flow to use (note: not re-usable!)
private val webSocketFlow = Http().webSocketClientFlow(WebSocketRequest("wss://api.com/v1/"))
// the materialized value is a tuple with
// upgradeResponse is a Future[WebSocketUpgradeResponse] that
// completes or fails when the connection succeeds or fails
// and closed is a Future[Done] with the stream completion from the incoming sink
private val graph =
outgoing
.viaMat(webSocketFlow)(Keep.right) // keep the materialized Future[WebSocketUpgradeResponse]
.toMat(incoming)(Keep.both) // also keep the Future[Done]
override def receive: PartialFunction[Any, Unit] = {
case Start =>
println("Start message received.")
graph.run()
}
}
:
object AkkaQuickstart extends App {
// Create the 'helloAkka' actor system
val system: ActorSystem = ActorSystem("test")
val materializer: ActorMaterializer = ActorMaterializer()
val socketActor: ActorRef =
system.actorOf(SocketActor.props("hello"), "socket-actor")
socketActor ! Start
}
我的主要方法:
implicit
不幸的是,我收到错误:
错误:(38,35)找不到参数系统的隐含值: akka.actor.ActorSystem private val webSocketFlow = HTTP().webSocketClientFlow(WebSocketRequest(" WSS://api.com/v1/"))
我已经尝试将一些SocketActor
参数传递给ActorSystem
的构造函数,但这样做效果不佳。似乎system
由于某种原因不在范围内。如何在Http()
中获取SocketActor
功能的{{1}}范围?
答案 0 :(得分:4)
定义隐式val
:
class SocketActor(val ticker: String) extends Actor {
implicit val sys = context.system
// ...
}
这将提供ActorSystem
对象所期望的隐式Http
。
您的代码还有另一个问题:您的actor中的流将无法运行,因为范围中没有物化器。解决这个问题的一种方法是在actor中创建一个物质化器:
class SocketActor(val ticker: String) extends Actor {
implicit val sys = context.system
implicit val mat = ActorMaterializer()(context)
// ...
}
请注意,如果将投影仪定义为implicit val mat = ActorMaterializer()
,则由于context.system
,它会隐式使用implicit val sys = context.system
。相反,使用actor context
显式创建了Materializer。这是因为documentation:
不要通过将
context.system
传递给actor来在actor中创建新的actor实现器。这将导致为每个这样的actor创建一个新的ActorMaterializer
并可能泄露(除非你明确地将其关闭)。相反,建议传入Materializer或使用actor的context
创建一个。
推荐的方法允许actor的创建者重用一个物化器,它将物化器作为隐式参数传递给actor:
class SocketActor(val ticker: String)(implicit val mat: ActorMaterializer) extends Actor {
implicit val sys = context.system
// ...
}
然后你可以将主程序中的物化器传递给这个actor:
object AkkaQuickstart extends App {
implicit val system: ActorSystem = ActorSystem("test")
implicit val materializer: ActorMaterializer = ActorMaterializer()
val socketActor: ActorRef =
system.actorOf(Props(classOf[SocketActor], "hello", materializer), "socket-actor")
socketActor ! Start
}