class Canistor::Storage::Bucket
Holds information about a bucket and implements interaction with it.
Attributes
name[RW]
objects[R]
region[RW]
settings[R]
uploads[R]
Public Class Methods
new(**attributes)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 22 def initialize(**attributes) @settings = Settings.new clear attributes.each do |name, value| public_send("#{name}=", value) end end
Public Instance Methods
[](name)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 36 def [](name) @objects[name] end
[]=(name, value)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 40 def []=(name, value) @objects[name] = value end
allow_access_to(access_key_ids)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 142 def allow_access_to(access_key_ids) settings.allow_access_keys(access_key_ids) end
clear()
click to toggle source
# File lib/canistor/storage/bucket.rb, line 126 def clear @objects = Canistor::Storage::Objects.new( versioned: settings.versioned? ) @uploads = {} end
delete(context, access_key_id, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 115 def delete(context, access_key_id, subject) if !settings.access_keys.include?(access_key_id) Canistor::ErrorHandler.serve_access_denied(context, subject) elsif objects[subject.key] object = @objects.delete(subject.key) object.delete(context, subject) else Canistor::ErrorHandler.serve_no_such_key(context, subject) end end
dig(*segments)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 44 def dig(*segments) @objects.dig(*segments) end
get(context, access_key_id, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 58 def get(context, access_key_id, subject) params = CGI::parse(context.http_request.endpoint.query.to_s) catch(:rendered_error) do if !settings.access_keys.include?(access_key_id) Canistor::ErrorHandler.serve_access_denied(context, subject) elsif params.has_key?('uploads') list_bucket_uploads(context) elsif params.has_key?('uploadId') list_bucket_upload_parts(context, subject, params) elsif subject.key.nil? || subject.key == '' list_bucket(context) elsif object = objects[subject.key] object.get(context, subject) else Canistor::ErrorHandler.serve_no_such_key(context, subject) end end end
head(context, access_key_id, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 48 def head(context, access_key_id, subject) if !settings.access_keys.include?(access_key_id) Canistor::ErrorHandler.serve_access_denied(context, subject) elsif object = objects[subject.key] object.head(context, subject) else Canistor::ErrorHandler.serve_no_such_key(context, subject) end end
post(context, access_key_id, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 95 def post(context, access_key_id, subject) if settings.access_keys.include?(access_key_id) Canistor.take_fail(:store) { return } params = CGI::parse(context.http_request.endpoint.query.to_s) catch(:rendered_error) do if params.has_key?('uploads') # Client wants to create a new upload when uploads is present in # the query. post_upload(context, subject) elsif params.has_key?('uploadId') # Client wants to complete the upload when uploadId is present in # the query. complete_upload(context, subject, params) end end else Canistor::ErrorHandler.serve_access_denied(context, subject) end end
put(context, access_key_id, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 77 def put(context, access_key_id, subject) if settings.access_keys.include?(access_key_id) Canistor.take_fail(:store) { return } params = CGI::parse(context.http_request.endpoint.query.to_s) catch(:rendered_error) do if params.has_key?('uploadId') # Client wants to create a new upload part when uploadId is # present in the query. put_upload_part(context, subject, params) else put_object(context, subject) end end else Canistor::ErrorHandler.serve_access_denied(context, subject) end end
store_replica(object)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 146 def store_replica(object) replica = object.copy replica.versioned = settings.versioned? self[object.key] = replica end
to_s()
click to toggle source
# File lib/canistor/storage/bucket.rb, line 133 def to_s @objects.values.map do |object| ' * ' + object.label end.join("\n") + @uploads.keys.each do |upload_id| ' - ' + upload_id end.join("\n") end
update_settings(settings)
click to toggle source
Update bucket settings, see Canistor::Storage::Bucket::Settings
for supported configuration.
# File lib/canistor/storage/bucket.rb, line 32 def update_settings(settings) @settings.update(settings) end
Private Instance Methods
build_object(subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 154 def build_object(subject) Canistor::Storage::Object.new( region: subject.region, bucket: subject.bucket, key: subject.key, versioned: settings.versioned? ) end
build_upload(subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 179 def build_upload(subject) Canistor::Storage::Upload.new( region: subject.region, bucket: subject.bucket, key: subject.key ) end
complete_upload(context, subject, params)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 202 def complete_upload(context, subject, params) if upload = uploads.dig(params['uploadId'][0]) object = upload.post(context, subject) self[subject.key] = object else Canistor::ErrorHandler.serve_no_such_upload(context, subject) throw :rendered_error end end
each(prefix:, marker:, max_keys:) { |object| ... }
click to toggle source
Iterate over all objects in the bucket using the filter and pagination options which exist in S3.
# File lib/canistor/storage/bucket.rb, line 214 def each(prefix:, marker:, max_keys:, &block) passed_marker = marker.nil? ? false : true has_prefix = (prefix.to_s.strip == '') ? false : true objects.each do |path, object| if !passed_marker && (!has_prefix || object.key.start_with?(prefix)) yield object max_keys -= 1 unless max_keys.nil? end break if max_keys && max_keys < 1 passed_marker = true if (!passed_marker && object.key == marker) end end
each_upload(upload_id_marker:, key_marker:) { |upload| ... }
click to toggle source
# File lib/canistor/storage/bucket.rb, line 237 def each_upload(upload_id_marker:, key_marker:, &block) uploads.each do |upload_id, upload| if upload_matches?( upload, upload_id_marker: upload_id_marker, key_marker: key_marker ) yield upload end end end
list_bucket(context)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 249 def list_bucket(context) context.http_response.signal_headers( 200, 'date' => Time.now.httpdate, 'x-amz-request-id' => SecureRandom.hex(8).upcase ) unless context.http_request.http_method == 'HEAD' context.http_response.signal_data(to_xml(context)) end end
list_bucket_upload_parts(context, subject, params)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 269 def list_bucket_upload_parts(context, subject, params) upload = uploads.dig(params['uploadId'][0]) if upload && upload.key == subject.key upload.get(context) else Canistor::ErrorHandler.serve_no_such_upload(context, subject) throw :rendered_error end end
list_bucket_uploads(context)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 260 def list_bucket_uploads(context) context.http_response.signal_headers( 200, 'date' => Time.now.httpdate, 'x-amz-request-id' => SecureRandom.hex(8).upcase ) context.http_response.signal_data(to_uploads_xml(context)) end
post_upload(context, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 187 def post_upload(context, subject) upload = build_upload(subject) @uploads[upload.id] = upload upload.put(context, subject) end
put_object(context, subject)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 163 def put_object(context, subject) object = build_object(subject) object.versioned = settings.versioned? object.put(context, subject) self[subject.key] = object replicate(object) end
put_upload_part(context, subject, params)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 193 def put_upload_part(context, subject, params) if upload = uploads.dig(params['uploadId'][0]) upload.put(context, subject) else Canistor::ErrorHandler.serve_no_such_upload(context, subject) throw :rendered_error end end
replicate(object)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 171 def replicate(object) if settings.replicated? settings.replicate_to_buckets.each do |bucket| bucket.store_replica(object) end end end
to_uploads_xml(context)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 305 def to_uploads_xml(context) # Only return uploads with ID's that start with id marker upload_id_marker = context.params[:upload_id_marker] # Only return uploads with keys that start with key marker key_marker = context.params[:key_marker] Nokogiri::XML::Builder.new do |xml| xml.ListMultipartUploadsResult( xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/' ) do xml.Bucket name xml.KeyMarker key_marker xml.UploadIdMarker upload_id_marker each_upload( upload_id_marker: upload_id_marker, key_marker: key_marker ) do |upload| xml.Upload do xml.Key upload.key xml.UploadId upload.id end end end end.to_xml end
to_xml(context)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 279 def to_xml(context) # Only return objects with keys that start with the prefix. prefix = context.params[:prefix] # Return objects until we find a key that matches the marker. Can # be used to group objects. marker = context.params[:marker] # Stop after returning a number of objects. max_keys = context.params[:max_keys] max_keys = max_keys ? max_keys.to_i : nil Nokogiri::XML::Builder.new do |xml| xml.ListBucketResult(xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/') do xml.Name name xml.Prefix xml.Marker xml.MaxKeys max_keys each(prefix: prefix, marker: marker, max_keys: max_keys) do |object| xml.Contents do xml.Key object.key xml.Size object.size xml.StorageClass 'STANDARD' end end end end.to_xml end
upload_matches?(upload, upload_id_marker:, key_marker:)
click to toggle source
# File lib/canistor/storage/bucket.rb, line 227 def upload_matches?(upload, upload_id_marker:, key_marker:) if upload_id_marker && !upload.id.start_with?(upload_id_marker) return false end if key_marker && !upload.key.start_with?(key_marker) return false end true end