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

sttp.tapir.server.vertx.encoders.package.scala Maven / Gradle / Ivy

The newest version!
package sttp.tapir.server.vertx

import java.io.{ByteArrayInputStream, InputStream}

import io.vertx.core.Future
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.core.buffer.Buffer
import io.vertx.core.http.{ServerWebSocket, WebSocketFrameType}
import io.vertx.core.streams.ReadStream
import sttp.ws.WebSocketFrame
import scala.annotation.tailrec
import java.util.concurrent.Callable

package object encoders {

  private val bufferSize = 1024

  /** README: Tests are using a ByteArrayInputStream, which is totally fine, but other blocking implementations like FileInputStream etc.
    * must maybe be wrapped in executeBlocking
    */
  private[vertx] def inputStreamToBuffer(is: InputStream, vertx: Vertx, byteLimit: Option[Long]): Future[Buffer] = {
    is match {
      case _: ByteArrayInputStream =>
        Future.succeededFuture(inputStreamToBufferUnsafe(is, byteLimit))
      case _ =>
        vertx.executeBlocking(new Callable[Buffer] { override def call(): Buffer = inputStreamToBufferUnsafe(is, byteLimit) })
    }
  }

  private def inputStreamToBufferUnsafe(is: InputStream, byteLimit: Option[Long]): Buffer = {
    val buffer = Buffer.buffer()

    @tailrec
    def readRec(buffer: Buffer, readSoFar: Long): Buffer =
      if (byteLimit.exists(_ <= readSoFar) || is.available() <= 0)
        buffer
      else {
        val bytes = is.readNBytes(bufferSize)
        val length = bytes.length.toLong
        val lengthToWrite: Int = byteLimit.map(limit => Math.min(limit - readSoFar, length)).getOrElse(length).toInt
        readRec(buffer.appendBytes(bytes, 0, lengthToWrite), readSoFar = readSoFar + lengthToWrite)
      }

    readRec(buffer, readSoFar = 0L)
  }

  def wrapWebSocket(websocket: ServerWebSocket): ReadStream[WebSocketFrame] =
    new ReadStream[WebSocketFrame] {
      override def exceptionHandler(handler: Handler[Throwable]): ReadStream[WebSocketFrame] = {
        websocket.exceptionHandler(handler)
        this
      }

      override def handler(handler: Handler[WebSocketFrame]): ReadStream[WebSocketFrame] = {
        websocket.frameHandler { frame =>
          val t = frame.`type`()
          if (t == WebSocketFrameType.TEXT) {
            handler.handle(WebSocketFrame.Text(frame.textData(), frame.isFinal(), None))
          } else if (t == WebSocketFrameType.BINARY) {
            handler.handle(WebSocketFrame.Binary(frame.binaryData().getBytes(), frame.isFinal(), None))
          }
        }
        websocket.pongHandler { buffer =>
          handler.handle(WebSocketFrame.Pong(buffer.getBytes()))
        }
        this
      }

      override def pause(): ReadStream[WebSocketFrame] = {
        websocket.pause()
        this
      }

      override def resume(): ReadStream[WebSocketFrame] = {
        websocket.resume()
        this
      }

      override def fetch(amount: Long): ReadStream[WebSocketFrame] = {
        websocket.fetch(amount)
        this
      }

      override def endHandler(endHandler: Handler[Void]): ReadStream[WebSocketFrame] = {
        websocket.endHandler(endHandler)
        this
      }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy