All Files (100.0% covered at 4.38 hits/line)
16 files in total.
358 relevant lines.
358 lines covered and
0 lines missed
# frozen_string_literal: true
- 1
require 'active_support'
- 1
require 'active_support/inflector'
- 1
require 'rack'
- 1
require 'securerandom'
- 1
require 'request_store'
- 1
require 'context_request_middleware/railtie' if defined?(Rails)
- 1
require 'context_request_middleware/sampling_handler'
- 1
require 'context_request_middleware/middleware'
- 1
require 'context_request_middleware/cookie'
- 1
require 'context_request_middleware/request'
- 1
require 'context_request_middleware/context'
- 1
require 'context_request_middleware/push_handler'
- 1
require 'context_request_middleware/sampling_handler/accept_all'
- 1
require 'context_request_middleware/error_logger'
- 1
require 'context_request_middleware/parameter_filter'
# :nodoc:
- 1
module ContextRequestMiddleware
- 1
include ActiveSupport::Configurable
# For older Rack Versions there is no method 'get_header' this
# Request class will provide that logic.
- skipped
# :nocov:
- skipped
config_accessor(:request_class, instance_accessor: false) do
- skipped
if Rack.release[0].to_i < 2
- skipped
# :nodoc:
- skipped
class RackRequest < Rack::Request
- skipped
def get_header(name)
- skipped
@env[name]
- skipped
end
- skipped
end
- skipped
RackRequest
- skipped
else
- skipped
Rack::Request
- skipped
end
- skipped
end
- skipped
# :nocov:
# For older ActiveSupport versions there is no class 'ParameterFilter'
# ContextRequestMiddleware::ParameterFilter class will provide the logic.
- skipped
# :nocov:
- skipped
config_accessor(:parameter_filter_class, instance_accessor: false) do
- skipped
if defined?(ActiveSupport::ParameterFilter)
- skipped
ActiveSupport::ParameterFilter
- skipped
else
- skipped
ContextRequestMiddleware::ParameterFilter
- skipped
end
- skipped
end
- skipped
# :nocov:
# Array to specify the parameters
# that need to be masked
# @default []
- 1
config_accessor(:parameter_filter_list, instance_accessor: false) do
- 1
[]
end
# Mask to use when masking the parameters
# @default '[FILTERED]'
- 1
config_accessor(:parameter_filter_mask, instance_accessor: false) do
- 1
'[FILTERED]'
end
# Array to specify the headers supported to hold the request_id.
# Defaults to the X_REQUEST_ID header.
# @default ['HTTP_X_REQUEST_ID']
- 1
config_accessor(:request_id_headers, instance_accessor: false) do
- 1
['HTTP_X_REQUEST_ID', 'action_dispatch.request_id']
end
# Array to specify the headers supported to hold the start time of the
# request.
# @default ['HTTP_X_REQUEST_START', 'HTTP_X_QUEUE_START']
- 1
config_accessor(:request_start_time_headers, instance_accessor: false) do
- 1
%w[HTTP_X_REQUEST_START HTTP_X_QUEUE_START]
end
# If remote IP is carried in an unsupported headers it can be specified here.
# Expects an Array. For one item this means one item Array.
# @default nil which means the X_REQUEST_HOST and rails specifics are
# supported
- 1
config_accessor(:remote_ip_headers, instance_accessor: false)
# Application id given to the application using the middleware.
# @default 'anonymous'
- 1
config_accessor(:app_id, instance_accessor: false) do
- 1
'anonymous'
end
# small case '_' or '.' delimited classname to point to the session id
# retriever.
# To be found under the namespace ContextRequestMiddleware::Request
# @default 'cookie_session_id_retriever' which resolves to
# ContextRequestMiddleware::Request::SessionIdRetriever.
- 1
config_accessor(:request_context_retriever, instance_accessor: false) do
- 1
'cookie_session_id_retriever'
end
# version for request_retriever.
# @default nil as no version yet set
- 1
config_accessor(:request_context_retriever_version, instance_accessor: false)
# Classname (small case) on how to extract the context if a new one is
# created. Basically this means detect if a new context was created or
# not. For example is the session still valid or not.
# To be found under the namespace ContextRequestMiddleware::Context
# @default 'cookie_session_id_retriever'
- 1
config_accessor(:context_retriever, instance_accessor: false) do
- 1
'cookie_session_retriever'
end
- 1
config_accessor(:context_retriever_version, instance_accessor: false)
# Extract the user id from Main application
# Set in Main App ENV['cookie_session.user_id'] = current_user.id
# usually done in application_controller
# so it can be applied to the context
# @default cookie_session.user_id
- 1
config_accessor(:session_owner_id, instance_accessor: false) do
- 1
'cookie_session.user_id'
end
# Extract the context status from Main application
# Set in Main App ENV['cookie_session.context_status']
# usually done in application_controller
# so it can be applied to the context
# @default cookie_session.context_status
- 1
config_accessor(:context_status, instance_accessor: false) do
- 1
'cookie_session.context_status'
end
# Classname (small case) on how to push the data stored from the current
# request.
# @default rabbitmq_push_handler which means it pushes to RabbitMQ
- 1
config_accessor(:push_handler, instance_accessor: false) do
- 1
'rabbitmq_push_handler'
end
- 1
config_accessor(:push_handler_version, instance_accessor: false)
# Configuration to configure the push_handler if required.
# @default: {}
- 2
config_accessor(:push_handler_config, instance_accessor: false) { {} }
# Classname (small case) on how to detect if this request should be
# sampled.
# @default accept_all which means all requests will be sampled.
- 1
config_accessor(:sampling_handler, instance_accessor: false) do
- 1
'accept_all'
end
- 1
config_accessor(:sampling_handler_version, instance_accessor: false)
# Array to specify the logger tags
# @default ['CONTEXT_REQUEST_MIDDLEWARE']
- 1
config_accessor(:logger_tags, instance_accessor: false) do
- 1
['CONTEXT_REQUEST_MIDDLEWARE']
end
# retrieves a class that is loaded from the root_pathname and
# suffixed with both name and version.
# @root_pathname: the root path to be prefixed.
# For example ContextRequestMiddleware::Request as string.
# @name: the name of the class in small case seperated with . or _.
# For example session_id_retriever will yield to SessionIdretriever.
# @version: if version is given it will be suffixed to the path.
# For example version=1 will yield {root_path}::V1.
# @return a class if found otherwise nil.
- 1
def self.load_class_from_name(name, root_path_name, version = nil)
- 22
version = "V#{version}" if version
[root_path_name, version, name.tr('.', '_').camelize].compact.join('::')
- 22
.constantize
rescue NameError
- 3
nil
end
#
# Returns the first header found from the given array of headers in the
# given request.
# @headres an array of headers to be looking for. Headers are specified full
# as in the environment with HTTP_ prefixed and capital letters ...
# @request the Rack::Request holding the request (headers) as Hash.
- 1
def self.select_request_headers(headers, request)
- 16
value = nil
- 16
headers.each do |header|
- 25
value = request.get_header(header)
- 25
break if value
end
- 16
value
end
end
- 1
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
# frozen_string_literal: true
- 1
require 'context_request_middleware/context/cookie_session_retriever'
- 1
module ContextRequestMiddleware
# Base module to consolidate the different context extraction logics.
# Like extracting sessions that have been newly created, apitokens, ..
- 1
module Context
- 1
extend self
- 1
def retriever_for_response(request)
ContextRequestMiddleware
.load_class_from_name(
ContextRequestMiddleware.context_retriever,
ContextRequestMiddleware::Context.to_s,
ContextRequestMiddleware.context_retriever_version
- 6
)&.new(request)
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
- 1
module Context
# Class for retrieving the session if set via rack cookie.
# This requires the session and more data to be stored in
# '_session_id' cookie key.
- 1
class CookieSessionRetriever
- 1
include ActiveSupport::Configurable
- 1
include ContextRequestMiddleware::Cookie
- 1
HTTP_HEADER = 'Set-Cookie'
- 1
attr_accessor :data
- 1
def initialize(request)
- 11
@request = request
- 11
@data = {}
end
- 1
def call(status, header, body)
- 11
@response = Rack::Response.new(body, status, header)
- 11
if new_context?
- 6
data[:context_id] = session_id
- 6
data[:owner_id] = owner_id
- 6
data[:context_status] = context_status
- 6
data[:context_type] = context_type
- 6
data[:app_id] = ContextRequestMiddleware.app_id
end
- 11
data
end
- 1
def new_context?
- 17
new_session_id && new_session_id != request_cookie_session_id
end
- 1
private
- 1
def owner_id
- 6
from_thread_var(ContextRequestMiddleware.session_owner_id, 'unknown')
end
- 1
def context_status
- 6
from_thread_var(ContextRequestMiddleware.context_status, 'unknown')
end
- 1
def context_type
- 6
'session_cookie'
end
- 1
def session_id
- 6
new_session_id || request_cookie_session_id
end
- 1
def new_session_id
- 33
new_session = nil
session_id_header = set_cookie_header.match(/_session_id=([^\;]+)/) \
- 33
if set_cookie_header
- 33
new_session = session_id_header[1] if session_id_header
- 33
new_session
end
- 1
def request_cookie_session_id
- 10
cookie_session_id(@request)
end
- 1
def set_cookie_header
- 59
@response.headers.fetch(HTTP_HEADER, nil)
end
- 1
def from_thread_var(key, default = nil)
- 12
RequestStore.store[key] || default
end
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
# Cookie module to consist the compatibility with
# rack version 1.x & 2.0
- 1
module Cookie
- 1
HTTP_COOKIE = 'HTTP_COOKIE' if Rack.release < '2.0.0'
- skipped
# :nocov:
- skipped
def cookie_session_id(request)
- skipped
if Rack.release < '2.0.0'
- skipped
parse_cookies(request.env)['_session_id'] ||
- skipped
(request.env['action_dispatch.cookies'] || {})['_session_id']
- skipped
else
- skipped
Rack::Utils.parse_cookies(request.env)['_session_id'] ||
- skipped
(request.env['action_dispatch.cookies'] || {})['_session_id']
- skipped
end
- skipped
end
- skipped
- skipped
# :nocov:
- 1
if Rack.release < '2.0.0'
- skipped
# :nocov:
- skipped
def parse_cookies(env)
- skipped
parse_cookies_header env[HTTP_COOKIE]
- skipped
end
- skipped
- skipped
def parse_cookies_header(header)
- skipped
# rubocop:disable Metrics/LineLength, Style/RescueModifier, Style/CaseEquality
- skipped
cookies = Rack::Utils.parse_query(header, ';,') { |s| unescape(s) rescue s }
- skipped
cookies.each_with_object({}) { |(k, v), hash| hash[k] = Array === v ? v.first : v }
- skipped
# rubocop:enable Metrics/LineLength, Style/RescueModifier, Style/CaseEquality
- skipped
end
- skipped
# :nocov:
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
# Duplicable module used by ParameterFilter module
- 1
module Duplicable
- 1
def self.check?(object)
- 12
return false if object.is_a?(Method) || object.is_a?(UnboundMethod)
- 12
true
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
# Logger module to provide logging of errors
- 1
module ErrorLogger
- 1
extend self
# runs block of code and logs an error if any occurs
- 1
def error_handler
- 6
yield
rescue StandardError => e
- 1
logger.tagged(ContextRequestMiddleware.logger_tags) do
- 1
logger.error e.message + e.backtrace.join('\n')
end
end
# Returns logger from these options:
# option 1: Rails.logger, as defined in the host application
# option 2: new instance of ActiveSupport::TaggedLogging class
- 1
def logger(logger = Logger)
- 2
@logger ||= if defined?(Rails.logger.tagged)
- skipped
# :nocov:
- skipped
Rails.logger
- skipped
# :nocov:
else
- 1
ActiveSupport::TaggedLogging.new(logger)
end
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
# :nodoc:
# rubocop:disable Metrics/ClassLength
- 1
class Middleware
- 1
def initialize(app)
- 7
@app = app
end
- 1
def call(env)
- 7
@push_handler ||= PushHandler.from_middleware
- 7
dup._call(env)
end
# rubocop:disable Metrics/MethodLength
- 1
def _call(env)
- 6
@data = {}
- 6
request = ContextRequestMiddleware.request_class.new(env)
- 6
request(request)
- 6
status, header, body = @app.call(env)
- 6
ContextRequestMiddleware::ErrorLogger.error_handler do
- 6
response(status, header, body)
- 6
@context = context(status, header, body, request)
- 6
push_context
- 5
push if valid_sample?(request)
end
- 6
[status, header, body]
end
# rubocop:enable Metrics/MethodLength
- 1
private
- 1
def request(request)
- 6
request_data(request)
- 6
others_data(request)
- 6
@data
end
- 1
def request_data(request)
- 6
@data[:request_id] = request_id(request)
- 6
@data[:request_context] = request_context(request)
- 6
@data[:request_start_time] = request_start_time(request)
- 6
@data[:request_method] = request.request_method
- 6
@data[:request_params] = filter_params(request.params)
- 6
@data[:request_path] = request.path
end
- 1
def filter_params(params)
- 6
return params if ContextRequestMiddleware.parameter_filter_list.empty?
- 6
filter = ContextRequestMiddleware.parameter_filter_class.new(
ContextRequestMiddleware.parameter_filter_list,
mask: ContextRequestMiddleware.parameter_filter_mask
)
- 6
filter.filter(params)
end
- 1
def others_data(request)
- 6
@data[:source] = source(request)
- 6
@data[:host] = request.host
end
- 1
def response(status, _headers, _response)
- 6
@data[:request_status] = status
end
# checks if this request changed the context
- 1
def context(status, header, body, request)
- 6
@context = context_retriever(request)&.call(status, header, body)
@data[:request_context] = @context[:context_id] \
- 6
if @context && @context[:context_id]
- 6
@context
end
# retrieves the context of the current request
- 1
def request_context(request)
- 6
@request_context ||= Request.retriever_for_request(request)&.call
end
- 1
def context_retriever(request)
- 6
@context_retriever ||=
Context.retriever_for_response(request)
end
- 1
def push
- 4
return unless @data
- 4
return unless @data.any?
- 4
return unless @push_handler
- 4
@push_handler.push(@data, push_options(@data, 'request'))
nil
end
- 1
def push_context
- 6
return unless @context_retriever.new_context?
- 3
return unless @context
- 3
return unless @context.any?
- 3
return unless @push_handler
- 3
@push_handler.push(@context, push_options(@data, 'context'))
end
- 1
def push_options(_data, type)
- 7
{
type: type,
message_id: SecureRandom.uuid
}
end
- 1
def valid_sample?(request)
- 5
@sample_handler ||= SamplingHandler.from_request
- 5
if @sample_handler
- 4
@sample_handler.valid?(request)
else
- 1
false
end
end
- 1
def request_start_time(request)
ContextRequestMiddleware.select_request_headers(
ContextRequestMiddleware.request_start_time_headers,
request
- 6
) || (defined?(Time.current) ? Time.current : Time.now).to_f
end
- 1
def source(request)
- 6
(ContextRequestMiddleware.remote_ip_headers &&
ContextRequestMiddleware
.select_request_headers(ContextRequestMiddleware.remote_ip_headers,
- 6
request)) ||
request.get_header('action_dispatch.remote_ip').to_s ||
request.get_header('HTTP_X_FORWARDED_HOST').to_s
end
- 1
def request_id(request)
- 6
@request_id ||= ContextRequestMiddleware.select_request_headers(
ContextRequestMiddleware.request_id_headers, request
)
end
end
# rubocop:enable Metrics/ClassLength
end
# frozen_string_literal: true
# rubocop:disable all
- 1
require 'context_request_middleware/duplicable'
- 1
module ContextRequestMiddleware
# ParameterFilter module to filter the contents of provided parameters.
# Used when the version of ActiveSupport doesn't have this class
- 1
class ParameterFilter
- 1
FILTERED = "[FILTERED]" # :nodoc:
# Create instance with given filters. Supported type of filters are +String+, +Regexp+, and +Proc+.
# Other types of filters are treated as +String+ using +to_s+.
# For +Proc+ filters, key, value, and optional original hash is passed to block arguments.
#
# ==== Options
#
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to +"[FILTERED]"+
- 1
def initialize(filters = [], mask: FILTERED)
- 6
@filters = filters
- 6
@mask = mask
end
# Mask value of +params+ if key matches one of filters.
- 1
def filter(params)
- 6
compiled_filter.call(params)
end
# Returns filtered value for given key. For +Proc+ filters, third block argument is not populated.
- skipped
# :nocov:
- skipped
def filter_param(key, value)
- skipped
@filters.empty? ? value : compiled_filter.value_for_key(key, value)
- skipped
end
- skipped
# :nocov:
- 1
private
- 1
def compiled_filter
- 6
@compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
end
- 1
class CompiledFilter # :nodoc:
- 1
def self.compile(filters, mask:)
- 6
return lambda { |params| params.dup } if filters.empty?
- 6
strings, regexps, blocks = [], [], []
- 6
filters.each do |item|
- 30
case item
when Proc
- 6
blocks << item
when Regexp
- 6
regexps << item
else
- 18
strings << Regexp.escape(item.to_s)
end
end
- 6
deep_regexps = regexps.dup
- 12
deep_regexps.keep_if { |r| r.to_s.include?("\\.") }
- 12
regexps.delete_if { |r| r.to_s.include?("\\.") }
- 6
deep_strings = strings.dup
- 24
deep_strings.keep_if { |s| s.include?("\\.") }
- 24
strings.delete_if { |s| s.include?("\\.") }
- 6
regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
- 6
deep_regexps << Regexp.new(deep_strings.join("|"), true) unless deep_strings.empty?
- 6
new regexps, deep_regexps, blocks, mask: mask
end
- 1
attr_reader :regexps, :deep_regexps, :blocks
- 1
def initialize(regexps, deep_regexps, blocks, mask:)
- 6
@regexps = regexps
- 6
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
- 6
@blocks = blocks
- 6
@mask = mask
end
- 1
def call(params, parents = [], original_params = params)
- 8
filtered_params = params.class.new
- 8
params.each do |key, value|
- 12
filtered_params[key] = value_for_key(key, value, parents, original_params)
end
- 8
filtered_params
end
- 1
def value_for_key(key, value, parents = [], original_params = nil)
- 12
parents.push(key) if deep_regexps
- 34
if regexps.any? { |r| r.match?(key) }
- 2
value = @mask
- 20
elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| r.match?(joined) }
- 2
value = @mask
- 8
elsif value.is_a?(Hash)
- 2
value = call(value, parents, original_params)
- 6
elsif value.is_a?(Array)
- skipped
# :nocov:
- skipped
# If we don't pop the current parent it will be duplicated as we
- skipped
# process each array value.
- skipped
parents.pop if deep_regexps
- skipped
value = value.map { |v| value_for_key(key, v, parents, original_params) }
- skipped
# Restore the parent stack after processing the array.
- skipped
parents.push(key) if deep_regexps
- skipped
# :nocov:
- 6
elsif blocks.any?
- 6
key = key.dup if Duplicable.check?(key)
- 6
value = value.dup if Duplicable.check?(value)
- 12
blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
end
- 12
parents.pop if deep_regexps
- 12
value
end
end
end
end
# rubocop:enable all
# frozen_string_literal: true
- 1
require 'context_request_middleware/push_handler/rabbitmq_push_handler'
- 1
require 'context_request_middleware/push_handler/rabbitmq_push_handler_async'
- 1
module ContextRequestMiddleware
# :nodoc:
- 1
module PushHandler
- 1
extend self
- 1
def initialize(**_config); end
- 1
def from_middleware
ContextRequestMiddleware
.load_class_from_name(ContextRequestMiddleware.push_handler,
ContextRequestMiddleware::PushHandler.to_s,
ContextRequestMiddleware.push_handler_version)
- 1
&.new(**ContextRequestMiddleware.push_handler_config)
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
- 1
module PushHandler
# :nodoc:
- 1
class Base
- 1
def push(_data, _options); end
end
end
end
# frozen_string_literal: true
- 1
require 'bunny'
- 1
require 'connection_pool'
- 1
require 'context_request_middleware/push_handler/base'
- 1
module ContextRequestMiddleware
- 1
module PushHandler
# PushHandler that pusblishes the data given to a RabbitMQ exchange.
# If the exchange is not existant it will be created. The session is
# taken from the session_pool.
- 1
class RabbitmqPushHandler < Base
# :nodoc:
- 1
class ConfirmationFailed < StandardError
- 1
def initialize(channel, nacked, unconfirmed)
super("Message confirmation on the exchange #{channel} has failed\
- 1
(#{nacked}/#{unconfirmed}).")
end
end
# Setup the rublisher with configuring via the config options. The
# following config options are supported:
# @rabbit_mq_url url to connect to RabbitMQ
# @pool_size size of the connection pool to be used. Defaults to 1
# @session_params a hash definiting the params passed to the session.
# @heartbeat heartbeat interval used to communicate with
# RabbitMQ.
# @exchange_name name of the exchange defaults to 'fos.context_request'
# @exchange_type type of the exchange defaults to ''
# @exchange_options options passed to the exchange if it has to be
# created.
# rubocop:disable Metrics/MethodLength
- 1
def initialize(**config)
- 3
@config = config.dup
- 3
@session_params = config.fetch(:session_params, {})
.merge(threaded: false,
automatically_recover: false,
heartbeat: config[:heartbeat])
- 3
pool_size = @session_params.delete(:session_pool) || 1
- 3
@session_params.freeze
- 3
@session_pool = ConnectionPool.new(size: pool_size) do
- 3
Bunny.new(config[:rabbit_mq_url], @session_params)
end
- 3
config_clean
end
# rubocop:enable Metrics/MethodLength
# Publishes the given data on the exchange. The exchange is created if
# it does not exist.
# @data a hash representing the data to be published as json.
# @options options to be passed to the publish to the exchange.
- 1
def push(data, options)
- 3
@session_pool.with do |session|
- 3
session.start
- 3
channel = session.create_channel
- 3
channel.confirm_select
- 3
exchange = fetch_exchange(session, channel)
- 3
exchange.publish(data.to_json, **options)
- 3
wait_for_confirms(channel)
- 2
channel.close
end
end
- 1
private
- 1
def wait_for_confirms(channel)
- 3
return if channel.wait_for_confirms
- 1
raise ConfirmationFailed.new(exchange_name, channel.nacked_set,
channel.unconfirmed_set)
end
- 1
def config_clean
- 3
@config.delete(:rabbit_mq_url)
- 3
@config.delete(:session_params)
- 3
@config.delete(:heartbeat)
end
# return the channel if a channel is already there otherwise create a new
# exchange with the predefined settings.
# Can be overwriten by ContextRequestMiddleware.fetch_exchange_callback
- 1
def fetch_exchange(_session, channel)
- 3
channel.exchanges[exchange_name] || bunny_exchange(channel)
end
- 1
def bunny_exchange(channel)
- 1
Bunny::Exchange.new(channel, exchange_type, exchange_name,
exchange_options)
end
- 1
def exchange_name
- 5
@exchange_name ||= @config.fetch(:exchange_name, 'fos.context_request')
end
- 1
def exchange_type
- 1
@config.fetch(:exchange_type, 'topic')
end
- 1
def exchange_options
- 1
@config.fetch(:exchange_options, {})
end
end
end
end
# frozen_string_literal: true
- 1
require 'rabbitmq_client'
- 1
require 'context_request_middleware/push_handler/base'
- 1
module ContextRequestMiddleware
- 1
module PushHandler
# PushHandler that publishes the data given to a RabbitMQ exchange.
# If the exchange is not existent it will be created. The session is
# taken from the session_pool.
- 1
class RabbitmqPushHandlerAsync < Base
# Setup the publisher with configuring via the config options. The
# following config options are supported:
# @rabbitmq_url url to connect to RabbitMQ
# @pool_size size of the connection pool to be used. Defaults to 1
# @session_params a hash defining the params passed to the session.
# @heartbeat_publisher heartbeat interval used to communicate with
# RabbitMQ.
# @exchange_name name of the exchange defaults to 'fos.context_request'
# @exchange_type type of the exchange defaults to ''
# @exchange_options options passed to the exchange if it has to be
# created.
- 1
def initialize(**config)
- 1
@config = config.dup
- 1
exchange = RabbitmqClient::ExchangeRegistry.new
- 1
exchange.add(exchange_name, exchange_type, exchange_options)
- 1
@config[:exchange_registry] = exchange
- 1
@publisher = RabbitmqClient::Publisher.new(@config)
- 1
config_clean
end
# Publishes the given data on the exchange.
# @data a hash representing the data to be published.
# @options options to be passed to the publish to the exchange.
- 1
def push(data, options)
- 1
@publisher.publish(data,
options.merge(exchange_name: exchange_name))
end
- 1
private
- 1
def config_clean
- 1
@config.delete(:rabbitmq_url)
- 1
@config.delete(:session_params)
- 1
@config.delete(:heartbeat)
end
- 1
def exchange_name
- 2
@exchange_name ||= @config.fetch(:exchange_name, 'fos.context_request')
end
- 1
def exchange_type
- 1
@config.fetch(:exchange_type, 'topic')
end
- 1
def exchange_options
- 1
@config.fetch(:exchange_options, {})
end
end
end
end
# frozen_string_literal: true
# Module to provide helper functions on request headers, methods, cookies
- 1
require 'context_request_middleware/request/cookie_session_id_retriever'
- 1
module ContextRequestMiddleware
# :nodoc:
- 1
module Request
- 1
extend self
- 1
def retriever_for_request(request)
ContextRequestMiddleware
.load_class_from_name(
ContextRequestMiddleware.request_context_retriever,
ContextRequestMiddleware::Request.to_s,
ContextRequestMiddleware.request_context_retriever_version
- 6
)&.new(request)
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
- 1
module Request
# Class for retrieving the session if set via rack cookie.
# This requires the session id to be stored in '_session_id'
# cookie key.
- 1
class CookieSessionIdRetriever
- 1
include ActiveSupport::Configurable
- 1
include ContextRequestMiddleware::Cookie
- 1
def initialize(request)
- 8
@request = request
end
- 1
def call
- 8
cookie_session_id(@request)
end
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
# :nodoc:
- 1
module SamplingHandler
- 1
extend self
- 1
def from_request
ContextRequestMiddleware
.load_class_from_name(ContextRequestMiddleware.sampling_handler,
ContextRequestMiddleware::SamplingHandler.to_s,
ContextRequestMiddleware.sampling_handler_version)
- 5
&.new
end
end
end
# frozen_string_literal: true
- 1
module ContextRequestMiddleware
- 1
module SamplingHandler
# Simple sampling handler that samples every request.
- 1
class AcceptAll
- 1
def valid?(_request)
- 4
true
end
end
end
end