Skip to content

Commit

Permalink
Added wrapper for config files and images
Browse files Browse the repository at this point in the history
  • Loading branch information
kevicency committed Oct 21, 2011
1 parent 3722164 commit d516961
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 169 deletions.
2 changes: 2 additions & 0 deletions Gemfile.lock
Expand Up @@ -24,6 +24,7 @@ GEM
rack (>= 1.0.0)
tilt (1.3.3)
uuidtools (2.1.2)
work_queue (2.0.0)

PLATFORMS
ruby
Expand All @@ -36,3 +37,4 @@ DEPENDENCIES
sinatra (= 1.2.6)
thin
uuidtools
work_queue
4 changes: 2 additions & 2 deletions cfg/picassound.json
@@ -1,9 +1,9 @@
{
"recommend_endpoint": "http://localhost:8080/iOS/Recommend",
"endpoint": "http://localhost:8080/iOS/Recommend",
"song_file": "/local/picassound/index/songs",
"base_file": "/local/picassound/base",
"samples_file": "/local/picassound/index/samples",
"data_file": "/local/picassound/index/data",
"mappings_dir": "/local/picassound/mappings3/",
"image_dir": "/local/picassound/images/"
"image_dir": "/mnt/images/"
}
19 changes: 14 additions & 5 deletions lib/picloud.rb
Expand Up @@ -3,16 +3,25 @@

require "rubygems"

module Picloud
def self.root_dir
File.expand_path("../..", __FILE__)
end

def self.version
"0.6.0".freeze
end
end

require "picloud/config"
require "picloud/errors"
require "picloud/image"
require "picloud/picassound"
require "picloud/profile"
require "picloud/recommendation"
require "picloud/s3_entity"
require "picloud/server"
require "picloud/server_legacy"
require "picloud/songlist"

module Picloud
def self.version
"0.6.0".freeze
end
end

15 changes: 15 additions & 0 deletions lib/picloud/config.rb
@@ -0,0 +1,15 @@
require "json"

module Picloud
module Config
["aws", "aws_keys", "picassound"].each do |cfg|
cfg_file = File.join(Picloud.root_dir, "cfg/#{cfg}.json")
cfg_hash = JSON.parse((File.read cfg_file), :symbolize_names => true)
cfg_hash.each do |k,v|
define_singleton_method k do
v
end
end
end
end
end
27 changes: 27 additions & 0 deletions lib/picloud/image.rb
@@ -0,0 +1,27 @@
require "picloud/config"
require "uuidtools"

module Picloud
class Image
attr_reader :data, :type, :size, :id, :path

def initialize(type, data)
@type = type
@data = data
@size = data.length
end

def id
@id ||= UUIDTools::UUID.random_create.to_s
end

def store
Dir.mkdir Config.image_dir unless Dir.exists? Config.image_dir
file_name = "#{id.to_s}.#{type}"
@path = File.join(Config.image_dir, file_name)
File.open(path, "w") {|f| f.write data}

@path
end
end
end
49 changes: 8 additions & 41 deletions lib/picloud/picassound.rb
@@ -1,6 +1,5 @@
require "net/http"
require "json"
require "uuidtools"

## Picloud::Picassound

Expand All @@ -9,59 +8,36 @@ module Picloud
class Picassound

DEFAULT_ENDPOINT = "http://localhost:8080/iOS/Recommend"
DEFAULT_IMAGE_DIR = "/local/picassound/images"

# Creates a new Picassound instance. It expects two parameters:
#
# * `endpoint`: Endpoint of the Picassound web service. _Defaults to
# Picassound::DEFAULT_ENDPOINT_.
#
# * `image_dir`: Directory where the images are stored. _Defaults to
# Picassound::DEFAULT_IMAGE_DIR_.
#
def initialize(endpoint = nil, image_dir = nil)
def initialize(endpoint = nil)
@endpoint = URI.parse(endpoint || DEFAULT_ENDPOINT)
@image_dir = image_dir || DEFAULT_IMAGE_DIR
end

# Recommends songs for an `image` from the list of `available_song_ids`.
# Returns the ids of recommended songs for the `image`. The recommended
# song ids are a subset from the `available_song_ids`.
# If `available_song_ids` is omitted, all known songs are used for
# recommendation
def recommend(image, available_song_ids = nil)
image_file = store_image image
image_path = image.path || image.store # store the image if it isn't already stored
params = {
Image: image_file
Image: image_path
}
params[:SongIds] = available_song_ids.join(",") unless available_song_ids.nil?

request params
end

# Recommends songs for an `image`. The list of available songs is derived
# from the Profile which belongs to the `profile_id`
def recommend_for_profile(image, profile_id)
image_file = store_image image
params = {
Image: image_file,
ProfileId: profile_id
}
request params
do_request params
end

## Private Methods

private

# Creates the params for the recommendation request
def recommend_params(image_file, song_ids = nil)
params = { Image: image_file }
params[:SongIds] = song_ids.join(",") unless song_ids.nil?

return params
end

# Request the recommended songs for `params` from the Picassound Web Service
def request(params)
# Request the recommended songs for `params` from the Picassound Web Service
def do_request(params)
res = Net::HTTP.post_form(@endpoint, params)

if res.is_a? Net::HTTPSuccess
Expand All @@ -70,14 +46,5 @@ def request(params)
raise Picloud::RecommendationError.new res.message
end
end

# Stores the `image` on disk and returns the path to the `image`
def store_image(image)
name = "#{UUIDTools::UUID.random_create.to_s}.#{image[:type]}"
path = File.join(@image_dir, name)
File.open(path, "w") {|f| f.write image[:data]}

path
end
end
end
6 changes: 5 additions & 1 deletion lib/picloud/profile.rb
@@ -1,5 +1,5 @@
require "json"
require "picloud/s3_entity.rb"
require "picloud/s3_entity"
#require "picloud/errors"

# # Picloud::Profile
Expand All @@ -23,6 +23,10 @@ def initialize(device_id, songs, id = nil)
@songs = songs
end

def song_ids
@songs.map { |song| song[:id] }
end

# JSON representation of the *Profile*.
# This method is required by the *S3Entity* Mixin.
def serialize
Expand Down
12 changes: 0 additions & 12 deletions lib/picloud/recommendation.rb

This file was deleted.

26 changes: 4 additions & 22 deletions lib/picloud/s3_entity.rb
Expand Up @@ -39,33 +39,15 @@ def delete(id)
((key id).delete if exists? id) || false
end

#### Private Class Methods

private

# Return a hash which contains data that is needed by the S3 Interface
def s3_config
if @s3_config.nil?
cfg_dir = File.expand_path("../../../cfg", __FILE__)
puts cfg_dir
@s3_config = {}
["aws_keys.json", "aws.json"].each do |cfg|
cfg_file = File.join(cfg_dir, cfg)
@s3_config.merge! JSON.parse((File.read cfg_file), :symbolize_names => true)
end
end
@s3_config
end

# S3 Interface
def s3
@s3 ||= RightAws::S3.new(s3_config[:access_key],
s3_config[:secret_key])
@s3 ||= RightAws::S3.new(Config.access_key,
Config.secret_key)
end

# The S3 bucket
def bucket
s3.bucket s3_config[:bucket_name]
s3.bucket Config.bucket_name
end

# Returns a bucket key for `id`
Expand All @@ -76,7 +58,7 @@ def key(id)

# The encoding to which the JSON string is encoded before uploading
def encoding
s3_config[:encoding]
Config.encoding
end
end

Expand Down
52 changes: 23 additions & 29 deletions lib/picloud/server.rb
Expand Up @@ -16,10 +16,8 @@ class Server < Sinatra::Base

def initialize
super
config_file = File.join(settings.root, "cfg/picassound.json")
config = JSON.parse((File.read config_file), :symbolize_names => true)
@songlist = Songlist.load config[:song_file]
@picassound = Picassound.new(config[:recommend_endpoint], config[:image_dir])
@songlist = Songlist.load Config.song_file
@picassound = Picassound.new Config.endpoint
end

get "/" do
Expand Down Expand Up @@ -86,23 +84,17 @@ def initialize
end

post "/profiles/:id/recommend" do
image = {
type: (get_image_type request.content_type),
data: (request.body.read)
}
halt 400, "Invalid Content-Type" unless image[:type]

begin
recommended_song_ids = @picassound.recommend_for_profile(image, params[:id])
image = get_image request
rofile = Profile.load(profile_id)
recommended_song_ids = @picassound.recommend(image, profile.song_ids)

content_type :json
recommended_song_ids.map do |id|
@songlist[id]
end.to_json
rescue Picloud::RecommendationError => ex
puts "error"
puts ex.message
halt 400, ex.message
rescue RuntimeError
halt 400, "Invalid Request.\n#{ex.message}"
end
end

Expand All @@ -114,25 +106,27 @@ def initialize
end

post "/recommend" do
image = {
type: (get_image_type request.content_type),
data: (request.body.read)
}
halt 400, "Invalid Content-Type" unless image[:type]
ids = params[:song_ids].split(",").map{|id| id.to_i} if params[:song_ids]
recommended_song_ids = @picassound.recommend(image, ids)
begin
image = get_image request
song_ids = params[:song_ids].split(",").map{|id| id.to_i} if params[:song_ids]
recommended_song_ids = @picassound.recommend(image, song_ids)

content_type :json
recommended_song_ids.map do |id|
@songlist[id]
end.to_json
content_type :json
recommended_song_ids.map do |id|
@songlist[id]
end.to_json
rescue RuntimeError
halt 400, "Invalid Request.\n#{ex.message}"
end
end

private

def get_image_type(content_type)
match = content_type.match(/image\/(?<type>\w+)/) if content_type
match[:type] if match
def get_image(request)
type_match = request.content_type.match(/image\/(?<type>\w+)/)
type = type_match[:type] if type_match

Image.new(type, request.body.read)
end

# Endpoint for the Load Balancer healthy check
Expand Down

0 comments on commit d516961

Please sign in to comment.