All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sss.openstar.telemetry.Client.scala Maven / Gradle / Ivy

package sss.openstar.telemetry

import akka.actor.ActorSystem
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.model.ws.{BinaryMessage, Message, WebSocketRequest}
import akka.http.scaladsl.{ConnectionContext, Http}
import akka.stream.scaladsl.{Flow, Keep, Sink, Source}
import akka.util.ByteString
import akka.{Done, NotUsed}
import sss.ancillary.Logging
import sss.openstar.BusEvent
import sss.openstar.network.MessageEventBus
import sss.openstar.telemetry.Client.ClientResponse

import javax.net.ssl.SSLContext
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.Try
import scala.util.control.NonFatal

object Client {
  case class ClientResponse(byteStr: ByteString) extends BusEvent
}

class Client(telemetryUrl: String, hostVerificationOff: Boolean)(implicit actorSystem: ActorSystem,
                                            events: MessageEventBus,
                                     ) extends Logging {


  private val requestSink: Sink[Message, Future[Done]] = Sink.foreach {

    case message: BinaryMessage.Strict =>
        events publish ClientResponse(message.data)

    case message: BinaryMessage =>
      message.toStrict(3.seconds) map { strictMsg =>
        events publish ClientResponse(strictMsg.data)
      }

    case message: Message =>
      log.debug(s"Unexpected received: ${message.asTextMessage}")

  }

  private def createFlow(requestSource: Source[Message, NotUsed]): Flow[Message, Message, Future[Done]] = {
    Flow.fromSinkAndSourceMat(requestSink, requestSource)(Keep.left)
  }

  private lazy val sslContext: SSLContext = SSLContext.getDefault

  //Note loose config has been stamped out, if it is still necessary try https://groups.google.com/g/akka-user/c/YBO75v3Mqww
  //The telemetry feature has not been tested as of this change Sept 2021
  //sslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose.withDisableHostnameVerification(hostVerificationOff)))
  private val httpsContxt = ConnectionContext.httpsClient(sslContext)


  def report(raw: ByteString): Try[Unit] = Try {

    val requestSource: Source[Message, NotUsed] =
      Source.single(
        BinaryMessage(raw)
      )

    val flow = createFlow(requestSource)

    val (upgradeResponse, closed) =  Http()
      .singleWebSocketRequest(WebSocketRequest(telemetryUrl), flow, connectionContext = httpsContxt)

    val connected = upgradeResponse.map { upgrade =>
      if (upgrade.response.status == StatusCodes.SwitchingProtocols) {
        Done
      } else {
        throw new RuntimeException(s"Connection failed: ${upgrade.response.status}")
      }
    }

    connected.recover {
      case e =>
        log.warn(s"${e.toString}")
    }

    closed.recover {
      case NonFatal(e) =>
        log.warn(s"Closed failed ${e.toString}")
    }

  }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy