Class: Guillotine::RiakAdapter

Inherits:
Adapter
  • Object
show all
Defined in:
lib/guillotine/adapters/riak_adapter.rb

Overview

Stores shortened URLs in Riak. Totally scales.

Constant Summary collapse

PLAIN =
'text/plain'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Adapter

#parse_url, #shorten

Constructor Details

#initialize(code_bucket, url_bucket = nil) ⇒ RiakAdapter

Initializes the adapter.

code_bucket - The Riak::Bucket for all code keys. url_bucket - The Riak::Bucket for all url keys. If this is not

given, the code bucket is used for all keys.


14
15
16
17
# File 'lib/guillotine/adapters/riak_adapter.rb', line 14

def initialize(code_bucket, url_bucket = nil)
  @code_bucket = code_bucket
  @url_bucket  = url_bucket || @code_bucket
end

Instance Attribute Details

#code_bucketObject (readonly)

Returns the value of attribute code_bucket.



7
8
9
# File 'lib/guillotine/adapters/riak_adapter.rb', line 7

def code_bucket
  @code_bucket
end

#url_bucketObject (readonly)

Returns the value of attribute url_bucket.



7
8
9
# File 'lib/guillotine/adapters/riak_adapter.rb', line 7

def url_bucket
  @url_bucket
end

Instance Method Details

#add(url, code = nil) ⇒ Object

Public: Stores the shortened version of a URL.

url - The String URL to shorten and store. code - Optional String code for the URL.

Returns the unique String code for the URL. If the URL is added multiple times, this should return the same code.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/guillotine/adapters/riak_adapter.rb', line 26

def add(url, code = nil)
  sha     = url_key url
  url_obj = @url_bucket.get_or_new sha, :r => 1
  if url_obj.raw_data
    fix_url_object(url_obj)
    code = url_obj.data
  end

  code   ||= shorten url
  code_obj = @code_bucket.get_or_new code
  code_obj.content_type = url_obj.content_type = PLAIN

  if existing_url = code_obj.data # key exists
    raise DuplicateCodeError.new(existing_url, url, code) if url_key(existing_url) != sha
  end

  if !url_obj.data # unsaved
    url_obj.data = code
    url_obj.store
  end

  code_obj.data = url
  code_obj.store
  code
end

#clear(url) ⇒ Object

Public: Removes the assigned short code for a URL.

url - The String URL to remove.

Returns nothing.



79
80
81
82
83
84
# File 'lib/guillotine/adapters/riak_adapter.rb', line 79

def clear(url)
  if code_obj = code_object(url)
    @url_bucket.delete  code_obj.key
    @code_bucket.delete code_obj.data
  end
end

#code_for(url) ⇒ Object

Public: Retrieves the code for a given URL.

url - The String URL to lookup.

Returns the String code, or nil if none is found.



68
69
70
71
72
# File 'lib/guillotine/adapters/riak_adapter.rb', line 68

def code_for(url)
  if obj = code_object(url)
    obj.data
  end
end

#code_object(url) ⇒ Object

Retrieves the code riak value for a given URL.

url - The String URL to lookup.

Returns a Riak::RObject, or nil if none is found.



102
103
104
105
106
107
108
109
# File 'lib/guillotine/adapters/riak_adapter.rb', line 102

def code_object(url)
  sha = url_key url
  if o = @url_bucket.get(sha, :r => 1)
    fix_url_object(o)
  end
rescue Riak::FailedRequest => err
  raise unless err.not_found?
end

#find(code) ⇒ Object

Public: Retrieves a URL from the code.

code - The String code to lookup the URL.

Returns the String URL.



57
58
59
60
61
# File 'lib/guillotine/adapters/riak_adapter.rb', line 57

def find(code)
  if obj = url_object(code)
    obj.data
  end
end

#fix_url_object(obj, data = nil) ⇒ Object

Fixes a bug in Guillotine 1.0.2 where the content type on url objects was not being set. The ruby Riak::Client defaults to JSON, so strings were being saved as “somecode”, which is unparseable by JSON.



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/guillotine/adapters/riak_adapter.rb', line 114

def fix_url_object(obj, data = nil)
  if data
    obj.content_type = PLAIN
    obj.data = data
    obj.store
    return obj
  end
  case obj.content_type
    when /json/ then fix_url_object(obj, JSON.parse(%({"data":#{obj.raw_data}}))['data'])
    when PLAIN  then obj
    else fix_url_object(obj, obj.data) # old values had the right data but the content type was application/x-www-form-urlencoded
  end
end

#url_key(url) ⇒ Object



128
129
130
# File 'lib/guillotine/adapters/riak_adapter.rb', line 128

def url_key(url)
  Digest::SHA1.hexdigest url.downcase
end

#url_object(code) ⇒ Object

Retrieves a URL riak value from the code.

code - The String code to lookup the URL.

Returns a Riak::RObject, or nil if none is found.



91
92
93
94
95
# File 'lib/guillotine/adapters/riak_adapter.rb', line 91

def url_object(code)
  @code_bucket.get(code, :r => 1)
rescue Riak::FailedRequest => err
  raise unless err.not_found?
end