module Storage class S3Service < StorageService attr_reader :configuration def initialize(config_service, instance_name) super() @config_service = config_service @instance_name = (instance_name || "").to_sym @configuration = create_configuration @client = create_client end def list_files(folder) @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder) .flat_map { |response| response.contents.map(&:key) } end def folder_present?(folder) response = @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder, max_keys: 1) response.key_count == 1 end def get_presigned_url(file_name, duration, response_content_disposition: nil) Aws::S3::Presigner .new({ client: @client }) .presigned_url(:get_object, bucket: @configuration.bucket_name, key: file_name, expires_in: duration, response_content_disposition:) end def get_file_io(file_name) @client.get_object(bucket: @configuration.bucket_name, key: file_name) .body end def get_file(file_name) @client.get_object(bucket: @configuration.bucket_name, key: file_name) .body.read end def write_file(file_name, data, content_type: nil) if content_type.nil? @client.put_object( body: data, bucket: @configuration.bucket_name, key: file_name, ) else @client.put_object( body: data, bucket: @configuration.bucket_name, key: file_name, content_type:, ) end end def get_file_metadata(file_name) @client.head_object(bucket: @configuration.bucket_name, key: file_name) end def file_exists?(file_name) @client.head_object(bucket: @configuration.bucket_name, key: file_name) true rescue Aws::S3::Errors::NotFound false end def delete_file(file_name) @client.delete_object(bucket: @configuration.bucket_name, key: file_name) end private def create_configuration unless @config_service.s3_config_present? raise "No S3 bucket is present in the configuration" end unless @config_service.s3_buckets.key?(@instance_name) raise "#{@instance_name} instance name could not be found" end bucket_config = @config_service.s3_buckets[@instance_name] StorageConfiguration.new(bucket_config[:credentials]) end def create_client credentials = Aws::ECSCredentials.new Aws::S3::Client.new( region: @configuration.region, credentials:, ) end end class StorageConfiguration attr_reader :access_key_id, :secret_access_key, :bucket_name, :region def initialize(credentials) @access_key_id = credentials[:aws_access_key_id] @secret_access_key = credentials[:aws_secret_access_key] @bucket_name = credentials[:bucket_name] @region = credentials[:aws_region] end def ==(other) @access_key_id == other.access_key_id && @secret_access_key == other.secret_access_key && @bucket_name == other.bucket_name && @region == other.region end end end