-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Action Cable implementation, FixityCheckChannel, and tests
- Loading branch information
Showing
22 changed files
with
470 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# frozen_string_literal: true | ||
|
||
class FixityCheckChannel < ApplicationCable::Channel | ||
FIXITY_CHECK_STREAM_PREFIX = "#{CHECK_PLEASE['action_cable_stream_prefix']}fixity_check:".freeze | ||
|
||
# A websocket client subscribes by sending this message: | ||
# { | ||
# "command" => "subscribe", | ||
# "identifier" => { "channel" => "FixityCheckChannel", "job_identifier" => "cool-job-id1" }.to_json | ||
# } | ||
def subscribed | ||
return if params[:job_identifier].blank? | ||
|
||
stream_name = "#{FIXITY_CHECK_STREAM_PREFIX}#{params[:job_identifier]}" | ||
Rails.logger.debug "A client has started streaming from: #{stream_name}" | ||
stream_from stream_name | ||
end | ||
|
||
def unsubscribed | ||
# Any cleanup needed when channel is unsubscribed | ||
return if params[:job_identifier].blank? | ||
|
||
stream_name = "#{FIXITY_CHECK_STREAM_PREFIX}#{params[:job_identifier]}" | ||
Rails.logger.debug "A client has stopped streaming from: #{stream_name}" | ||
stop_stream_from stream_name | ||
end | ||
|
||
# A websocket client runs this command by sending this message: | ||
# { | ||
# "command" => "run_fixity_check_for_s3_object", | ||
# "identifier" => { "channel" => "FixityCheckChannel", "job_identifier" => "cool-job-id1" }.to_json, | ||
# "data" => { | ||
# "action" => "run_fixity_check_for_s3_object", "bucket_name" => "some-bucket", | ||
# "object_path" => "path/to/object.png", "checksum_algorithm_name" => "sha256" | ||
# }.to_json | ||
# } | ||
def run_fixity_check_for_s3_object(data) | ||
Rails.logger.debug("run_fixity_check_for_s3_object action received with job_identifier: #{params[:job_identifier]}") | ||
job_identifier = params[:job_identifier] | ||
bucket_name = data['bucket_name'] | ||
object_path = data['object_path'] | ||
checksum_algorithm_name = data['checksum_algorithm_name'] | ||
|
||
AwsCheckFixityJob.perform_later(job_identifier, bucket_name, object_path, checksum_algorithm_name) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# frozen_string_literal: true | ||
|
||
# rubocop:disable Metrics/MethodLength | ||
|
||
class AwsCheckFixityJob < ApplicationJob | ||
queue_as CheckPlease::Queues::CHECK_FIXITY | ||
|
||
def perform(job_identifier, bucket_name, object_path, checksum_algorithm_name) | ||
response_stream_name = "#{FixityCheckChannel::FIXITY_CHECK_STREAM_PREFIX}#{job_identifier}" | ||
progress_report_lambda = lambda { |_chunk, _bytes_read, chunk_counter| | ||
return unless (chunk_counter % 100).zero? | ||
|
||
# TODO: Broadcast a message to indicate that the processing is still happening. | ||
# This way, clients will know if a job has stalled and will not wait indefinitely for results. | ||
ActionCable.server.broadcast( | ||
response_stream_name, | ||
{ type: 'fixity_check_in_progress' }.to_json | ||
) | ||
} | ||
|
||
checksum_hexdigest, object_size = CheckPlease::Aws::ObjectFixityChecker.check( | ||
bucket_name, | ||
object_path, | ||
checksum_algorithm_name, | ||
on_chunk: progress_report_lambda | ||
) | ||
|
||
# Broadcast message when job is complete | ||
broadcast_fixity_check_complete( | ||
response_stream_name, bucket_name, object_path, checksum_algorithm_name, checksum_hexdigest, object_size | ||
) | ||
rescue StandardError => e | ||
broadcast_fixity_check_error(response_stream_name, e.message, bucket_name, object_path, checksum_algorithm_name) | ||
end | ||
|
||
def broadcast_fixity_check_complete( | ||
response_stream_name, bucket_name, object_path, checksum_algorithm_name, checksum_hexdigest, object_size | ||
) | ||
ActionCable.server.broadcast( | ||
response_stream_name, | ||
{ | ||
type: 'fixity_check_complete', | ||
data: { | ||
bucket_name: bucket_name, object_path: object_path, | ||
checksum_algorithm_name: checksum_algorithm_name, | ||
checksum_hexdigest: checksum_hexdigest, object_size: object_size | ||
} | ||
}.to_json | ||
) | ||
end | ||
|
||
def broadcast_fixity_check_error( | ||
response_stream_name, error_message, bucket_name, object_path, checksum_algorithm_name | ||
) | ||
ActionCable.server.broadcast( | ||
response_stream_name, | ||
{ | ||
type: 'fixity_check_error', | ||
data: { | ||
error_message: error_message, bucket_name: bucket_name, | ||
object_path: object_path, checksum_algorithm_name: checksum_algorithm_name | ||
} | ||
}.to_json | ||
) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
development: | ||
# adapter: async | ||
adapter: redis | ||
url: redis://localhost:6379/1 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,9 @@ | ||
development: | ||
run_queued_jobs_inline: true | ||
remote_request_api_key: changethis | ||
action_cable_stream_prefix: '<%= "#{Rails.application.class.module_parent_name}:#{Rails.env}:" %>' | ||
|
||
test: | ||
run_queued_jobs_inline: true | ||
run_queued_jobs_inline: true | ||
remote_request_api_key: changethis | ||
action_cable_stream_prefix: '<%= "#{Rails.application.class.module_parent_name}:#{Rails.env}:" %>' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
module CheckPlease::Queues | ||
CHECK_FIXITY = 'check_fixity' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe ApplicationCable::Connection, type: :channel do | ||
let(:uuid_regex) { /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/ } | ||
let(:invalid_authorization_header_value) { "Bearer: invalid-#{CHECK_PLEASE['remote_request_api_key']}" } | ||
let(:valid_authorization_header_value) { "Bearer: #{CHECK_PLEASE['remote_request_api_key']}" } | ||
|
||
it 'rejects a connection when no authorization header is given' do | ||
expect { connect '/cable' }.to have_rejected_connection | ||
end | ||
|
||
it 'rejects a connection when an invalid authorization header value is given' do | ||
expect { | ||
connect '/cable', headers: { 'Authorization' => invalid_authorization_header_value } | ||
}.to have_rejected_connection | ||
end | ||
|
||
it "successfully connects and assigns a uuid value to the connection's uuid field" do | ||
connect '/cable', headers: { 'Authorization' => valid_authorization_header_value } | ||
expect(connection.uuid).to match(uuid_regex) | ||
end | ||
end |
Oops, something went wrong.