aws-sdk-rails 4.0.3 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +261 -0
- data/LICENSE.txt +12 -0
- data/VERSION +1 -1
- data/lib/aws/rails/middleware/elastic_beanstalk_sqsd.rb +205 -0
- data/lib/aws/rails/notifications.rb +5 -7
- data/lib/aws/rails/railtie.rb +49 -69
- data/lib/aws-sdk-rails.rb +1 -9
- metadata +14 -197
- data/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb +0 -79
- data/bin/aws_sqs_active_job +0 -6
- data/config/routes.rb +0 -8
- data/lib/action_dispatch/session/dynamodb_store.rb +0 -38
- data/lib/active_job/queue_adapters/sqs_adapter/params.rb +0 -78
- data/lib/active_job/queue_adapters/sqs_adapter.rb +0 -58
- data/lib/active_job/queue_adapters/sqs_async_adapter.rb +0 -39
- data/lib/aws/rails/action_mailbox/engine.rb +0 -21
- data/lib/aws/rails/action_mailbox/rspec/email.rb +0 -50
- data/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb +0 -37
- data/lib/aws/rails/action_mailbox/rspec.rb +0 -69
- data/lib/aws/rails/action_mailbox/s3_client.rb +0 -28
- data/lib/aws/rails/action_mailbox/sns_message_verifier.rb +0 -18
- data/lib/aws/rails/action_mailbox/sns_notification.rb +0 -99
- data/lib/aws/rails/middleware/ebs_sqs_active_job_middleware.rb +0 -118
- data/lib/aws/rails/ses_mailer.rb +0 -49
- data/lib/aws/rails/sesv2_mailer.rb +0 -60
- data/lib/aws/rails/sqs_active_job/configuration.rb +0 -184
- data/lib/aws/rails/sqs_active_job/deduplication.rb +0 -21
- data/lib/aws/rails/sqs_active_job/executor.rb +0 -77
- data/lib/aws/rails/sqs_active_job/job_runner.rb +0 -27
- data/lib/aws/rails/sqs_active_job/lambda_handler.rb +0 -63
- data/lib/aws/rails/sqs_active_job/poller.rb +0 -160
- data/lib/aws/rails/sqs_active_job.rb +0 -33
- data/lib/generators/aws_record/base.rb +0 -213
- data/lib/generators/aws_record/generated_attribute.rb +0 -138
- data/lib/generators/aws_record/model/USAGE +0 -24
- data/lib/generators/aws_record/model/model_generator.rb +0 -25
- data/lib/generators/aws_record/model/templates/model.erb +0 -48
- data/lib/generators/aws_record/model/templates/table_config.erb +0 -18
- data/lib/generators/aws_record/secondary_index.rb +0 -66
- data/lib/generators/dynamo_db/session_store_migration/USAGE +0 -13
- data/lib/generators/dynamo_db/session_store_migration/session_store_migration_generator.rb +0 -48
- data/lib/generators/dynamo_db/session_store_migration/templates/dynamo_db_session_store.yml +0 -70
- data/lib/generators/dynamo_db/session_store_migration/templates/session_store_migration.erb +0 -9
- data/lib/tasks/aws_record/migrate.rake +0 -14
- data/lib/tasks/dynamo_db/session_store.rake +0 -10
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module Rails
|
5
|
-
module ActionMailbox
|
6
|
-
module RSpec
|
7
|
-
# @api private
|
8
|
-
class SubscriptionConfirmation
|
9
|
-
def initialize(authentic: true, topic: 'topic:arn:default')
|
10
|
-
@authentic = authentic
|
11
|
-
@topic = topic
|
12
|
-
end
|
13
|
-
|
14
|
-
def url
|
15
|
-
'/rails/action_mailbox/ses/inbound_emails'
|
16
|
-
end
|
17
|
-
|
18
|
-
def headers
|
19
|
-
{ 'content-type' => 'application/json' }
|
20
|
-
end
|
21
|
-
|
22
|
-
def params
|
23
|
-
{
|
24
|
-
'Type' => 'SubscriptionConfirmation',
|
25
|
-
'TopicArn' => @topic,
|
26
|
-
'SubscribeURL' => 'http://example.com/subscribe'
|
27
|
-
}
|
28
|
-
end
|
29
|
-
|
30
|
-
def authentic?
|
31
|
-
@authentic
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'aws/rails/action_mailbox/rspec/email'
|
4
|
-
require 'aws/rails/action_mailbox/rspec/subscription_confirmation'
|
5
|
-
require 'aws-sdk-sns'
|
6
|
-
require 'aws/rails/action_mailbox/sns_message_verifier'
|
7
|
-
|
8
|
-
module Aws
|
9
|
-
module Rails
|
10
|
-
module ActionMailbox
|
11
|
-
# Include the `Aws::Rails::ActionMailbox::RSpec` extension in your tests, like so:
|
12
|
-
# require 'aws/rails/action_mailbox/rspec'
|
13
|
-
# RSpec.configure do |config|
|
14
|
-
# config.include Aws::Rails::ActionMailbox::RSpec
|
15
|
-
# end
|
16
|
-
# Then, in a request spec, use like so:
|
17
|
-
# RSpec.describe 'amazon emails', type: :request do
|
18
|
-
# it 'delivers a subscription notification' do
|
19
|
-
# action_mailbox_ses_deliver_subscription_confirmation
|
20
|
-
# expect(response).to have_http_status :ok
|
21
|
-
# end
|
22
|
-
|
23
|
-
# it 'delivers an email notification' do
|
24
|
-
# action_mailbox_ses_deliver_email(mail: Mail.new(to: 'user@example.com'))
|
25
|
-
# expect(ActionMailbox::InboundEmail.last.mail.recipients).to eql ['user@example.com']
|
26
|
-
# end
|
27
|
-
# end
|
28
|
-
module RSpec
|
29
|
-
def action_mailbox_ses_deliver_subscription_confirmation(options = {})
|
30
|
-
subscription_confirmation = SubscriptionConfirmation.new(**options)
|
31
|
-
stub_aws_sns_message_verifier(subscription_confirmation)
|
32
|
-
stub_aws_sns_subscription_request
|
33
|
-
|
34
|
-
post subscription_confirmation.url,
|
35
|
-
params: subscription_confirmation.params,
|
36
|
-
headers: subscription_confirmation.headers,
|
37
|
-
as: :json
|
38
|
-
end
|
39
|
-
|
40
|
-
def action_mailbox_ses_deliver_email(options = {})
|
41
|
-
email = Email.new(**options)
|
42
|
-
stub_aws_sns_message_verifier(email)
|
43
|
-
|
44
|
-
post email.url,
|
45
|
-
params: email.params,
|
46
|
-
headers: email.headers,
|
47
|
-
as: :json
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def message_verifier(subscription_confirmation)
|
53
|
-
instance_double(Aws::SNS::MessageVerifier, authentic?: subscription_confirmation.authentic?)
|
54
|
-
end
|
55
|
-
|
56
|
-
def stub_aws_sns_message_verifier(notification)
|
57
|
-
allow(Aws::Rails::ActionMailbox::SnsMessageVerifier).to receive(:verifier) { message_verifier(notification) }
|
58
|
-
end
|
59
|
-
|
60
|
-
def stub_aws_sns_subscription_request
|
61
|
-
allow(Net::HTTP).to receive(:get_response).and_call_original
|
62
|
-
allow(Net::HTTP)
|
63
|
-
.to receive(:get_response)
|
64
|
-
.with(URI('http://example.com/subscribe')) { double(code: '200') }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'aws-sdk-s3'
|
4
|
-
|
5
|
-
module Aws
|
6
|
-
module Rails
|
7
|
-
module ActionMailbox
|
8
|
-
# @api private
|
9
|
-
class S3Client
|
10
|
-
class << self
|
11
|
-
def client
|
12
|
-
@client ||= build_client
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def build_client
|
18
|
-
client = Aws::S3::Client.new(
|
19
|
-
**::Rails.configuration.action_mailbox.ses.s3_client_options
|
20
|
-
)
|
21
|
-
client.config.user_agent_frameworks << 'aws-sdk-rails'
|
22
|
-
client
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'aws-sdk-sns'
|
4
|
-
|
5
|
-
module Aws
|
6
|
-
module Rails
|
7
|
-
module ActionMailbox
|
8
|
-
# @api private
|
9
|
-
class SnsMessageVerifier
|
10
|
-
class << self
|
11
|
-
def verifier
|
12
|
-
@verifier ||= Aws::SNS::MessageVerifier.new
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'aws-sdk-sns'
|
4
|
-
require 'aws/rails/action_mailbox/s3_client'
|
5
|
-
require 'aws/rails/action_mailbox/sns_message_verifier'
|
6
|
-
|
7
|
-
module Aws
|
8
|
-
module Rails
|
9
|
-
module ActionMailbox
|
10
|
-
# @api private
|
11
|
-
class SnsNotification
|
12
|
-
class MessageContentError < StandardError; end
|
13
|
-
|
14
|
-
def initialize(request_body)
|
15
|
-
@request_body = request_body
|
16
|
-
end
|
17
|
-
|
18
|
-
def subscription_confirmed?
|
19
|
-
(200..299).cover?(confirmation_response.code.to_i)
|
20
|
-
end
|
21
|
-
|
22
|
-
def verified?
|
23
|
-
SnsMessageVerifier.verifier.authentic?(@request_body)
|
24
|
-
end
|
25
|
-
|
26
|
-
def topic
|
27
|
-
notification.fetch(:TopicArn)
|
28
|
-
end
|
29
|
-
|
30
|
-
def type
|
31
|
-
notification.fetch(:Type)
|
32
|
-
end
|
33
|
-
|
34
|
-
def message_content
|
35
|
-
raise MessageContentError, 'Incoming emails must have notificationType `Received`' unless receipt?
|
36
|
-
|
37
|
-
if content_in_s3?
|
38
|
-
s3_content
|
39
|
-
else
|
40
|
-
return message[:content] unless destination
|
41
|
-
|
42
|
-
"X-Original-To: #{destination}\n#{message[:content]}"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def notification
|
49
|
-
@notification ||= JSON.parse(@request_body, symbolize_names: true)
|
50
|
-
rescue JSON::ParserError => e
|
51
|
-
Rails.logger.warn("Unable to parse SNS notification: #{e}")
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def s3_content
|
56
|
-
S3Client
|
57
|
-
.client
|
58
|
-
.get_object(key: key, bucket: bucket)
|
59
|
-
.body
|
60
|
-
.string
|
61
|
-
end
|
62
|
-
|
63
|
-
def message
|
64
|
-
@message ||= JSON.parse(notification[:Message], symbolize_names: true)
|
65
|
-
end
|
66
|
-
|
67
|
-
def destination
|
68
|
-
message.dig(:mail, :destination)&.first
|
69
|
-
end
|
70
|
-
|
71
|
-
def action
|
72
|
-
return unless message[:receipt]
|
73
|
-
|
74
|
-
message.fetch(:receipt).fetch(:action)
|
75
|
-
end
|
76
|
-
|
77
|
-
def bucket
|
78
|
-
action.fetch(:bucketName)
|
79
|
-
end
|
80
|
-
|
81
|
-
def key
|
82
|
-
action.fetch(:objectKey)
|
83
|
-
end
|
84
|
-
|
85
|
-
def content_in_s3?
|
86
|
-
action&.fetch(:type) == 'S3'
|
87
|
-
end
|
88
|
-
|
89
|
-
def receipt?
|
90
|
-
message.fetch(:notificationType) == 'Received'
|
91
|
-
end
|
92
|
-
|
93
|
-
def confirmation_response
|
94
|
-
@confirmation_response ||= Net::HTTP.get_response(URI(notification[:SubscribeURL]))
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,118 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module Rails
|
5
|
-
# Middleware to handle requests from the SQS Daemon present on Elastic Beanstalk worker environments.
|
6
|
-
class EbsSqsActiveJobMiddleware
|
7
|
-
INTERNAL_ERROR_MESSAGE = 'Failed to execute job - see Rails log for more details.'
|
8
|
-
INTERNAL_ERROR_RESPONSE = [500, { 'Content-Type' => 'text/plain' }, [INTERNAL_ERROR_MESSAGE]].freeze
|
9
|
-
FORBIDDEN_MESSAGE = 'Request with aws-sqsd user agent was made from untrusted address.'
|
10
|
-
FORBIDDEN_RESPONSE = [403, { 'Content-Type' => 'text/plain' }, [FORBIDDEN_MESSAGE]].freeze
|
11
|
-
|
12
|
-
def initialize(app)
|
13
|
-
@app = app
|
14
|
-
@logger = ::Rails.logger
|
15
|
-
end
|
16
|
-
|
17
|
-
def call(env)
|
18
|
-
request = ActionDispatch::Request.new(env)
|
19
|
-
|
20
|
-
# Pass through unless user agent is the SQS Daemon
|
21
|
-
return @app.call(env) unless from_sqs_daemon?(request)
|
22
|
-
|
23
|
-
@logger.debug('aws-sdk-rails middleware detected call from Elastic Beanstalk SQS Daemon.')
|
24
|
-
|
25
|
-
# Only accept requests from this user agent if it is from localhost or a docker host in case of forgery.
|
26
|
-
unless request.local? || sent_from_docker_host?(request)
|
27
|
-
@logger.warn("SQSD request detected from untrusted address #{request.ip}; returning 403 forbidden.")
|
28
|
-
return FORBIDDEN_RESPONSE
|
29
|
-
end
|
30
|
-
|
31
|
-
# Execute job or periodic task based on HTTP request context
|
32
|
-
periodic_task?(request) ? execute_periodic_task(request) : execute_job(request)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def execute_job(request)
|
38
|
-
# Jobs queued from the Active Job SQS adapter contain the JSON message in the request body.
|
39
|
-
job = Aws::Json.load(request.body.string)
|
40
|
-
job_name = job['job_class']
|
41
|
-
@logger.debug("Executing job: #{job_name}")
|
42
|
-
|
43
|
-
begin
|
44
|
-
ActiveJob::Base.execute(job)
|
45
|
-
rescue NoMethodError, NameError => e
|
46
|
-
@logger.error("Job #{job_name} could not resolve to a class that inherits from Active Job.")
|
47
|
-
@logger.error("Error: #{e}")
|
48
|
-
return INTERNAL_ERROR_RESPONSE
|
49
|
-
end
|
50
|
-
|
51
|
-
[200, { 'Content-Type' => 'text/plain' }, ["Successfully ran job #{job_name}."]]
|
52
|
-
end
|
53
|
-
|
54
|
-
def execute_periodic_task(request)
|
55
|
-
# The beanstalk worker SQS Daemon will add the 'X-Aws-Sqsd-Taskname' for periodic tasks set in cron.yaml.
|
56
|
-
job_name = request.headers['X-Aws-Sqsd-Taskname']
|
57
|
-
@logger.debug("Creating and executing periodic task: #{job_name}")
|
58
|
-
|
59
|
-
begin
|
60
|
-
job = job_name.constantize.new
|
61
|
-
job.perform_now
|
62
|
-
rescue NoMethodError, NameError => e
|
63
|
-
@logger.error("Periodic task #{job_name} could not resolve to an Active Job class - check the spelling in cron.yaml.")
|
64
|
-
@logger.error("Error: #{e}.")
|
65
|
-
return INTERNAL_ERROR_RESPONSE
|
66
|
-
end
|
67
|
-
|
68
|
-
[200, { 'Content-Type' => 'text/plain' }, ["Successfully ran periodic task #{job_name}."]]
|
69
|
-
end
|
70
|
-
|
71
|
-
# The beanstalk worker SQS Daemon sets a specific User-Agent headers that begins with 'aws-sqsd'.
|
72
|
-
def from_sqs_daemon?(request)
|
73
|
-
current_user_agent = request.headers['User-Agent']
|
74
|
-
|
75
|
-
!current_user_agent.nil? && current_user_agent.start_with?('aws-sqsd')
|
76
|
-
end
|
77
|
-
|
78
|
-
# The beanstalk worker SQS Daemon will add the custom 'X-Aws-Sqsd-Taskname' header for periodic tasks set in cron.yaml.
|
79
|
-
def periodic_task?(request)
|
80
|
-
!request.headers['X-Aws-Sqsd-Taskname'].nil? && request.headers['X-Aws-Sqsd-Taskname'].present?
|
81
|
-
end
|
82
|
-
|
83
|
-
def sent_from_docker_host?(request)
|
84
|
-
app_runs_in_docker_container? && default_gw_ips.include?(request.ip)
|
85
|
-
end
|
86
|
-
|
87
|
-
def app_runs_in_docker_container?
|
88
|
-
@app_runs_in_docker_container ||= in_docker_container_with_cgroup1? || in_docker_container_with_cgroup2?
|
89
|
-
end
|
90
|
-
|
91
|
-
def in_docker_container_with_cgroup1?
|
92
|
-
File.exist?('/proc/1/cgroup') && File.read('/proc/1/cgroup') =~ %r{/docker/}
|
93
|
-
end
|
94
|
-
|
95
|
-
def in_docker_container_with_cgroup2?
|
96
|
-
File.exist?('/proc/self/mountinfo') && File.read('/proc/self/mountinfo') =~ %r{/docker/containers/}
|
97
|
-
end
|
98
|
-
|
99
|
-
def default_gw_ips
|
100
|
-
default_gw_ips = ['172.17.0.1']
|
101
|
-
|
102
|
-
if File.exist?('/proc/net/route')
|
103
|
-
File.open('/proc/net/route').each_line do |line|
|
104
|
-
fields = line.strip.split
|
105
|
-
next if fields.size != 11
|
106
|
-
|
107
|
-
# Destination == 0.0.0.0 and Flags & RTF_GATEWAY != 0
|
108
|
-
if fields[1] == '00000000' && (fields[3].hex & 0x2) != 0
|
109
|
-
default_gw_ips << IPAddr.new_ntoh([fields[2].hex].pack('L')).to_s
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
default_gw_ips
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
data/lib/aws/rails/ses_mailer.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'aws-sdk-ses'
|
4
|
-
|
5
|
-
module Aws
|
6
|
-
module Rails
|
7
|
-
# Provides a delivery method for ActionMailer that uses Amazon Simple Email
|
8
|
-
# Service.
|
9
|
-
#
|
10
|
-
# Once you have an SES delivery method you can configure Rails to
|
11
|
-
# use this for ActionMailer in your environment configuration
|
12
|
-
# (e.g. RAILS_ROOT/config/environments/production.rb)
|
13
|
-
#
|
14
|
-
# config.action_mailer.delivery_method = :ses
|
15
|
-
#
|
16
|
-
# Uses the AWS SDK for Ruby's credential provider chain when creating an SES
|
17
|
-
# client instance.
|
18
|
-
class SesMailer
|
19
|
-
# @param [Hash] options Passes along initialization options to
|
20
|
-
# [Aws::SES::Client.new](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SES/Client.html#initialize-instance_method).
|
21
|
-
def initialize(options = {})
|
22
|
-
@client = SES::Client.new(options)
|
23
|
-
@client.config.user_agent_frameworks << 'aws-sdk-rails'
|
24
|
-
end
|
25
|
-
|
26
|
-
# Rails expects this method to exist, and to handle a Mail::Message object
|
27
|
-
# correctly. Called during mail delivery.
|
28
|
-
def deliver!(message)
|
29
|
-
params = {
|
30
|
-
raw_message: { data: message.to_s },
|
31
|
-
source: message.smtp_envelope_from, # defaults to From header
|
32
|
-
destinations: message.smtp_envelope_to # defaults to destinations (To,Cc,Bcc)
|
33
|
-
}
|
34
|
-
@client.send_raw_email(params).tap do |response|
|
35
|
-
message.header[:ses_message_id] = response.message_id
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# ActionMailer expects this method to be present and to return a hash.
|
40
|
-
def settings
|
41
|
-
{}
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# This is for backwards compatibility after introducing support for SESv2.
|
48
|
-
# The old mailer is now replaced with the new SES (v1) mailer.
|
49
|
-
Aws::Rails::Mailer = Aws::Rails::SesMailer
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'aws-sdk-sesv2'
|
4
|
-
|
5
|
-
module Aws
|
6
|
-
module Rails
|
7
|
-
# Provides a delivery method for ActionMailer that uses Amazon Simple Email
|
8
|
-
# Service V2.
|
9
|
-
#
|
10
|
-
# Once you have an SESv2 delivery method you can configure Rails to
|
11
|
-
# use this for ActionMailer in your environment configuration
|
12
|
-
# (e.g. RAILS_ROOT/config/environments/production.rb)
|
13
|
-
#
|
14
|
-
# config.action_mailer.delivery_method = :sesv2
|
15
|
-
#
|
16
|
-
# Uses the AWS SDK for Ruby's credential provider chain when creating an SESV2
|
17
|
-
# client instance.
|
18
|
-
class Sesv2Mailer
|
19
|
-
# @param [Hash] options Passes along initialization options to
|
20
|
-
# [Aws::SESV2::Client.new](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html#initialize-instance_method).
|
21
|
-
def initialize(options = {})
|
22
|
-
@client = SESV2::Client.new(options)
|
23
|
-
@client.config.user_agent_frameworks << 'aws-sdk-rails'
|
24
|
-
end
|
25
|
-
|
26
|
-
# Rails expects this method to exist, and to handle a Mail::Message object
|
27
|
-
# correctly. Called during mail delivery.
|
28
|
-
def deliver!(message)
|
29
|
-
params = { content: { raw: { data: message.to_s } } }
|
30
|
-
# smtp_envelope_from will default to the From address *without* sender names.
|
31
|
-
# By omitting this param, SESv2 will correctly use sender names from the mail headers.
|
32
|
-
# We should only use smtp_envelope_from when it was explicitly set (instance variable set)
|
33
|
-
params[:from_email_address] = message.smtp_envelope_from if message.instance_variable_get(:@smtp_envelope_from)
|
34
|
-
params[:destination] = {
|
35
|
-
to_addresses: to_addresses(message),
|
36
|
-
cc_addresses: message.cc,
|
37
|
-
bcc_addresses: message.bcc
|
38
|
-
}
|
39
|
-
|
40
|
-
@client.send_email(params).tap do |response|
|
41
|
-
message.header[:ses_message_id] = response.message_id
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# ActionMailer expects this method to be present and to return a hash.
|
46
|
-
def settings
|
47
|
-
{}
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
# smtp_envelope_to will default to the full destinations (To, Cc, Bcc)
|
53
|
-
# SES v2 API prefers each component split out into a destination hash.
|
54
|
-
# When smtp_envelope_to was set, use it explicitly for to_address only.
|
55
|
-
def to_addresses(message)
|
56
|
-
message.instance_variable_get(:@smtp_envelope_to) ? message.smtp_envelope_to : message.to
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,184 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module Rails
|
5
|
-
# Configuration for AWS SQS ActiveJob.
|
6
|
-
module SqsActiveJob
|
7
|
-
# Use +Aws::Rails::SqsActiveJob.config+ to access the singleton config instance.
|
8
|
-
class Configuration
|
9
|
-
# Default configuration options
|
10
|
-
# @api private
|
11
|
-
DEFAULTS = {
|
12
|
-
max_messages: 10,
|
13
|
-
shutdown_timeout: 15,
|
14
|
-
retry_standard_errors: true, # TODO: Remove in next MV
|
15
|
-
queues: {},
|
16
|
-
logger: ::Rails.logger,
|
17
|
-
message_group_id: 'SqsActiveJobGroup',
|
18
|
-
excluded_deduplication_keys: ['job_id']
|
19
|
-
}.freeze
|
20
|
-
|
21
|
-
# @api private
|
22
|
-
attr_accessor :queues, :max_messages, :visibility_timeout,
|
23
|
-
:shutdown_timeout, :client, :logger,
|
24
|
-
:async_queue_error_handler, :message_group_id
|
25
|
-
|
26
|
-
attr_reader :excluded_deduplication_keys
|
27
|
-
|
28
|
-
# Don't use this method directly: Configuration is a singleton class, use
|
29
|
-
# +Aws::Rails::SqsActiveJob.config+ to access the singleton config.
|
30
|
-
#
|
31
|
-
# @param [Hash] options
|
32
|
-
# @option options [Hash[Symbol, String]] :queues A mapping between the
|
33
|
-
# active job queue name and the SQS Queue URL. Note: multiple active
|
34
|
-
# job queues can map to the same SQS Queue URL.
|
35
|
-
#
|
36
|
-
# @option options [Integer] :max_messages
|
37
|
-
# The max number of messages to poll for in a batch.
|
38
|
-
#
|
39
|
-
# @option options [Integer] :visibility_timeout
|
40
|
-
# If unset, the visibility timeout configured on the
|
41
|
-
# SQS queue will be used.
|
42
|
-
# The visibility timeout is the number of seconds
|
43
|
-
# that a message will not be processable by any other consumers.
|
44
|
-
# You should set this value to be longer than your expected job runtime
|
45
|
-
# to prevent other processes from picking up an running job.
|
46
|
-
# See the (SQS Visibility Timeout Documentation)[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html]
|
47
|
-
#
|
48
|
-
# @option options [Integer] :shutdown_timeout
|
49
|
-
# the amount of time to wait
|
50
|
-
# for a clean shutdown. Jobs that are unable to complete in this time
|
51
|
-
# will not be deleted from the SQS queue and will be retryable after
|
52
|
-
# the visibility timeout.
|
53
|
-
#
|
54
|
-
# @ option options [Boolean] :retry_standard_errors
|
55
|
-
# If `true`, StandardErrors raised by ActiveJobs are left on the queue
|
56
|
-
# and will be retried (pending the SQS Queue's redrive/DLQ/maximum receive settings).
|
57
|
-
# This behavior overrides the standard Rails ActiveJob
|
58
|
-
# [Retry/Discard for failed jobs](https://guides.rubyonrails.org/active_job_basics.html#retrying-or-discarding-failed-jobs)
|
59
|
-
# behavior. When set to `true` the retries provided by this will be
|
60
|
-
# on top of any retries configured on the job with `retry_on`.
|
61
|
-
# When `false`, retry behavior is fully configured
|
62
|
-
# through `retry_on`/`discard_on` on the ActiveJobs.
|
63
|
-
#
|
64
|
-
# @option options [ActiveSupport::Logger] :logger Logger to use
|
65
|
-
# for the poller.
|
66
|
-
#
|
67
|
-
# @option options [String] :config_file
|
68
|
-
# Override file to load configuration from. If not specified will
|
69
|
-
# attempt to load from config/aws_sqs_active_job.yml.
|
70
|
-
#
|
71
|
-
# @option options [String] :message_group_id (SqsActiveJobGroup)
|
72
|
-
# The message_group_id to use for queueing messages on a fifo queues.
|
73
|
-
# Applies only to jobs queued on FIFO queues.
|
74
|
-
# See the (SQS FIFO Documentation)[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html]
|
75
|
-
#
|
76
|
-
# @option options [Callable] :async_queue_error_handler An error handler
|
77
|
-
# to be called when the async active job adapter experiances an error
|
78
|
-
# queueing a job. Only applies when
|
79
|
-
# +active_job.queue_adapter = :sqs_async+. Called with:
|
80
|
-
# [error, job, job_options]
|
81
|
-
#
|
82
|
-
# @option options [SQS::Client] :client SQS Client to use. A default
|
83
|
-
# client will be created if none is provided.
|
84
|
-
#
|
85
|
-
# @option options [Array] :excluded_deduplication_keys (['job_id'])
|
86
|
-
# The type of keys stored in the array should be String or Symbol.
|
87
|
-
# Using this option, job_id is implicitly added to the keys.
|
88
|
-
|
89
|
-
def initialize(options = {})
|
90
|
-
options[:config_file] ||= config_file if File.exist?(config_file)
|
91
|
-
options = DEFAULTS
|
92
|
-
.merge(file_options(options))
|
93
|
-
.merge(options)
|
94
|
-
set_attributes(options)
|
95
|
-
end
|
96
|
-
|
97
|
-
def excluded_deduplication_keys=(keys)
|
98
|
-
@excluded_deduplication_keys = keys.map(&:to_s) | ['job_id']
|
99
|
-
end
|
100
|
-
|
101
|
-
def client
|
102
|
-
@client ||= begin
|
103
|
-
client = Aws::SQS::Client.new
|
104
|
-
client.config.user_agent_frameworks << 'aws-sdk-rails'
|
105
|
-
client
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Return the queue_url for a given job_queue name
|
110
|
-
def queue_url_for(job_queue)
|
111
|
-
job_queue = job_queue.to_sym
|
112
|
-
raise ArgumentError, "No queue defined for #{job_queue}" unless queues.key? job_queue
|
113
|
-
|
114
|
-
queues[job_queue]
|
115
|
-
end
|
116
|
-
|
117
|
-
# @api private
|
118
|
-
def to_s
|
119
|
-
to_h.to_s
|
120
|
-
end
|
121
|
-
|
122
|
-
# @api private
|
123
|
-
def to_h
|
124
|
-
h = {}
|
125
|
-
instance_variables.each do |v|
|
126
|
-
v_sym = v.to_s.delete('@').to_sym
|
127
|
-
val = instance_variable_get(v)
|
128
|
-
h[v_sym] = val
|
129
|
-
end
|
130
|
-
h
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
# Set accessible attributes after merged options.
|
136
|
-
def set_attributes(options)
|
137
|
-
options.each_key do |opt_name|
|
138
|
-
instance_variable_set("@#{opt_name}", options[opt_name])
|
139
|
-
client.config.user_agent_frameworks << 'aws-sdk-rails' if opt_name == :client
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def file_options(options = {})
|
144
|
-
file_path = config_file_path(options)
|
145
|
-
if file_path
|
146
|
-
load_from_file(file_path)
|
147
|
-
else
|
148
|
-
{}
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def config_file
|
153
|
-
file = ::Rails.root.join("config/aws_sqs_active_job/#{::Rails.env}.yml")
|
154
|
-
file = ::Rails.root.join('config/aws_sqs_active_job.yml') unless File.exist?(file)
|
155
|
-
file
|
156
|
-
end
|
157
|
-
|
158
|
-
# Load options from YAML file
|
159
|
-
def load_from_file(file_path)
|
160
|
-
opts = load_yaml(file_path) || {}
|
161
|
-
opts.deep_symbolize_keys
|
162
|
-
end
|
163
|
-
|
164
|
-
# @return [String] Configuration path found in environment or YAML file.
|
165
|
-
def config_file_path(options)
|
166
|
-
options[:config_file] || ENV.fetch('AWS_SQS_ACTIVE_JOB_CONFIG_FILE', nil)
|
167
|
-
end
|
168
|
-
|
169
|
-
def load_yaml(file_path)
|
170
|
-
require 'erb'
|
171
|
-
source = ERB.new(File.read(file_path)).result
|
172
|
-
|
173
|
-
# Avoid incompatible changes with Psych 4.0.0
|
174
|
-
# https://bugs.ruby-lang.org/issues/17866
|
175
|
-
begin
|
176
|
-
YAML.safe_load(source, aliases: true) || {}
|
177
|
-
rescue ArgumentError
|
178
|
-
YAML.safe_load(source) || {}
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module Rails
|
5
|
-
# SQS ActiveJob modules
|
6
|
-
module SqsActiveJob
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
included do
|
10
|
-
class_attribute :excluded_deduplication_keys
|
11
|
-
end
|
12
|
-
|
13
|
-
# class methods for SQS ActiveJob.
|
14
|
-
module ClassMethods
|
15
|
-
def deduplicate_without(*keys)
|
16
|
-
self.excluded_deduplication_keys = keys.map(&:to_s) | ['job_id']
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|