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

io.github.cactacea.finasocket.WebSocket.scala Maven / Gradle / Ivy

The newest version!
package io.github.cactacea.finasocket

import com.twitter.finagle.param.{ProtocolLibrary, Stats}
import com.twitter.finagle.client.{StackClient, StdStackClient, Transporter}
import com.twitter.finagle.server.{Listener, StackServer, StdStackServer}
import com.twitter.finagle.websocket._
import com.twitter.finagle.transport.{Transport, TransportContext}
import com.twitter.util.Closable
import java.net.{SocketAddress, URI}

import com.twitter.finagle._
import com.twitter.finagle.netty4.Netty4Transporter
import com.twitter.finagle.ssl.client.SslClientConfiguration
import io.netty.channel.ChannelPipeline
import io.netty.handler.codec.http.{DefaultHttpHeaders, HttpClientCodec, HttpObjectAggregator}
import io.netty.handler.codec.http.websocketx.{WebSocketClientHandshakerFactory, WebSocketVersion}
import io.github.cactacea.finasocket.{Client => WebSocketClient}

object WebSocket extends Server[WebSocketClient, WebSocketClient] {

  case class Client(stack: Stack[ServiceFactory[Request, Response]] = StackClient.newStack,
                    params: Stack.Params = StackClient.defaultParams + ProtocolLibrary("ws"))
    extends StdStackClient[Request, Response, Client] {
    override protected type In = Any
    override protected type Out = Any
    override protected type Context = TransportContext

    override protected def newTransporter(addr: SocketAddress): Transporter[In, Out, Context] = {

      val endpoint = params[Transporter.EndpointAddr].addr
      val scheme = params[ProtocolLibrary].name
      val uri = endpoint match {
        case Address.Inet(a, _) =>
          Some(new URI(s"${scheme}://${a.getHostName}:${a.getPort}"))
        case _ =>
          None
      }

      val httpHeaders = new DefaultHttpHeaders()
      val handShaker = WebSocketClientHandshakerFactory.newHandshaker(uri.get, WebSocketVersion.V13, null, false, httpHeaders, 1280000)
      val handler = new WebSocketClientHandler(handShaker)

      Netty4Transporter.raw(clientPipeline(handler), addr, params)
    }

    private def clientPipeline(handler: WebSocketClientHandler)(pipeline: ChannelPipeline): Unit = {
      pipeline.addLast("client", new HttpClientCodec())
      pipeline.addLast("aggregator", new HttpObjectAggregator(65536))
      pipeline.addLast("ws", handler)
    }


    override protected def copy1(
                                  stack: Stack[ServiceFactory[Request, Response]] = this.stack,
                                  params: Stack.Params = this.params
                                ): Client = copy(stack, params)

    override protected def newDispatcher(transport: Transport[In, Out] {
      type Context <: TransportContext
    }): Service[Request, Response] = {

      new ClientDispatcher(transport)

    }

    def withTlsWithoutValidation: Client = withTransport.tlsWithoutValidation

    def withTls(hostname: String): Client = withTransport.tls(hostname)

    def withTls(cfg: SslClientConfiguration): Client =
      withTransport.tls.configured(Transport.ClientSsl(Some(cfg)))
  }

  val client: Client = Client()

  case class Server(
                     stack: Stack[ServiceFactory[WebSocketClient, WebSocketClient]] = StackServer.newStack,
                     params: Stack.Params = StackServer.defaultParams + ProtocolLibrary("ws"))
    extends StdStackServer[WebSocketClient, WebSocketClient, Server] {

    protected type In = Any
    protected type Out = Any
    protected type Context = TransportContext

    protected def newListener(): Listener[In, Out, Context] =
      Netty4.newListener(params)

    private[this] val statsReceiver = {
      val Stats(sr) = params[Stats]
      sr.scope("websocket")
    }

    protected def newDispatcher(
      transport: Transport[In, Out] { type Context <: Server.this.Context },
      service: Service[WebSocketClient, WebSocketClient]
    ): Closable =
        new ServerDispatcher(transport, service, statsReceiver)

    protected def copy1(
                         stack: Stack[ServiceFactory[WebSocketClient, WebSocketClient]] = this.stack,
                         params: Stack.Params = this.params
    ): Server = copy(stack, params)
  }

  val server: WebSocket.Server = Server()

  def serve(
    addr: SocketAddress,
    factory: ServiceFactory[WebSocketClient, WebSocketClient]
  ): ListeningServer = server.serve(addr, factory)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy