Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active July 2, 2023 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/838642d670a8d9c67b6ac5ce0e206ee9 to your computer and use it in GitHub Desktop.
Save dacr/838642d670a8d9c67b6ac5ce0e206ee9 to your computer and use it in GitHub Desktop.
akka websocket counter service, just increment a counter every second for each connected client / published by https://github.com/dacr/code-examples-manager #6f6fe721-8f29-4670-85e0-727ba0487c9b/956933cc908d72a2462b8ed5ac81ec4d70214967
// summary : akka websocket counter service, just increment a counter every second for each connected client
// keywords : scala, actors, akka-http, http-server, websocket
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : 6f6fe721-8f29-4670-85e0-727ba0487c9b
// created-on : 2021-02-06T17:41:33Z
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// usage-example : scala-cli akka-http-server-websocket-counter.sc
// ---------------------
//> using scala "2.13.11"
//> using objectWrapper
//> using dep "com.typesafe.akka::akka-http:10.2.10"
//> using dep "com.typesafe.akka::akka-stream:2.6.21"
////> using dep "org.slf4j:slf4j-nop:2.0.7"
//> using dep "org.slf4j:slf4j-simple:2.0.7"
// ---------------------
import akka.http.scaladsl._
import akka.http.scaladsl.model.ws.{Message, TextMessage}
import akka.http.scaladsl.server.Directives._
import akka.stream.scaladsl.{Flow, Sink, Source}
import scala.concurrent.Await
import scala.concurrent.duration.{Duration, DurationInt}
// ---------------------------------------------------------------------------------------------------------------------
// Just a helper function which can be removed as only used for some println
def lanAddresses(): List[String] = {
import scala.jdk.CollectionConverters._
java.net.NetworkInterface
.getNetworkInterfaces().asScala
.filterNot(_.isLoopback)
.filterNot(_.isVirtual)
.filter(_.isUp)
.toList
.flatMap { interface =>
val ips = interface
.getInetAddresses.asScala
.to(List)
.filterNot(_.isAnyLocalAddress)
.collect { case x: java.net.Inet4Address => x.getHostAddress }
ips.headOption
}
}
// ---------------------------------------------------------------------------------------------------------------------
val port = args.headOption.map(_.toInt).getOrElse(8080)
val interface = args.drop(1).headOption.getOrElse("0.0.0.0")
System.setProperty("akka.http.server.remote-address-header", "true")
System.setProperty("akka.http.server.remote-address-attribute", "true")
System.setProperty("akka.http.server.websocket.periodic-keep-alive-max-idle", "1 second")
implicit val system = akka.actor.ActorSystem("MySystem")
implicit val executionContext = system.dispatcher
val routes = pathEndOrSingleSlash {
extractClientIP { clientIP =>
val from = clientIP.toIP.map(_.ip.getHostAddress)
println(s"new connection from $from")
val tickSource = Source.tick(2.seconds, 1.second, 0)
val integers = Iterator.from(0)
val tickMessageSource = tickSource.map(_ => TextMessage(integers.next().toString))
extractWebSocketUpgrade{ ws =>
complete {
ws.handleMessagesWithSinkSource(Sink.ignore, tickMessageSource)
}
}
}
}
Http().newServerAt(interface, port).bind(routes).andThen { case _ =>
val addr = lanAddresses().head
println(s"Waiting for websocket clients on $interface:$port ")
println(s"Try this server by using such command :")
println(s"- scala-cli akka-wscat.sc -- ws://$addr:8080")
println(s"- scala-cli pekko-wscat.sc -- ws://$addr:8080")
println(s"- scala-cli akka-wscat-stream.sc -- ws://$addr:8080")
println(s"- scala-cli pekko-wscat-stream.sc -- ws://$addr:8080")
println(s"- docker run -it --rm solsson/websocat -v ws://$addr:$port")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment