Javascript WebSocket not connecting to Scala server - scala

I am trying to implement a real-time game server in Scala, but I have a problem connecting to it with javascript's WebSocket. I tryed connecting with websocket.org/echo.html using either ws://localhost:8888, ws://127.0.0.1:8888 or ws://[my ip]:8888 .
Here's my server code, whch is pretty much the example from Akka's doc:
class MyServer(port: Int) extends Actor with ActorLogging{
var address: InetSocketAddress = new InetSocketAddress("", port)
var socketServer: ServerHandle = IOManager(context.system).listen(address)
override def receive = {
//Fired when the server is listening
case Listening(server, add) =>
log.info(s"The server is now listening on $add.")
//When a new client connect to the server...
case NewClient(server) =>
log.info("A new client just connected !")
server.accept()
//When a message is received by the server
case Read(socket, bytes) =>
log.info("The server just received some data.")
log.info(bytes.decodeString("US-ASCII"))
//When a connection with a client is closed
case Closed(socket, cause) =>
log.info(s"A client just disconnected : $cause")
}
}
object GemsApplication extends App{
println("Starting Gems application !")
val port = Option(System.getenv("PORT")).map(_.toInt).getOrElse(8888)
println(s"Selected port is $port.")
ActorSystem().actorOf(Props( new MyServer(port) ))
}
The odd thing is that I can connect to my server using Python sockets. Since they are may more low-level I'm guessing that I'll have to implement the handshake response to make it work with WebSocket, but shouldn't I see the message from the web socket asking for upgrade ? or even just connecting ?
Thanks for any insight you might have
Robin

Related

Reload certificates server at runtime

Is it possible to reload at runtime certificates in a web server using API of Akka-HTTP? I would that the HttpsConnectionContext is reloaded without shutdown of server. Is there a way to do that? I've already implemented a mechanism that read the renew of certificate but my problem is to reload the context at runtime.
Below I show how my server is started:
log.info("HTTPS ENABLED!")
val https: HttpsConnectionContext = newHttpsConnectionContext()
val (host, port, connectionContext) = ("0.0.0.0", 8080, https)
log.debug(s" Binding RESTful Web Services ... https://$host:$port/")
val bindingFuture =
Http().bindAndHandle(
endpoints,
host,
port,
connectionContext
)
bindingFuture.onComplete {
case Success(bind) =>
log.info(s"HTTPS server binding $bind")
binding = Some(bind)
log.warn(
s" Service online at https://$host:$port/"
)
case Failure(ex) =>
log.error(
s" Failed to bind to https://$host:$port/ - Error : ${ex.getMessage}"
)
close()
}
}
def newHttpsConnectionContext(): HttpsConnectionContext = {
import myService.TlsSettings
log.debug(
s"Creating a new HTTPS Connection Context between my Service (Server) and Clients..."
)
val sslParameters: Option[SSLParameters] = None
val sslConnectionContext: HttpsConnectionContext =
ConnectionContext.https(
TlsSettings(
ApplicationProperties.clientCert,
ApplicationProperties.clientPrivKey
).sslContext,
None,
Some(SSL_CIPHER_SUITES),
Some(SSL_PROTOCOLS),
Some(TLSClientAuth.Need),
sslParameters
)
log.info(
s"HTTPS Connection Context my Service <--> Clients created! $sslConnectionContext"
)
sslConnectionContext
}

How to send web socket message from server to client at particular time intervals?

I have implemented a web socket server using Play Framework. The server can take connections and respond to clients.
If the connections are idle for some time then the server automatically closes the connection .
I am not sure if there is any configuration to make the connections always alive.
So in order to monitor the connection status (connection is alive or not), the server needs to send PING message to the client at a particular time
intervals and it should receive PONG from the client.
Below is my server implementation
#Singleton
class RequestController #Inject()(cc: ControllerComponents)(implicit system: ActorSystem, mat: Materializer) extends AbstractController(cc) {
def ws = WebSocket.accept[String, String] {req =>
ActorFlow.actorRef { out =>
ParentActor.props(out)
}
}
}
object ParentActor {
def props(out: ActorRef) = Props(new ParentActor(out))
}
class ParentActor(out : ActorRef) extends Actor {
override def receive: Receive = {
case msg: String => out ! s"Echo from server $msg"
}
}
So how to send web socket ping message from server to client at particular time intervals?
You can use a scheduler in order to send message to client in certain interval. Following is one of the example that can be use to implement your scenario:
class ParentActor(out : ActorRef) extends Actor {
var isPongReceived = false
override def receive: Receive = {
case "START" =>
// Client started the connection, i.e. so, initially let mark client pong receive status as true.
isPongReceived = true
out ! s"Echo from server - Connection Started"
// This part schedules a scheduler that check in every 10 seconds if client is active/connected or not.
// Sends PING response if connected to client, otherwise terminate the actor.
context.system.scheduler.schedule(new DurationInt(10).seconds,
new DurationInt(10).seconds) {
if(isPongReceived) {
// Below ensures that server is waiting for client's PONG message in order to keep connection.
// That means, next time when this scheduler run after 10 seconds, if PONG is not received from client, the
// connection will be terminated.
isPongReceived = false
out ! "PING_RESPONSE"
}
else {
// Pong is not received from client / client is idle, terminate the connection.
out ! PoisonPill // Or directly terminate - context.stop(out)
}
}
case "PONG" => isPongReceived = true // Client sends PONG request, isPongReceived status is marked as true.
}
}

Grpc parallel Stream communication leads to error:AkkaNettyGrpcClientGraphStage

I have two services: one that sends stream data and the second one receives it using akka-grpc for communication. When source data is provided Service one is called to process and send it to service two via grpc client. It's possible that multiple instances of server one runs at the same time when multiple source data are provided at the same time.In long running test of my application. I see below error in service one:
ERROR i.a.g.application.actors.DbActor - GraphStage [akka.grpc.internal.AkkaNettyGrpcClientGraphStage$$anon$1#59d40805] terminated abruptly, caused by for example materializer or act
akka.stream.AbruptStageTerminationException: GraphStage [akka.grpc.internal.AkkaNettyGrpcClientGraphStage$$anon$1#59d40805] terminated abruptly, caused by for example materializer or actor system termination.
I have never shutdown actor systems but only kill actors after doing their job. Also I used proto3 and http2 for request binding. Here is a piece of my code in service one:
////////////////////server http binding /////////
val service: HttpRequest => Future[HttpResponse] =
ServiceOneServiceHandler(new ServiceOneServiceImpl(system))
val bound = Http().bindAndHandleAsync(
service,
interface = config.getString("akka.grpc.server.interface"),
port = config.getString("akka.grpc.server.default-http-port").toInt,
connectionContext = HttpConnectionContext(http2 = Always))
bound.foreach { binding =>
logger.info(s"gRPC server bound to: ${binding.localAddress}")
}
////////////////////client /////////
def send2Server[A](data: ListBuffer[A]): Future[ResponseDTO] = {
val reply = {
val thisClient = interface.initialize()
interface.call(client = thisClient, req = data.asInstanceOf[ListBuffer[StoreRequest]].toList)
}
reply
}
///////////////// grpc communication //////////
def send2GrpcServer[A](data: ListBuffer[A]): Unit = {
val reply = send2Server(data)
Await.ready(reply, Duration.Inf) onComplete {
case util.Success(response: ResponseDTO) =>
logger.info(s"got reply message: ${res.description}")
//////check response content and stop application if desired result not found in response
}
case util.Failure(exp) =>
//////stop application
throw exp.getCause
}
}
Error occurred exactly after waiting for service 2 response :
Await.ready(reply, Duration.Inf)
I can't catch the cause of error.
UPDATE
I found that some stream is missed such that service one sends an stream an indefinitely wait for the response and service two does not receive any thing to reply to service one but still don't know why stream is missed
I also updated akka grpc plugin but has no sense:
addSbtPlugin("com.lightbend.akka.grpc" % "sbt-akka-grpc" % "0.6.1")
addSbtPlugin("com.lightbend.sbt" % "sbt-javaagent" % "0.1.4")

Ktor Secure Sockets (SSL/TLS) windows example?

I was trying to follow the ktor documentation for Raw Sockets and in specific the part related to secured sockets (https://ktor.io/servers/raw-sockets.html):
runBlocking {
val socket = aSocket(ActorSelectorManager(ioCoroutineDispatcher)).tcp().connect(InetSocketAddress("google.com", 443)).tls()
val w = socket.openWriteChannel(autoFlush = false)
w.write("GET / HTTP/1.1\r\n")
w.write("Host: google.com\r\n")
w.write("\r\n")
w.flush()
val r = socket.openReadChannel()
println(r.readUTF8Line())
}
You can adjust a few optional parameters for the TLS connection:
suspend fun Socket.tls(
trustManager: X509TrustManager? = null,
randomAlgorithm: String = "NativePRNGNonBlocking",
serverName: String? = null,
coroutineContext: CoroutineContext = ioCoroutineDispatcher
): Socket
But the NativePRNGNonBlocking SecureRandom algorithm is not available on Windows, so my only option was to use SHA1PRNG (https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SecureRandomImp)
This is the code I'm running to connect to a listening socket :
socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(InetSocketAddress(host, port))
.tls(Dispatchers.IO, randomAlgorithm = "SHA1PRNG")
Unfortunately, I always receive the same error: "Channel was closed"
If I remove tls, keeping only the raw socket:
socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(InetSocketAddress(host, port))
Everything works as expected.
Does anyone has used Ktor Secure Sockets in Windows ? (Unfortunately, Ktor's documentation still has a long way to go).
Thanks,
J

Scala with Play Framework 2.3.6: sending a message to all socket clients

I'm new to Scala and the Play Framework, so I'm experimenting a bit.
I've successfully created websockets, but I'd like to be able to send a message to multiple socket clients from a simple POST request.
For instance, I have 10 different random browsers connected to my socket (ws:// ... /websocket), and I can myself send a "POST: HELLO" to /newMessage. How do I make so this "HELLO" gets sent to each of the 10 clients ?
Here's the controller receiving the HELLO. Works fine and prints "Got: AnyContentAsText(HELLO)" :
def newMessage = Action { implicit request =>
println("Got: " + request.body)
/* add something here to send "request.body" to every socket client */
Ok("Got: " + request.body)
}
And here's my simple "Socket" controller that sends "Welcome" to connected clients :
object Socket extends Controller {
def txSocket = WebSocket.using[String] { request =>
// Log events to the console
val in = Iteratee.foreach[String](println).map { _ =>
println("Disconnected")
}
// Send a single 'Welcome!' message
val out = Enumerator("Welcome!")
(in, out)
}
}
How can I, from my "Message" controller, send request.body to the websocket ?
Thank you for your time !
Each websocket connection makes a new actor. You need to select the actors and send the message to them.
Like so.
object Application extends Controller {
def connect = WebSocket.acceptWithActor[JsValue, JsValue] { request => out =>
ClientActor.props(out)
}
def broadcast = Action { _ =>
system.actorSelection("akka://application/system/websockets/*/handler") ! "msg"
Ok
}
def system = play.api.libs.concurrent.Akka.system(play.api.Play.current)
}