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

io.gatling.http.action.ws.fsm.WsFsm.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2011-2024 GatlingCorp (https://gatling.io)
 *
 * 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 io.gatling.http.action.ws.fsm

import java.util.concurrent.{ ScheduledFuture, TimeUnit }

import scala.concurrent.duration.FiniteDuration

import io.gatling.commons.util.Clock
import io.gatling.core.action.Action
import io.gatling.core.session.Session
import io.gatling.core.stats.StatsEngine
import io.gatling.core.util.BoundedMutableDequeue
import io.gatling.http.action.ws.WsInboundMessage
import io.gatling.http.check.ws.{ WsFrameCheck, WsFrameCheckSequence }
import io.gatling.http.client.{ Request, WebSocket }
import io.gatling.http.engine.HttpEngine
import io.gatling.http.protocol.HttpProtocol

import com.typesafe.scalalogging.StrictLogging
import io.netty.channel.EventLoop
import io.netty.handler.codec.http.cookie.Cookie
import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus

final class WsFsm(
    private[fsm] val wsName: String,
    private[fsm] val connectRequest: Request,
    private[fsm] val connectCheckSequence: List[WsFrameCheckSequence[WsFrameCheck]],
    private[fsm] val onConnected: Option[Action],
    private[fsm] val statsEngine: StatsEngine,
    private[fsm] val httpEngine: HttpEngine,
    private[fsm] val httpProtocol: HttpProtocol,
    eventLoop: EventLoop,
    private[fsm] val clock: Clock,
    private[fsm] val wsLogger: WsLogger
) extends StrictLogging {
  private var currentState: WsState = new WsInitState(this)
  private var currentTimeout: ScheduledFuture[Unit] = _
  private[fsm] val unmatchedInboundMessageBuffer = new BoundedMutableDequeue[WsInboundMessage](httpProtocol.wsPart.unmatchedInboundMessageBufferSize)

  private[fsm] def scheduleTimeout(dur: FiniteDuration): Unit = {
    currentTimeout = eventLoop.schedule(
      () => {
        logger.debug(s"Timeout ${currentTimeout.hashCode} triggered")
        currentTimeout = null
        execute(currentState.onTimeout())
      },
      dur.toMillis,
      TimeUnit.MILLISECONDS
    )
    logger.debug(s"Timeout ${currentTimeout.hashCode} scheduled")
  }

  private[fsm] def cancelTimeout(): Unit =
    if (currentTimeout == null) {
      logger.debug("Couldn't cancel timeout because it wasn't set")
    } else {
      if (currentTimeout.cancel(true)) {
        logger.debug(s"Timeout ${currentTimeout.hashCode} cancelled")
      } else {
        logger.debug(s"Failed to cancel timeout ${currentTimeout.hashCode}")
      }
      currentTimeout = null
    }

  private def execute(f: => NextWsState): Unit = {
    val NextWsState(nextState, afterStateUpdate) = f
    currentState = nextState
    afterStateUpdate()
  }

  def onPerformInitialConnect(session: Session, initialConnectNext: Action): Unit =
    execute(currentState.onPerformInitialConnect(session, initialConnectNext))

  def onWebSocketConnected(webSocket: WebSocket, cookies: List[Cookie], timestamp: Long): Unit =
    execute(currentState.onWebSocketConnected(webSocket, cookies, timestamp))

  def onSendTextFrame(
      actionName: String,
      message: String,
      checkSequences: List[WsFrameCheckSequence[WsFrameCheck]],
      session: Session,
      next: Action
  ): Unit = {
    unmatchedInboundMessageBuffer.clear()
    execute(currentState.onSendTextFrame(actionName, message, checkSequences, session, next))
  }

  def onSendBinaryFrame(
      actionName: String,
      message: Array[Byte],
      checkSequences: List[WsFrameCheckSequence[WsFrameCheck]],
      session: Session,
      next: Action
  ): Unit = {
    unmatchedInboundMessageBuffer.clear()
    execute(currentState.onSendBinaryFrame(actionName, message, checkSequences, session, next))
  }

  def onTextFrameReceived(message: String, timestamp: Long): Unit =
    execute(currentState.onTextFrameReceived(message, timestamp))

  def onBinaryFrameReceived(message: Array[Byte], timestamp: Long): Unit =
    execute(currentState.onBinaryFrameReceived(message, timestamp))

  def onWebSocketClosed(code: Int, reason: String, timestamp: Long): Unit =
    execute(currentState.onWebSocketClosed(code, reason, timestamp))

  def onWebSocketCrashed(t: Throwable, timestamp: Long): Unit =
    execute(currentState.onWebSocketCrashed(t, timestamp))

  def onClientCloseRequest(actionName: String, closeStatus: WebSocketCloseStatus, session: Session, next: Action): Unit =
    execute(currentState.onClientCloseRequest(actionName, closeStatus, session, next))

  def collectUnmatchedInboundMessages(): List[WsInboundMessage] =
    unmatchedInboundMessageBuffer.removeAll()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy