class Typingpool::Project::Remote::S3

Subclass for storing remote files on Amazon Simple Storage Service (S3)

Attributes

url[R]

Returns the base URL, which is prepended to the remote files. This is either the 'url' attribute of the Config#amazon value passed to Project::Remote::S3.new or, if that attribute is not set, the value returned by 'default_url' (e.g. “bucketname.s3.amazonaws.com”).

Public Class Methods

from_config(config_amazon) click to toggle source

Takes a Config#amazon, extracts the needed params, and returns a Project::Remote::S3 instance. Raises an exception of type Error::File::Remote::S3 if any required params (key, secret, bucket) are missing from the config.

# File lib/typingpool/project/remote/s3.rb, line 14
def self.from_config(config_amazon)
  key = config_amazon.key or raise Error::File::Remote::S3, "Missing Amazon key in config"
  secret = config_amazon.secret or raise Error::File::Remote::S3, "Missing Amazon secret in config"
  bucket_name = config_amazon.bucket or raise Error::File::Remote::S3, "Missing Amazon bucket in config"
  url = config_amazon.url
  new(key, secret, bucket_name, url)
end
new(key, secret, bucket, url=nil) click to toggle source

Constructor. Takes an Amazon AWS access key id, secret access key, bucket name, and optional URL prefix.

# File lib/typingpool/project/remote/s3.rb, line 48
def initialize(key, secret, bucket, url=nil)
  @key = key 
  @secret = secret
  @bucket_name = bucket 
  @url = url || default_url
end
random_bucket_name(length=16, prefix='typingpool-') click to toggle source

Takes an optional length for the random sequence, 16 by default, and an optional bucket name prefix, 'typingpool-' by default. Returns a string safe for use as both an S3 bucket and as a subdomain. Random charcters are drawn from [a-z0-9], though the first character in the returned string will always be a letter.

# File lib/typingpool/project/remote/s3.rb, line 28
def self.random_bucket_name(length=16, prefix='typingpool-')
  charset = [(0 .. 9).to_a, ('a' .. 'z').to_a].flatten
  if prefix.to_s.empty? && (length > 0)
    #ensure subdomain starts with a letter
    prefix = ('a' .. 'z').to_a[SecureRandom.random_number(26)]
    length -= 1
  end
  random_sequence = (1 .. length).map{ charset[ SecureRandom.random_number(charset.count) ] }
  [prefix.to_s, random_sequence].join
end

Public Instance Methods

host() click to toggle source

The remote host (server) name, parsed from url

# File lib/typingpool/project/remote/s3.rb, line 56
def host
  URI.parse(@url).host
end
path() click to toggle source

The remote path (directory), pased from url

# File lib/typingpool/project/remote/s3.rb, line 61
def path
  URI.parse(@url).path
end
put(io_streams, as=io_streams.map{|file| File.basename(file)}) { |stream, dest| ... } click to toggle source

Upload files/strings to S3, optionally changing the names in the process.

==== Params
io_streams

Enumerable collection of IO objects, like a File or StringIO instance. Each IO object must repond to the methods rewind, read, and eof? (so no pipes, sockets, etc)

as

Optional if the io_streams are File instances. Array of file basenames, used to name the destination files. Default is the basename of the Files passed in as io_streams.

&block

Optional. Passed an io_stream and destination name just before each upload

==== Returns

Array of URLs corresponding to the uploaded files.

# File lib/typingpool/project/remote/s3.rb, line 79
def put(io_streams, as=io_streams.map{|file| File.basename(file)})
  batch(io_streams) do |stream, i|
    dest = as[i]
    yield(stream, dest) if block_given?
    begin
      s3.buckets[@bucket_name].objects[dest].write(stream, :acl => :public_read)
    rescue AWS::S3::Errors::NoSuchBucket
      s3.buckets.create(@bucket_name, :acl => :public_read)
      stream.rewind
      retry
    end #begin
    file_to_url(dest)
  end #batch
end
remove(files) { |file| ... } click to toggle source

Delete objects from S3.

==== Params
files

Enumerable collection of file names. Should NOT include the bucket name (path).

&block

Optional. Passed a file name before each delete.

==== Returns

Nil

# File lib/typingpool/project/remote/s3.rb, line 101
def remove(files)
  batch(files) do |file, i|
    yield(file) if block_given?
    s3.buckets[@bucket_name].objects[file].delete
  end
  nil
end

Protected Instance Methods

batch(io_streams) { |stream, i| ... } click to toggle source
# File lib/typingpool/project/remote/s3.rb, line 111
def batch(io_streams)
  results = []
  io_streams.each_with_index do |stream, i|
    begin
      results.push(yield(stream, i))
    rescue AWS::S3::Errors::InvalidAccessKeyId
      raise Error::File::Remote::S3::Credentials, "S3 operation failed because your AWS access key ID  is wrong. Double-check your config file."
    rescue AWS::S3::Errors::SignatureDoesNotMatch
      raise Error::File::Remote::S3::Credentials, "S3 operation failed with a signature error. This likely means your AWS secret access key is wrong."
    rescue AWS::Errors::Base => e
      raise Error::File::Remote::S3, "Your S3 operation failed with an Amazon error: #{e} (#{e.class})"
    end #begin
  end #io_streams.each_with_index
  results
end
default_url() click to toggle source
# File lib/typingpool/project/remote/s3.rb, line 134
def default_url
  "https://#{@bucket_name}.s3.amazonaws.com"
end
s3() click to toggle source
# File lib/typingpool/project/remote/s3.rb, line 127
def s3
  AWS::S3.new(
             :access_key_id => @key,
             :secret_access_key => @secret
             )
end