Search code examples
scalawebsocketakka-streamakka-http

Akka-http: connect to websocket on localhost


I am trying to connect to some server through websocket on localhost. When I try to do it in JS by

ws = new WebSocket('ws://localhost:8137');

it succeeds. However, when I use akka-http and akka-streams I get "connection failed" error.

object Transmitter {
    implicit val system: ActorSystem = ActorSystem()
    implicit val materializer: ActorMaterializer = ActorMaterializer()

    import system.dispatcher

    object Rec extends Actor {
        override def receive: Receive = {
            case TextMessage.Strict(msg) =>
                Log.info("Recevied signal " + msg)
        }
    }

    //  val host = "ws://echo.websocket.org"
    val host = "ws://localhost:8137"

    val sink: Sink[Message, NotUsed] = Sink.actorRef[Message](system.actorOf(Props(Rec)), PoisonPill)


    val source: Source[Message, NotUsed] = Source(List("test1", "test2") map (TextMessage(_)))


    val flow: Flow[Message, Message, Future[WebSocketUpgradeResponse]] =
        Http().webSocketClientFlow(WebSocketRequest(host))

    val (upgradeResponse, closed) =
        source
        .viaMat(flow)(Keep.right) // keep the materialized Future[WebSocketUpgradeResponse]
        .toMat(sink)(Keep.both) // also keep the Future[Done]
        .run()

    val connected: Future[Done.type] = upgradeResponse.flatMap { upgrade =>
        if (upgrade.response.status == StatusCodes.SwitchingProtocols) {
            Future.successful(Done)
        } else {
            Future.failed(new Exception(s"Connection failed: ${upgrade.response.status}")
        }
    }

    def test(): Unit = {
        connected.onComplete(Log.info)
    }
}

It works completely OK with ws://echo.websocket.org.

I think attaching code of my server is reasonless, because it works with JavaScript client and problem is only with connection, however if you would like to look at it I may show it.

What am I doing wrong?


Solution

  • I found the solution: the server I used was running on IPv6 (as ::1), but akka-http treats localhost as 127.0.0.1 and ignores ::1. I had to rewrite server to force it to use IPv4 and it worked.