class DearS3::Client

Attributes

bucket[RW]
s3[R]

Public Instance Methods

bucket_name() click to toggle source
# File lib/dears3/client.rb, line 31
def bucket_name
  bucket.name
end
configure_website(index_doc, error_doc) click to toggle source
# File lib/dears3/client.rb, line 55
def configure_website index_doc, error_doc
  bucket.configure_website do |cfg|
    cfg.index_document_suffix = index_doc
    cfg.error_document_key = error_doc
  end

  bucket.policy = generate_policy
  # TODO: find more general pattern
  "http://#{ bucket_name }.s3-website-us-east-1.amazonaws.com/"
end
files_in_bucket() click to toggle source
# File lib/dears3/client.rb, line 73
def files_in_bucket
  @files_in_bucket ||= bucket.objects.map &:key
end
generate_policy() click to toggle source
# File lib/dears3/client.rb, line 66
def generate_policy
  policy = AWS::S3::Policy.new
  resources = "arn:aws:s3:::#{ bucket_name }/*"
  policy.allow(actions: [:get_object], resources: resources, principals: :any)
  policy
end
new_bucket?(name) click to toggle source
# File lib/dears3/client.rb, line 27
def new_bucket? name
  !s3.buckets[name].exists?
end
remove_website() click to toggle source
# File lib/dears3/client.rb, line 77
def remove_website
  bucket.remove_website_configuration
  bucket.url
end
set_bucket(name) click to toggle source
# File lib/dears3/client.rb, line 10
def set_bucket name
  self.bucket = s3.buckets[name]

  if new_bucket? name
    s3.buckets.create(bucket.name, acl: :bucket_owner_full_control)
  end

  bucket.name
end
validate_bucket_name(name) click to toggle source
# File lib/dears3/client.rb, line 20
def validate_bucket_name name
  return :Invalid if invalid_bucket_name? name
  return :Unavailable if unavailable_bucket_name? name

  nil
end
walk_and_upload(path, status_proc = nil) click to toggle source
# File lib/dears3/client.rb, line 41
def walk_and_upload path, status_proc = nil
  entries = Dir.entries path
  entries.each do |entry|
    next if entry == File.basename(__FILE__) || entry[0] == '.' 
    nested_entry = (path == "." ? entry : "#{ path }/#{ entry }")
    if File.directory? nested_entry
      walk_and_upload nested_entry, status_proc
      next
    else
      upload nested_entry, status_proc
    end
  end
end
with(s3_connection) click to toggle source
# File lib/dears3/client.rb, line 35
def with s3_connection
  @bucket = nil
  @s3 = s3_connection
  self
end

Private Instance Methods

entry_is_unchanged?(entry, object) click to toggle source
# File lib/dears3/client.rb, line 102
def entry_is_unchanged? entry, object
  # Is object etag equal to the MD5 digest of the entry?
  # Strip opening and closing "\" chars from AWS-formatted etag
  object.etag[1..-2] == ::Digest::MD5.hexdigest(File.read entry)
end
invalid_bucket_name?(name) click to toggle source
# File lib/dears3/client.rb, line 108
def invalid_bucket_name? name
  name.length < 3     or
  name.length > 62    or
  name[-1] == '-'     or
  name.include?(".")  or
  name.include?(";")  or
  name.include?("-.") or
  name.include?(".-")
end
unavailable_bucket_name?(name) click to toggle source
# File lib/dears3/client.rb, line 118
def unavailable_bucket_name? name
  # Try deleting a non-existent object
  # If the action is forbidden, the bucket exists and is taken
  forbidden_exceptions = [AWS::S3::Errors::AccessDenied,
                            AWS::S3::Errors::Forbidden]

  rand_key = (0...20).map { ('a'..'z').to_a[rand(26)] }.join
  begin
    s3.buckets[name].objects[rand_key].delete
  rescue *forbidden_exceptions
    return true
  rescue AWS::S3::Errors::NoSuchBucket
    return false
  end

  false
end
upload(entry, status_proc = nil) click to toggle source
# File lib/dears3/client.rb, line 87
def upload entry, status_proc = nil
  object = bucket.objects[entry]

  if object.exists? && entry_is_unchanged?(entry, object)
    status_proc.call entry, :unchanged
  elsif object.exists?
    status_proc.call entry, :update
  else
    status_proc.call entry, :upload
  end

  content_type = ::MIME::Types.type_for(entry).to_s
  object.write File.open entry, content_type: content_type
end