Class: Angelo::Base

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
ParamsParser, Celluloid::Logger
Defined in:
lib/angelo/base.rb

Defined Under Namespace

Classes: ChunkedResponse, EventSource

Constant Summary

Constants included from ParamsParser

ParamsParser::AMPERSAND, ParamsParser::EMPTY_JSON, ParamsParser::EQUALS, ParamsParser::SEMICOLON

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ParamsParser

#content_type?, #form_encoded?, #json?, #parse_formencoded, #parse_post_body, #parse_query_string, #recurse_symhash

Constructor Details

#initialize(responder) ⇒ Base

Returns a new instance of Base.



204
205
206
207
# File 'lib/angelo/base.rb', line 204

def initialize responder
  @responder = responder
  @klass = self.class
end

Class Attribute Details

.app_fileObject

Returns the value of attribute app_file.



15
16
17
# File 'lib/angelo/base.rb', line 15

def app_file
  @app_file
end

.serverObject

Returns the value of attribute server.



15
16
17
# File 'lib/angelo/base.rb', line 15

def server
  @server
end

Instance Attribute Details

#responderObject

Returns the value of attribute responder.



11
12
13
# File 'lib/angelo/base.rb', line 11

def responder
  @responder
end

Class Method Details

.addr(a = nil) ⇒ Object



43
44
45
46
# File 'lib/angelo/base.rb', line 43

def addr a = nil
  @addr = a if a
  @addr
end

.after(opts = {}, &block) ⇒ Object



125
126
127
# File 'lib/angelo/base.rb', line 125

def after opts = {}, &block
  filter :after, opts, &block
end

.before(opts = {}, &block) ⇒ Object



121
122
123
# File 'lib/angelo/base.rb', line 121

def before opts = {}, &block
  filter :before, opts, &block
end

.compile!(name, &block) ⇒ Object



83
84
85
86
87
88
# File 'lib/angelo/base.rb', line 83

def compile! name, &block
  define_method name, &block
  method = instance_method name
  remove_method name
  method
end

.content_type(type) ⇒ Object



163
164
165
# File 'lib/angelo/base.rb', line 163

def content_type type
  Responder.content_type type
end

.eventsource(path, headers = nil, &block) ⇒ Object



139
140
141
# File 'lib/angelo/base.rb', line 139

def eventsource path, headers = nil, &block
  routes[:get][path] = Responder::Eventsource.new headers, &block
end

.filter(which, opts = {}, &block) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/angelo/base.rb', line 102

def filter which, opts = {}, &block
  f = compile! :filter, &block
  case opts
  when String
    filter_by which, opts, f
  when Hash
    if opts[:path]
      filter_by which, opts[:path], f
    else
      filters[which][:default] << f
    end
  end
end

.filter_by(which, path, meth) ⇒ Object



116
117
118
119
# File 'lib/angelo/base.rb', line 116

def filter_by which, path, meth
  filters[which][path] ||= []
  filters[which][path] << meth
end

.filtersObject



98
99
100
# File 'lib/angelo/base.rb', line 98

def filters
  @filters ||= {before: {default: []}, after: {default: []}}
end

.inherited(subclass) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/angelo/base.rb', line 17

def inherited subclass

  # set app_file from caller stack
  #
  subclass.app_file = caller(1).map {|l| l.split(/:(?=|in )/, 3)[0,1]}.flatten[0]

  # bring RequestError into this namespace
  #
  subclass.class_eval 'class RequestError < Angelo::RequestError; end'

  subclass.addr DEFAULT_ADDR
  subclass.port DEFAULT_PORT

  subclass.ping_time DEFAULT_PING_TIME
  subclass.log_level DEFAULT_LOG_LEVEL

  class << subclass

    def root
      @root ||= File.expand_path '..', app_file
    end

  end

end

.local_path(path) ⇒ Object



185
186
187
188
189
190
# File 'lib/angelo/base.rb', line 185

def local_path path
  if public_dir
    lp = File.join(public_dir, path)
    File.file?(lp) ? lp : nil
  end
end

.log_level(ll = nil) ⇒ Object



48
49
50
51
# File 'lib/angelo/base.rb', line 48

def log_level ll = nil
  @log_level = ll if ll
  @log_level
end

.on_pong(&block) ⇒ Object



143
144
145
# File 'lib/angelo/base.rb', line 143

def on_pong &block
  Responder::Websocket.on_pong = block
end

.ping_time(pt = nil) ⇒ Object



53
54
55
56
# File 'lib/angelo/base.rb', line 53

def ping_time pt = nil
  @ping_time = pt if pt
  @ping_time
end

.port(p = nil) ⇒ Object



58
59
60
61
# File 'lib/angelo/base.rb', line 58

def port p = nil
  @port = p if p
  @port
end

.public_dir(d = nil) ⇒ Object



69
70
71
72
73
# File 'lib/angelo/base.rb', line 69

def public_dir d = nil
  @public_dir = d if d
  @public_dir ||= DEFAULT_PUBLIC_DIR
  File.join root, @public_dir
end

.report_errors!Object



75
76
77
# File 'lib/angelo/base.rb', line 75

def report_errors!
  @report_errors = true
end

.report_errors?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/angelo/base.rb', line 79

def report_errors?
  !!@report_errors
end

.routesObject



90
91
92
93
94
95
96
# File 'lib/angelo/base.rb', line 90

def routes
  @routes ||= {}
  ROUTABLE.each do |m|
    @routes[m] ||= {}
  end
  @routes
end

.run(_addr = addr, _port = port, blocking = false) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/angelo/base.rb', line 171

def run _addr = addr, _port = port, blocking = false
  Celluloid.logger.level = log_level
  @server = Angelo::Server.new self, _addr, _port
  @server.async.ping_websockets
  if blocking
    trap "INT" do
      @server.terminate if @server and @server.alive?
      exit
    end
    sleep
  end
  @server
end

.run!(_addr = addr, _port = port) ⇒ Object



167
168
169
# File 'lib/angelo/base.rb', line 167

def run! _addr = addr, _port = port
  run _addr, _port, true
end

.sse_event(event_name, data) ⇒ Object



192
193
194
195
# File 'lib/angelo/base.rb', line 192

def sse_event event_name, data
  data = data.to_json if Hash === data
  SSE_EVENT_TEMPLATE % [event_name.to_s, data]
end

.sse_message(data) ⇒ Object



197
198
199
200
# File 'lib/angelo/base.rb', line 197

def sse_message data
  data = data.to_json if Hash === data
  SSE_DATA_TEMPLATE % data
end

.sses(reject = true) ⇒ Object



157
158
159
160
161
# File 'lib/angelo/base.rb', line 157

def sses reject = true
  @sses ||= Stash::SSE.new server
  @sses.reject! &:closed? if reject
  @sses
end

.task(name, &block) ⇒ Object



147
148
149
# File 'lib/angelo/base.rb', line 147

def task name, &block
  Angelo::Server.define_task name, &block
end

.views_dir(d = nil) ⇒ Object



63
64
65
66
67
# File 'lib/angelo/base.rb', line 63

def views_dir d = nil
  @views_dir = d if d
  @views_dir ||= DEFAULT_VIEWS_DIR
  File.join root, @views_dir
end

.websocket(path, &block) ⇒ Object



135
136
137
# File 'lib/angelo/base.rb', line 135

def websocket path, &block
  routes[:websocket][path] = Responder::Websocket.new &block
end

.websockets(reject = true) ⇒ Object



151
152
153
154
155
# File 'lib/angelo/base.rb', line 151

def websockets reject = true
  @websockets ||= Stash::Websocket.new server
  @websockets.reject! &:closed? if reject
  @websockets
end

Instance Method Details

#async(meth, *args) ⇒ Object



209
210
211
# File 'lib/angelo/base.rb', line 209

def async meth, *args
  self.class.server.async.__send__ meth, *args
end

#chunked_response(&block) ⇒ Object



331
332
333
334
# File 'lib/angelo/base.rb', line 331

def chunked_response &block
  transfer_encoding :chunked
  ChunkedResponse.new &block
end

#eventsource(&block) ⇒ Object



315
316
317
318
319
# File 'lib/angelo/base.rb', line 315

def eventsource &block
  headers SSE_HEADER
  async :handle_event_source, EventSource.new(responder), block
  halt 200, :sse
end

#filter(which) ⇒ Object



325
326
327
328
329
# File 'lib/angelo/base.rb', line 325

def filter which
  fs = self.class.filters[which][:default]
  fs += self.class.filters[which][request.path] if self.class.filters[which][request.path]
  fs.each {|f| f.bind(self).call}
end

#future(meth, *args) ⇒ Object



213
214
215
# File 'lib/angelo/base.rb', line 213

def future meth, *args
  self.class.server.future.__send__ meth, *args
end

#halt(status = 400, body = '') ⇒ Object



269
270
271
# File 'lib/angelo/base.rb', line 269

def halt status = 400, body = ''
  throw :halt, HALT_STRUCT.new(status, body)
end

#paramsObject



217
218
219
220
221
222
223
224
# File 'lib/angelo/base.rb', line 217

def params
  @params ||= case request.method
              when GET, DELETE, OPTIONS
                parse_query_string
              when POST, PUT
                parse_post_body
              end
end

#request_headersObject



226
227
228
229
230
231
232
233
234
235
# File 'lib/angelo/base.rb', line 226

def request_headers
  @request_headers ||= Hash.new do |hash, key|
    if Symbol === key
      k = key.to_s.upcase
      k.gsub! UNDERSCORE, DASH
      rhv = request.headers.select {|header_key,v| header_key.upcase == k}
      hash[key] = rhv.values.first
    end
  end
end

#send_data(data, opts = {}) ⇒ Object



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/angelo/base.rb', line 295

def send_data data, opts = {}
  # Content-Type
  #
  headers CONTENT_TYPE_HEADER_KEY =>
    (MIME::Types.type_for(File.extname(opts[:filename]))[0].content_type rescue HTML_TYPE)

  # Content-Disposition
  #
  if opts[:disposition] == :attachment
    headers CONTENT_DISPOSITION_HEADER_KEY =>
      ATTACHMENT_CONTENT_DISPOSITION % opts[:filename]
  end

  # Content-Length
  #
  headers CONTENT_LENGTH_HEADER_KEY => data.length

  halt 200, data
end

#send_file(local_file, opts = {}) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/angelo/base.rb', line 273

def send_file local_file, opts = {}
  lp = self.class.local_path local_file

  # Content-Type
  #
  headers CONTENT_TYPE_HEADER_KEY =>
    (MIME::Types.type_for(File.extname(lp))[0].content_type rescue HTML_TYPE)

  # Content-Disposition
  #
  if opts[:disposition] == :attachment or opts[:filename]
    headers CONTENT_DISPOSITION_HEADER_KEY =>
      ATTACHMENT_CONTENT_DISPOSITION % (opts[:filename] or File.basename(lp))
  end

  # Content-Length
  #
  headers CONTENT_LENGTH_HEADER_KEY => File.size(lp)

  halt 200, File.read(lp)
end

#sleep(time) ⇒ Object



321
322
323
# File 'lib/angelo/base.rb', line 321

def sleep time
  Celluloid.sleep time
end