Class: Gossamer::Broker

Inherits:
Object
  • Object
show all
Includes:
ParamsProcessor
Defined in:
lib/gossamer/broker.rb

Defined Under Namespace

Classes: UnknownFormat, UnknownPath

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ParamsProcessor

#process_params

Constructor Details

#initialize(params = {}) ⇒ Broker

Returns a new instance of Broker.



21
22
23
24
25
# File 'lib/gossamer/broker.rb', line 21

def initialize(params={})
  process_params(params.merge(:REQUIRED => [:cache_address, :cache_namespace], :DEFAULTS => { :default_format => 'html' }))
  @cache = Memcached.new(@cache_address, :namespace => @cache_namespace)
  @resources = {} # key is resource path, value is Scheduler::Event if scheduled for update
end

Instance Attribute Details

#cacheObject

Returns the value of attribute cache.



16
17
18
# File 'lib/gossamer/broker.rb', line 16

def cache
  @cache
end

#cache_addressObject

Returns the value of attribute cache_address.



14
15
16
# File 'lib/gossamer/broker.rb', line 14

def cache_address
  @cache_address
end

#cache_namespaceObject

Returns the value of attribute cache_namespace.



15
16
17
# File 'lib/gossamer/broker.rb', line 15

def cache_namespace
  @cache_namespace
end

#default_formatObject

Returns the value of attribute default_format.



17
18
19
# File 'lib/gossamer/broker.rb', line 17

def default_format
  @default_format
end

Instance Method Details

#[](path) ⇒ Object



33
34
35
36
37
38
39
40
41
# File 'lib/gossamer/broker.rb', line 33

def [](path)
  begin
    resource = @cache.get(path)
    resource.broker = self
    resource
  rescue Memcached::NotFound
    nil
  end
end

#[]=(path, resource) ⇒ Object



43
44
45
# File 'lib/gossamer/broker.rb', line 43

def []=(path, resource)
  put(path, resource)
end

#call(env) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/gossamer/broker.rb', line 77

def call(env)
  request = Rack::Request.new(env)
  response = Rack::Response.new
  begin
    response.body = get(request.path_info, request.params['format'])
    response['Content-Type'] = response.body.type
  rescue UnknownPath, UnknownFormat => e
    ;;warn "Error while handling request for #{request.path_info.inspect}: #{e.inspect}"
    response.status, response.body = 404, "Resource does not exist"
  rescue => e
    ;;warn "Error while handling request for #{request.path_info.inspect}: #{e.inspect}"
    e.backtrace.each { |t| ;;warn "\t" + t }
    response.status, response.body = 500, "Internal error"
  end
  response.finish
end

#cloneObject



27
28
29
30
31
# File 'lib/gossamer/broker.rb', line 27

def clone
  clone = dup
  clone.cache = @cache.clone
  clone
end

#get(path, format = nil) ⇒ Object

Raises:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/gossamer/broker.rb', line 94

def get(path, format=nil)
  format = (format.to_s.empty? ? @default_format : format.to_s.downcase)
  raise UnknownFormat, "Unknown format #{format.inspect} for path #{path.inspect}" if format =~ /[^\w]/
  resource = self[path] or raise UnknownPath, "Unknown path #{path.inspect}"
  begin
    method = resource.method("to_#{format}")
  rescue NameError => e
    raise UnknownFormat, "Unknown format #{format.inspect} for path #{path.inspect}"
  end
  ;;warn "#{path} [#{format}] => #{resource.class}#{(method && method.name) ? '.' + method.name : ''}"
  case format
  when 'html'
    TypedString.new(method.call, "text/html")
  when 'xml'
    TypedString.new(method.call, "application/xml")
  when 'atom'
    TypedString.new(method.call, "application/atom+xml")
  when 'text'
    TypedString.new(method.call, "text/plain")
  else
    TypedString.new(method.call, "application/octet-stream")
  end
end

#post(path, resource) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/gossamer/broker.rb', line 55

def post(path, resource)
  resource.broker = nil
  begin
    @cache.set(path, resource)
  rescue TypeError => e
    raise e, "Couldn't save #{resource.class} to path #{path.inspect}: #{e.inspect}"
  end
  resource.broker = self
end

#put(path, resource) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/gossamer/broker.rb', line 47

def put(path, resource)
  resource.path = path
  post(path, resource)
  if resource.respond_to?(:update) && @resources[path].nil?
    @resources[path] = Scheduler.after_delay(0) { update(resource.path) }
  end
end

#update(path) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/gossamer/broker.rb', line 65

def update(path)
  if (event = @resources[path])
    Scheduler.cancel(event)
    @resources[path] = nil
  end
  broker = clone
  resource = broker[path]
  resource.update
  broker.post(path, resource)
  @resources[path] = Scheduler.after_delay(resource.update_frequency) { update(resource.path) }
end