lib/mail_room/delivery/sidekiq.rb
require "redis"
require "securerandom"
require "json"
require "charlock_holmes"
module MailRoom
module Delivery
# Sidekiq Delivery method
# @author Douwe Maan
class Sidekiq
Options = Struct.new(:redis_url, :namespace, :sentinels, :queue, :worker, :logger, :redis_db) do
def initialize(mailbox)
redis_url = mailbox.delivery_options[:redis_url] || "redis://localhost:6379"
redis_db = mailbox.delivery_options[:redis_db] || 0
namespace = mailbox.delivery_options[:namespace]
sentinels = mailbox.delivery_options[:sentinels]
queue = mailbox.delivery_options[:queue] || "default"
worker = mailbox.delivery_options[:worker]
logger = mailbox.logger
if namespace
warn <<~MSG
Redis namespaces are deprecated. This option will be ignored in future versions.
See https://github.com/sidekiq/sidekiq/issues/2586 for more details."
MSG
end
super(redis_url, namespace, sentinels, queue, worker, logger, redis_db)
end
end
attr_accessor :options
# Build a new delivery, hold the mailbox configuration
# @param [MailRoom::Delivery::Sidekiq::Options]
def initialize(options)
@options = options
end
# deliver the message by pushing it onto the configured Sidekiq queue
# @param message [String] the email message as a string, RFC822 format
def deliver(message)
item = item_for(message)
client.lpush("queue:#{options.queue}", JSON.generate(item))
@options.logger.info({ delivery_method: 'Sidekiq', action: 'message pushed' })
true
end
private
def client
@client ||= begin
sentinels = options.sentinels
redis_options = { url: options.redis_url, db: options.redis_db }
redis_options[:sentinels] = sentinels if sentinels
redis = ::Redis.new(redis_options)
namespace = options.namespace
if namespace
require 'redis/namespace'
Redis::Namespace.new(namespace, redis: redis)
else
redis
end
end
end
def item_for(message)
{
'class' => options.worker,
'args' => [utf8_encode_message(message)],
'queue' => options.queue,
'jid' => SecureRandom.hex(12),
'retry' => false,
'enqueued_at' => Time.now.to_f
}
end
def utf8_encode_message(message)
message = message.dup
message.force_encoding("UTF-8")
return message if message.valid_encoding?
detection = CharlockHolmes::EncodingDetector.detect(message)
return message unless detection && detection[:encoding]
# Convert non-UTF-8 body UTF-8 so it can be dumped as JSON.
CharlockHolmes::Converter.convert(message, detection[:encoding], 'UTF-8')
end
end
end
end