The Scala Toolkit

How to use websockets?

Language
Info: JavaScript is currently disabled, code tabs will still work, but preferences will not be remembered.

You can declare a dependency on Cask with the following using directive:

//> using dep com.lihaoyi::cask::0.10.2

In your build.sbt, you can add a dependency on Cask:

lazy val example = project.in(file("example"))
 .settings(
 scalaVersion := "3.4.2",
 libraryDependencies += "com.lihaoyi" %% "cask" % "0.10.2",
 fork := true
 )

In your build.sc, you can add a dependency on Cask:

object example extends RootModule with ScalaModule {
 def scalaVersion = "3.4.2"
 def ivyDeps = Agg(
 ivy"com.lihaoyi::cask::0.10.2"
 )
}

You can create a WebSocket endpoint with the @cask.websocket annotation. The endpoint method should return a cask.WsHandler instance defining how the communication should take place. It can also return a cask.Response, which rejects the attempt at forming a WebSocket connection.

The connection can also be closed by sending a cask.Ws.close() message through the WebSocket channel.

Create an HTML file named websockets.html with the following content and place it in the resources directory.

<!DOCTYPE html>
<html>
<body>
<div>
 <input type="text" id="input" placeholder="Provide city name">
 <button onclick="sendMessage()">Send</button>
</div>
<div id="time"></div>
<script>
 const ws = new WebSocket('ws://localhost:8080/websocket');
 ws.onmessage = function(event) {
 receiveMessage(event.data);
 };
 ws.onclose = function(event) {
 receiveMessage('The connection has been closed');
 };
 function sendMessage() {
 const inputElement = document.getElementById('input');
 const message = inputElement.value;
 ws.send(message);
 }
 function receiveMessage(message) {
 const timeElement = document.getElementById('time');
 timeElement.textContent = message;
 }
</script>
</body>
</html>

The JavaScript code opens a WebSocket connection using the ws://localhost:8080/websocket endpoint. The ws.onmessage event handler is executed when the server pushes a message to the browser and ws.onclose when the connection is closed.

Create an endpoint for serving static files using the @cask.staticResources annotation and an endpoint for handling the WebSocket connection.

@cask.staticResources("/static")
def static() = "."
private def getZoneIdForCity(city: String): Option[ZoneId] = {
 import scala.jdk.CollectionConverters._
 ZoneId.getAvailableZoneIds.asScala.find(_.endsWith("/" + city)).map(ZoneId.of)
}
@cask.websocket("/websocket")
def websocket(): cask.WsHandler = {
 cask.WsHandler { channel =>
 cask.WsActor {
 case cask.Ws.Text("") => channel.send(cask.Ws.Close())
 case cask.Ws.Text(city) =>
 val text = getZoneIdForCity(city) match {
 case Some(zoneId) => s"Current date is: ${ZonedDateTime.now().withZoneSameInstant(zoneId)}"
 case None => s"Couldn't find time zone for city $city"
 }
 channel.send(cask.Ws.Text(text))
 }
 }
}
initialize()
@cask.staticResources("/static")
def static() = "."
private def getZoneIdForCity(city: String): Option[ZoneId] =
 import scala.jdk.CollectionConverters.*
 ZoneId.getAvailableZoneIds.asScala.find(_.endsWith("/" + city)).map(ZoneId.of)
@cask.websocket("/websocket")
def websocket(): cask.WsHandler =
 cask.WsHandler { channel =>
 cask.WsActor {
 case cask.Ws.Text("") => channel.send(cask.Ws.Close())
 case cask.Ws.Text(city) =>
 val text = getZoneIdForCity(city) match
 case Some(zoneId) => s"Current date is: ${ZonedDateTime.now().withZoneSameInstant(zoneId)}"
 case None => s"Couldn't find time zone for city $city"
 channel.send(cask.Ws.Text(text))
 }
 }
initialize()

In the cask.WsHandler we define a cask.WsActor. It reacts to events (of type cask.util.Ws.Event) and uses the WebSocket channel to send messages. In this example, we receive the name of a city and return the current time there. If the server receives an empty message, the connection is closed.

Contributors to this page:

Contents

AltStyle によって変換されたページ (->オリジナル) /