![JAR search and dependency download from the Maven repository](/logo.png)
net.sigusr.mqtt.examples.LocalSubscriber.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014 Frédéric Cabestre
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sigusr.mqtt.examples
import cats.effect.std.Console
import cats.effect.{ExitCode, IO, IOApp}
import cats.implicits._
import com.comcast.ip4s.{Host, Port}
import fs2.Stream
import fs2.concurrent.SignallingRef
import net.sigusr.mqtt.api.QualityOfService.{AtLeastOnce, AtMostOnce, ExactlyOnce}
import net.sigusr.mqtt.api.RetryConfig.Custom
import net.sigusr.mqtt.api._
import retry.RetryPolicies
import java.util.concurrent.TimeUnit
import scala.concurrent.duration.{FiniteDuration, SECONDS}
object LocalSubscriber extends IOApp {
private val stopTopic: String = s"$localSubscriber/stop"
private val subscribedTopics: Vector[(String, QualityOfService)] = Vector(
(stopTopic, ExactlyOnce),
("AtMostOnce", AtMostOnce),
("AtLeastOnce", AtLeastOnce),
("ExactlyOnce", ExactlyOnce)
)
private val unsubscribedTopics: Vector[String] = Vector("AtMostOnce", "AtLeastOnce", "ExactlyOnce")
override def run(args: List[String]): IO[ExitCode] = {
val retryConfig: Custom[IO] = Custom[IO](
RetryPolicies
.limitRetries[IO](5)
.join(RetryPolicies.fullJitter[IO](FiniteDuration(2, SECONDS)))
)
val transportConfig =
TransportConfig[IO](
Host.fromString("localhost").get,
Port.fromString("1883").get,
// TLS support looks like
// 8883,
// tlsConfig = Some(TLSConfig(TLSContextKind.System)),
retryConfig = retryConfig,
traceMessages = true
)
val sessionConfig =
SessionConfig(
s"$localSubscriber",
cleanSession = false,
user = Some(localSubscriber),
password = Some("yolo"),
keepAlive = 5
)
implicit val console: Console[IO] = Console.make[IO]
Session[IO](transportConfig, sessionConfig).use { session =>
SignallingRef[IO, Boolean](false).flatMap { stopSignal =>
val sessionStatus = session.state.discrete
.evalMap(logSessionStatus[IO])
.evalMap(onSessionError[IO])
.interruptWhen(stopSignal)
.compile
.drain
val subscriber = for {
s <- session.subscribe(subscribedTopics)
_ <- s.traverse { p =>
putStrLn[IO](
s"Topic ${scala.Console.CYAN}${p._1}${scala.Console.RESET} subscribed with QoS " +
s"${scala.Console.CYAN}${p._2.show}${scala.Console.RESET}"
)
}
_ <- IO.sleep(FiniteDuration(23, TimeUnit.SECONDS))
_ <- session.unsubscribe(unsubscribedTopics)
_ <-
putStrLn[IO](s"Topic ${scala.Console.CYAN}${unsubscribedTopics.mkString(", ")}${scala.Console.RESET} unsubscribed")
_ <- stopSignal.discrete.compile.drain
} yield ()
val reader = session.messages.flatMap(processMessages(stopSignal)).interruptWhen(stopSignal).compile.drain
for {
_ <- IO.racePair(sessionStatus, subscriber.race(reader))
} yield ExitCode.Success
}
}.handleErrorWith(_ => IO.pure(ExitCode.Error))
}
private def processMessages(stopSignal: SignallingRef[IO, Boolean]): Message => Stream[IO, Unit] = {
case Message(LocalSubscriber.stopTopic, _) => Stream.exec(stopSignal.set(true))
case Message(topic, payload) =>
Stream.eval(
putStrLn[IO](
s"Topic ${scala.Console.CYAN}$topic${scala.Console.RESET}: " +
s"${scala.Console.BOLD}${new String(payload.toArray, "UTF-8")}${scala.Console.RESET}"
)
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy