em-midori 0.0.9.2 → 0.0.9.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6692e87f5ea4a18142263b9562cb6028ebb2ade
4
- data.tar.gz: f04594483fcfd0d6246b69eb3123ee921c909117
3
+ metadata.gz: 10e7c12fb4c851be82d6b1ebf1a5edbdfa8c3b77
4
+ data.tar.gz: 1e8c9cfe8c4cb0416f8e4f2f84ac2160e1825096
5
5
  SHA512:
6
- metadata.gz: 50c92c8b8e94100969250047ca66cde9a48aa9f66c8d7cdde79027128d617309044f628c9f94f082d4b06409c2a7027fe477af69943bca4025b5b5cdc76e0328
7
- data.tar.gz: c8af60ef0b79b5b3d06b8c8878dbcf9ef907df2a4a5b0ab95a75c1ab9d67a4d4abeeaff79d5e5af5edccccc1839af07034aecb35585359a8bc248a2cdd441e06
6
+ metadata.gz: a97cb0557f0865a4198415d9d72f3abf36b0b1929dda53b5fdcd0470c36d9ca99372da9deb3db60a510100052d36ae5e768456be6674d9ead089b4404d0f1e81
7
+ data.tar.gz: 7041791083c422d4b7929bcbb9fb97a43c37d82890333b61eba09a60fae44c355f2bd79c74c56b4dc44c0839d47e3793181f4e94b0a831a457899661218b35fd
data/lib/em-midori.rb CHANGED
@@ -2,6 +2,7 @@ require 'digest/sha1'
2
2
  require 'stringio'
3
3
  require 'eventmachine'
4
4
  require 'fiber'
5
+ require 'logger'
5
6
 
6
7
  require_relative 'em-midori/version'
7
8
  require_relative 'em-midori/string'
data/lib/em-midori/api.rb CHANGED
@@ -3,165 +3,143 @@
3
3
  class Midori::API
4
4
  class << self
5
5
  # Add GET method as a DSL for route definition
6
- # === Attributes
7
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
8
- # === Returns
9
- # nil
10
- # === Examples
11
- # String as router
6
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
7
+ # @yield what to run when route matched
8
+ # @return [ nil ] nil
9
+ # @example String as router
12
10
  # get '/' do
13
11
  # puts 'Hello World'
14
12
  # end
15
13
  #
16
- # Regex as router
14
+ # @example Regex as router
17
15
  # get /\/hello\/(.*?)/ do
18
16
  # puts 'Hello World'
19
17
  # end
20
18
  def get(path, &block) end
21
19
 
22
20
  # Add POST method as a DSL for route definition
23
- # === Attributes
24
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
25
- # === Returns
26
- # nil
27
- # === Examples
28
- # String as router
21
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
22
+ # @yield what to run when route matched
23
+ # @return [ nil ] nil
24
+ # @example String as router
29
25
  # post '/' do
30
26
  # puts 'Hello World'
31
27
  # end
32
28
  #
33
- # Regex as router
29
+ # @example Regex as router
34
30
  # post /\/hello\/(.*?)/ do
35
31
  # puts 'Hello World'
36
32
  # end
37
33
  def post(path, &block) end
38
34
 
39
35
  # Add PUT method as a DSL for route definition
40
- # === Attributes
41
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
42
- # === Returns
43
- # nil
44
- # === Examples
45
- # String as router
36
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
37
+ # @yield what to run when route matched
38
+ # @return [ nil ] nil
39
+ # @example String as router
46
40
  # put '/' do
47
41
  # puts 'Hello World'
48
42
  # end
49
43
  #
50
- # Regex as router
44
+ # @example Regex as router
51
45
  # put /\/hello\/(.*?)/ do
52
46
  # puts 'Hello World'
53
47
  # end
54
48
  def put(path, &block) end
55
49
 
56
50
  # Add DELETE method as a DSL for route definition
57
- # === Attributes
58
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
59
- # === Returns
60
- # nil
61
- # === Examples
62
- # String as router
51
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
52
+ # @yield what to run when route matched
53
+ # @return [ nil ] nil
54
+ # @example String as router
63
55
  # delete '/' do
64
56
  # puts 'Hello World'
65
57
  # end
66
58
  #
67
- # Regex as router
59
+ # @example Regex as router
68
60
  # delete /\/hello\/(.*?)/ do
69
61
  # puts 'Hello World'
70
62
  # end
71
63
  def delete(path, &block) end
72
64
 
73
65
  # Add OPTIONS method as a DSL for route definition
74
- # === Attributes
75
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
76
- # === Returns
77
- # nil
78
- # === Examples
79
- # String as router
66
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
67
+ # @return [ nil ] nil
68
+ # @example String as router
80
69
  # options '/' do
81
70
  # puts 'Hello World'
82
71
  # end
83
72
  #
84
- # Regex as router
73
+ # @example Regex as router
85
74
  # options /\/hello\/(.*?)/ do
86
75
  # puts 'Hello World'
87
76
  # end
88
77
  def options(path, &block) end
89
78
 
90
79
  # Add LINK method as a DSL for route definition
91
- # === Attributes
92
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
93
- # === Returns
94
- # nil
95
- # === Examples
96
- # String as router
80
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
81
+ # @yield what to run when route matched
82
+ # @return [ nil ] nil
83
+ # @example String as router
97
84
  # link '/' do
98
85
  # puts 'Hello World'
99
86
  # end
100
87
  #
101
- # Regex as router
88
+ # @example Regex as router
102
89
  # link /\/hello\/(.*?)/ do
103
90
  # puts 'Hello World'
104
91
  # end
105
92
  def link(path, &block) end
106
93
 
107
94
  # Add UNLINK method as a DSL for route definition
108
- # === Attributes
109
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
110
- # === Returns
111
- # nil
112
- # === Examples
113
- # String as router
95
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
96
+ # @yield what to run when route matched
97
+ # @return [ nil ] nil
98
+ # @example String as router
114
99
  # unlink '/' do
115
100
  # puts 'Hello World'
116
101
  # end
117
102
  #
118
- # Regex as router
103
+ # @example Regex as router
119
104
  # unlink /\/hello\/(.*?)/ do
120
105
  # puts 'Hello World'
121
106
  # end
122
107
  def unlink(path, &block) end
123
108
 
124
109
  # Add WEBSOCKET method as a DSL for route definition
125
- # === Attributes
126
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
127
- # === Returns
128
- # nil
129
- # === Examples
130
- # String as router
131
- # unlink '/' do
110
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
111
+ # @yield what to run when route matched
112
+ # @return [ nil ] nil
113
+ # @example String as router
114
+ # websocket '/' do
132
115
  # puts 'Hello World'
133
116
  # end
134
117
  #
135
- # Regex as router
136
- # unlink /\/hello\/(.*?)/ do
118
+ # @example Regex as router
119
+ # websocket /\/hello\/(.*?)/ do
137
120
  # puts 'Hello World'
138
121
  # end
139
122
  def websocket(path, &block) end
140
123
 
141
124
  # Add EVENTSOURCE method as a DSL for route definition
142
- # === Attributes
143
- # * +path+ [+String+, +Regexp+] - Accepts as part of path in route definition.
144
- # === Returns
145
- # nil
146
- # === Examples
147
- # String as router
148
- # unlink '/' do
125
+ # @param [ String, Regexp ] path Accepts as part of path in route definition
126
+ # @return [ nil ] nil
127
+ # @example String as router
128
+ # eventsource '/' do
149
129
  # puts 'Hello World'
150
130
  # end
151
131
  #
152
- # Regex as router
153
- # unlink /\/hello\/(.*?)/ do
132
+ # @example Regex as router
133
+ # eventsource /\/hello\/(.*?)/ do
154
134
  # puts 'Hello World'
155
135
  # end
156
136
  def eventsource(path, &block) end
157
137
 
158
138
  # Implementation of route DSL
159
- # === Attributes
160
- # * +method+ [+String+] - HTTP method
161
- # * +path+ [+String+, +Regexp+] - path definition
162
- # * +block+ [+Proc+] - process to run when route matched
163
- # === Returns
164
- # nil
139
+ # @param [ String ] method HTTP method
140
+ # @param [ String, Regexp ] path path definition
141
+ # @param [ Proc ] block process to run when route matched
142
+ # @return [ nil ] nil
165
143
  def add_route(method, path, block)
166
144
  if path.class == String
167
145
  # Convert String to Regexp to provide performance boost (Precompiled Regexp)
@@ -173,10 +151,11 @@ class Midori::API
173
151
  end
174
152
 
175
153
  # Process after receive data from client
176
- # === Attributes
177
- # * +request+ [+Midori::Request+] - Http Raw Request
178
- # === Returns
179
- # [+Midori::Response+] - Http response
154
+ # @param request [ Midori::Request ] Http Raw Request
155
+ # @param connection [ EM::Connection ] A connection created by EventMachine
156
+ # @yield what to run when route matched
157
+ # @return [ Midori::Response ] Http Response
158
+ # @raise [ Midori::Error::NotFound ] If no route matched
180
159
  def receive(request, connection = nil)
181
160
  @route.each do |route|
182
161
  matched = match(route.method, route.path, request.method, request.path)
@@ -188,8 +167,6 @@ class Midori::API
188
167
  end
189
168
  middlewares.each { |middleware| request = middleware.before(request) }
190
169
  clean_room = Midori::CleanRoom.new(request, middlewares, body_accept)
191
- @helpers ||= []
192
- @helpers.map { |block| clean_room.instance_exec(&block) }
193
170
  if request.websocket?
194
171
  # Send 101 Switching Protocol
195
172
  connection.send_data Midori::Response.new(101, websocket_header(request.header['Sec-WebSocket-Key']), '')
@@ -211,15 +188,13 @@ class Midori::API
211
188
  end
212
189
 
213
190
  # Match route with given definition
214
- # === Attributes
215
- # * +method+ [+String+] - Accepts an HTTP/1.1 method like GET POST PUT ...
216
- # * +path+ [+Regexp+] - Precompiled route definition.
217
- # * +request+ [+String+] - HTTP Request String
218
- # === Returns
219
- # if not matched returns false
220
- #
221
- # else returns an array of parameter string matched
222
- # === Examples
191
+ # @param [ String ] method Accepts an HTTP/1.1 method like GET POST PUT ...
192
+ # @param [ Regexp ] path Precompiled route definition.
193
+ # @param [ String ] request_method HTTP Request Method
194
+ # @param [ String ] request_path HTTP Request Path
195
+ # @return [ Array ] matched parameters
196
+ # @return [ Boolean ] false if not matched
197
+ # @example match a route
223
198
  # match('GET', /^\/user\/(.*?)\/order\/(.*?)$/, '/user/foo/order/bar') # => ['foo', 'bar']
224
199
  def match(method, path, request_method, request_path)
225
200
  if request_method == method
@@ -232,11 +207,9 @@ class Midori::API
232
207
  end
233
208
 
234
209
  # Convert String path to its Regexp equivalent
235
- # === Attributes
236
- # * +path+ [+String+] - String route definition
237
- # === Returns
238
- # Regexp equivalent
239
- # === Examples
210
+ # @param [ String ] path String route definition
211
+ # @return [ Regexp ] Regexp equivalent
212
+ # @example
240
213
  # convert_route('/user/:id/order/:order_id') # => Regexp
241
214
  def convert_route(path)
242
215
  path = '^' + path
@@ -246,13 +219,21 @@ class Midori::API
246
219
  Regexp.new path
247
220
  end
248
221
 
222
+ # Use a middleware in the all routes
223
+ # @param [Class] middleware Inherited from +Midori::Middleware+
224
+ # @return [nil] nil
249
225
  def use(middleware, *args)
250
226
  middleware = middleware.new(*args)
227
+ CleanRoom.class_exec { middleware.helper }
251
228
  @middleware = [] if @middleware.nil?
252
229
  @middleware << middleware
253
230
  @body_accept = middleware.body_accept
231
+ nil
254
232
  end
255
233
 
234
+ # Return websocket header with given key
235
+ # @param [String] key 'Sec-WebSocket-Key' in request header
236
+ # @return [Hash] header
256
237
  def websocket_header(key)
257
238
  {
258
239
  'Upgrade' => 'websocket',
@@ -261,15 +242,17 @@ class Midori::API
261
242
  }
262
243
  end
263
244
 
245
+ # Helper block for defining methods in APIs
246
+ # @yield define what to run in CleanRoom
264
247
  def helper(&block)
265
- @helpers = [] if @helpers.nil?
266
- @helpers << block
248
+ Midori::CleanRoom.class_exec(&block)
267
249
  end
268
250
  end
269
251
 
270
252
  private_class_method :add_route
271
253
 
272
- METHODS = %w(get post put delete options link unlink websocket eventsource).freeze # :nodoc:
254
+ # Constants of supported methods in route definition
255
+ METHODS = %w(get post put delete options link unlink websocket eventsource).freeze
273
256
 
274
257
  # Magics to fill DSL methods through dynamically class method definition
275
258
  METHODS.each do |method|
@@ -1,5 +1,14 @@
1
+ ##
2
+ # This class is used to be sandbox of requests processing.
3
+ # @attr [Fixnum] code HTTP response code
4
+ # @attr [Hash] header HTTP response header
5
+ # @attr [Object] body HTTP response body. String could is accepted by default, but could leave for further process with +Midori::Midlleware+
6
+ # @attr [Midori::Request] request HTTP request
1
7
  class Midori::CleanRoom
2
8
  attr_accessor :code, :header, :body, :request
9
+ # @param [Midori::Request] request HTTP request
10
+ # @param [Array<Midori::Middleware>] middleware middlewares to run
11
+ # @param [Array<Class>] body_accept what class for body could last middleware accept by default
3
12
  def initialize(request, middleware = [], body_accept = [String])
4
13
  @status = 200
5
14
  @header = Midori::Const::DEFAULT_HEADER.clone
@@ -9,15 +18,23 @@ class Midori::CleanRoom
9
18
  @body_accept = body_accept
10
19
  end
11
20
 
21
+ # Genenrate response from variables inside +Midori::CleanRoom+
22
+ # @return [Midori::Response] midori response
12
23
  def raw_response
13
24
  Midori::Response.new(@status, @header, @body)
14
25
  end
15
26
 
27
+ # Add a middleware to a specific route
28
+ # @param [Class] middleware inherited form +Midori::Middleware+ class
29
+ # @param [Array<Object>] args for middleware initialize
30
+ # @return [nil] nil
16
31
  def use(middleware, *args)
17
32
  middleware = middleware.new(*args)
33
+ middleware.helper
18
34
  @middleware = [] if @middleware.nil?
19
35
  @middleware << middleware
20
36
  @body_accept.replace middleware.body_accept
21
37
  @request = middleware.before(request)
38
+ nil
22
39
  end
23
40
  end
@@ -1,4 +1,7 @@
1
+ ##
2
+ # Module for store Midori Consts
1
3
  module Midori::Const
4
+ # Hash table for converting numbers to HTTP/1.1 status code line
2
5
  STATUS_CODE = {
3
6
  100 => '100 Continue',
4
7
  101 => '101 Switching Protocols',
@@ -32,6 +35,7 @@ module Midori::Const
32
35
  415 => '415 Unsupported Media Type',
33
36
  416 => '416 Requested range not satisfiable',
34
37
  417 => '417 Expectation Failed',
38
+ 451 => '451 ',
35
39
  500 => '500 Internal Server Error',
36
40
  501 => '501 Not Implemented',
37
41
  502 => '502 Bad Gateway',
@@ -42,10 +46,12 @@ module Midori::Const
42
46
  STATUS_CODE.default = '500 Internal Server Error'
43
47
  STATUS_CODE.freeze
44
48
 
49
+ # Default header for Basic HTTP response
45
50
  DEFAULT_HEADER = {
46
51
  'Server' => "Midori/#{Midori::VERSION}"
47
52
  }
48
53
 
54
+ # Default header for Evenrsource response
49
55
  EVENTSOURCE_HEADER = {
50
56
  'Content-Type' => 'text-event-stream',
51
57
  'Cache-Control' => 'no-cache',
@@ -1,16 +1,29 @@
1
- module Kernel #:nodoc:
1
+ ##
2
+ # Meta-programming Kernel for Syntactic Sugars
3
+ module Kernel
2
4
  # This method is implemented to dynamically generate class with given name and template.
3
5
  # Referenced from {Ruby China}[https://ruby-china.org/topics/17382]
6
+ # @param [String] name name of class
7
+ # @param [Class] ancestor class to be inherited
8
+ # @yield inner block to be inserted into class
9
+ # @return [Class] the class defined
4
10
  def define_class(name, ancestor = Object)
5
11
  Object.const_set(name, Class.new(ancestor))
6
12
  Object.const_get(name).class_eval(&Proc.new) if block_given?
7
13
  Object.const_get(name)
8
14
  end
9
15
 
16
+ # Define a batch of error handler with given name
17
+ # @param [Array<Symbol>] args names to be defined
18
+ # @return [nil] nil
19
+ # @example
20
+ # define_error(:foo_error, :bar_error)
21
+ # => nil, FooError < StandardError and BarError < StandardError would be defined
10
22
  def define_error(*args)
11
23
  args.each do |arg|
12
24
  class_name = arg.to_s.split('_').collect(&:capitalize).join
13
25
  define_class(class_name, StandardError)
14
26
  end
27
+ nil
15
28
  end
16
29
  end
@@ -1,18 +1,27 @@
1
- require 'logger'
2
-
1
+ ##
2
+ # The main module of Midori
3
3
  module Midori
4
- @logger = ::Logger.new(StringIO.new)
5
-
6
- def self.run(api = Midori::API, ip = nil, port = nil, logger = ::Logger.new(STDOUT))
7
- ip ||= '127.0.0.1'
8
- port ||= 8081
4
+ @logger = ::Logger.new(STDOUT)
5
+ # Start Midori Server instance
6
+ # @note This is an async method, but no callback
7
+ # @param [Class] api Inherit from +Midori::API+
8
+ # @param [String] ip The ip address to bind
9
+ # @param [Fixnum] port Port number
10
+ # @param [Logger] logger Ruby logger
11
+ # @return [nil] nil
12
+ def self.run(api = Midori::API, ip = '127.0.0.1', port = 8081, logger = ::Logger.new(STDOUT))
9
13
  @logger = logger
10
14
  EventMachine.run do
11
15
  @logger.info "Midori #{Midori::VERSION} is now running on #{ip}:#{port}".blue
12
16
  @midori_server = EventMachine.start_server ip, port, Midori::Server, api, logger
13
17
  end
18
+ nil
14
19
  end
15
20
 
21
+ # Stop Midori Server instance
22
+ # @note This is an async method, but no callback
23
+ # @return [Boolean] [true] stop successfully
24
+ # @return [Boolean] [false] nothing to stop
16
25
  def self.stop
17
26
  if @midori_server.nil?
18
27
  @logger.error 'Midori Server has NOT been started'.red
@@ -1,10 +1,20 @@
1
+ ##
2
+ # This module store errors to be handled in Midori
1
3
  module Midori::Error
4
+ # No route matched
2
5
  class NotFound < StandardError; end
6
+ # Midori doesn't support continuous frame of WebSockets yet
3
7
  class ContinuousFrame < StandardError; end
8
+ # WebSocket OpCode not defined in RFC standards
4
9
  class OpCodeError < StandardError; end
10
+ # Websocket request not masked
5
11
  class NotMasked < StandardError; end
12
+ # Websocket frame has ended
6
13
  class FrameEnd < StandardError; end
14
+ # Websocket Ping Pong size too large
7
15
  class PingPongSizeTooLarge < StandardError; end
16
+ # Not sending String in EventSource
8
17
  class EventSourceTypeError < StandardError; end
18
+ # Insert a not middleware class to middleware list
9
19
  class MiddlewareError < StandardError; end
10
20
  end
@@ -1,10 +1,16 @@
1
+ ##
2
+ # This class provides methods for EventSource connection instance.
3
+ # @attr [EM::Connection] connection the connection instance of EventMachine
1
4
  class Midori::EventSource
2
5
  attr_accessor :connection
3
6
 
7
+ # @param [EM::Connection] connection the connection instance of EventMachine
4
8
  def initialize(connection)
5
9
  @connection = connection
6
10
  end
7
11
 
12
+ # Send data and close the connection
13
+ # @param [String] data data to be sent
8
14
  def send(data)
9
15
  raise Midori::Error::EventSourceTypeError unless data.is_a?String
10
16
  @connection.send_data(data.split("\n").map {|str| "data: #{str}\n"}.join + "\n")
@@ -1,15 +1,32 @@
1
+ ##
2
+ # Ancestor of all middlewares
1
3
  class Midori::Middleware
4
+ # Init a middleware
2
5
  def initialize
3
6
  end
4
7
 
8
+ # run before processing a request
9
+ # @param [Midori::Request] request raw request
10
+ # @return [Midori::Request] request to be further processed
5
11
  def before(request)
6
12
  request
7
13
  end
8
14
 
15
+ # run after processing a request
16
+ # @param [Midori::Request] _request raw request
17
+ # @param [Midori::Response] response raw response
18
+ # @return [Midori::Response] response to be further processed
9
19
  def after(_request, response)
10
20
  response
11
21
  end
12
22
 
23
+ # code to be inserted inside CleanRoom
24
+ # @return [nil] nil
25
+ def helper
26
+ end
27
+
28
+ # Acceptable body
29
+ # @return [Array<Class>] array of acceptable type's class
13
30
  def body_accept
14
31
  [String]
15
32
  end
@@ -1,30 +1,52 @@
1
+ ##
2
+ # Meta-programming String for Syntactic Sugars
1
3
  # Referenced from {Qiita}[http://qiita.com/south37/items/99a60345b22ef395d424]
2
4
  class Promise
5
+ # @param [Proc] callback an async method
3
6
  def initialize(callback)
4
7
  @callback = callback
5
8
  end
6
9
 
10
+ # Define what to do after a method callbacked
11
+ # @param [Proc] resolve what if callbacked
12
+ # @param [Proc] reject what if callback failed
13
+ # @return [nil] nil
7
14
  def then(resolve = ->() {}, reject = ->() {})
8
15
  @callback.call(resolve, reject)
9
16
  end
10
17
  end
11
18
 
12
- def async_internal(fiber)
13
- chain = ->(result) {
14
- return if result.class != Promise
15
- result.then(->(val) {
16
- chain.call(fiber.resume(val))
17
- })
18
- }
19
- chain.call(fiber.resume)
20
- end
19
+ module Kernel
20
+ # Logic dealing of async method
21
+ # @param [Fiber] fiber a fiber to call
22
+ def async_internal(fiber)
23
+ chain = lambda do |result|
24
+ return if result.class != Promise
25
+ result.then(lambda do |val|
26
+ chain.call(fiber.resume(val))
27
+ end)
28
+ end
29
+ chain.call(fiber.resume)
30
+ end
21
31
 
22
- def async(method_name, &block)
23
- define_singleton_method method_name, ->(*args) {
24
- async_internal(Fiber.new {block.call(*args)})
25
- }
26
- end
32
+ # Define an async method
33
+ # @param [Symbol] method_name method name
34
+ # @yield async method
35
+ # @example
36
+ # async :hello do
37
+ # puts 'Hello'
38
+ # end
39
+ def async(method_name)
40
+ define_singleton_method method_name, ->(*args) {
41
+ async_internal(Fiber.new { yield(*args) })
42
+ }
43
+ end
27
44
 
28
- def await(promise)
29
- Fiber.yield promise
45
+ # Block the I/O to wait for async method response
46
+ # @param [Promise] promise promise method
47
+ # @example
48
+ # result = await SQL.query('SELECT * FROM hello')
49
+ def await(promise)
50
+ Fiber.yield promise
51
+ end
30
52
  end
@@ -1,8 +1,19 @@
1
+ ##
2
+ # Request class for midori
3
+ # @attr [String] ip client ip address
4
+ # @attr [Fixnum] port client port
5
+ # @attr [String] protocol protocol version of HTTP request
6
+ # @attr [String] path request path
7
+ # @attr [String] query_string request query string
8
+ # @attr [Hash] header request header
9
+ # @attr [String] body request body
10
+ # @attr [Boolean] parsed whether the request parsed
1
11
  class Midori::Request
2
12
  attr_accessor :ip, :port,
3
13
  :protocol, :method, :path, :query_string,
4
14
  :header, :body, :parsed
5
15
 
16
+ # Init Request
6
17
  def initialize
7
18
  @parsed = false
8
19
  @is_websocket = false
@@ -10,8 +21,7 @@ class Midori::Request
10
21
  end
11
22
 
12
23
  # Init an request with StringIO data
13
- # === Attributes
14
- # * +data+ [+StringIO+] - Request data
24
+ # @param [StringIO+] data Request data
15
25
  def parse(data)
16
26
  @header = {}
17
27
 
@@ -46,14 +56,20 @@ class Midori::Request
46
56
  @parsed = true
47
57
  end
48
58
 
59
+ # Syntatic sugur for whether a request is parsed
60
+ # @return [Boolean] parsed or not
49
61
  def parsed?
50
62
  @parsed
51
63
  end
52
64
 
65
+ # Syntatic sugur for whether a request is a websocket request
66
+ # @return [Boolean] websocket or not
53
67
  def websocket?
54
68
  @is_websocket
55
69
  end
56
70
 
71
+ # Syntatic sugur for whether a request is an eventsource request
72
+ # @return [Boolean] eventsource or not
57
73
  def eventsource?
58
74
  @is_eventsource
59
75
  end
@@ -1,18 +1,30 @@
1
+ ##
2
+ # Class for midori response
3
+ # @attr [String] HTTP response status
4
+ # @attr [Hash] HTTP response header
5
+ # @attr [String] HTTP response body
1
6
  class Midori::Response
2
7
  attr_accessor :status, :header, :body
3
8
 
9
+ # @param [Fixnum] code HTTP response code
10
+ # @param [Hash] header HTTP response header
11
+ # @param [String] body HTTP response body
4
12
  def initialize(code = 200, header = Midori::Const::DEFAULT_HEADER.clone, body = '')
5
13
  @status = Midori::Const::STATUS_CODE[code]
6
14
  @header = header
7
15
  @body = body
8
16
  end
9
17
 
18
+ # Generate header string from hash
19
+ # @return [String] generated string
10
20
  def generate_header
11
21
  @header.map do |key, value|
12
22
  "#{key}: #{value}\r\n"
13
23
  end.join
14
24
  end
15
25
 
26
+ # Convert response to raw string
27
+ # @return [String] generated string
16
28
  def to_s
17
29
  "HTTP/1.1 #{@status}\r\n#{generate_header}\r\n#{@body}"
18
30
  end
@@ -1,5 +1,14 @@
1
+ ##
2
+ # Class for Midori route
3
+ # @attr [String] method HTTP method
4
+ # @attr [Regexp] path regex to match
5
+ # @attr [Proc] function what to do after matched
1
6
  class Midori::Route
2
7
  attr_accessor :method, :path, :function
8
+
9
+ # @param [String] method HTTP method
10
+ # @param [Regexp] path regex to match
11
+ # @param [Proc] function what to do after matched
3
12
  def initialize(method, path, function)
4
13
  @method = method
5
14
  @path = path
@@ -1,6 +1,14 @@
1
+ ##
2
+ # Logics to EventMachine TCP Server, running inside +EM::Connection+
3
+ # @attr [Midori::Request] request
4
+ # @attr [Class] api inherited from Midori::API
5
+ # @attr [Midori::WebSocket] websocket websocket instance
6
+ # @attr [Midori::EventSource] eventsource eventsource instance
1
7
  module Midori::Server
2
8
  attr_accessor :request, :api, :websocket, :eventsource
3
9
 
10
+ # @param [Class] api inherited from Midori::API
11
+ # @param [Logger] logger global logger
4
12
  def initialize(api, logger)
5
13
  @api = api
6
14
  @logger = logger
@@ -9,6 +17,8 @@ module Midori::Server
9
17
  @eventsource = Midori::EventSource.new(self)
10
18
  end
11
19
 
20
+ # Logics of receiving data
21
+ # @param [String] data raw data
12
22
  def receive_data(data)
13
23
  ->() { async_internal(Fiber.new do
14
24
  start_time = Time.now
@@ -26,6 +36,8 @@ module Midori::Server
26
36
  end) }.call
27
37
  end
28
38
 
39
+ # Logics of receiving new request
40
+ # @param [String] data raw data
29
41
  def receive_new_request(data)
30
42
  begin
31
43
  @request.parse(data)
@@ -44,6 +56,8 @@ module Midori::Server
44
56
  end
45
57
  end
46
58
 
59
+ # Logics of receiving WebSocket request
60
+ # @param [String] data raw data
47
61
  def websocket_request(data)
48
62
  @websocket.decode(data)
49
63
  case @websocket.opcode
@@ -69,6 +83,9 @@ module Midori::Server
69
83
  close_connection_after_writing
70
84
  end
71
85
 
86
+ # To call a websocket event if it exist
87
+ # @param [Symbol] event event name
88
+ # @param [Array] args arg list
72
89
  def call_event(event, args = [])
73
90
  (-> { @websocket.instance_exec(*args, &@websocket.events[event]) }.call) unless @websocket.events[event].nil?
74
91
  end
@@ -1,20 +1,28 @@
1
+ ##
2
+ # Meta-programming String for Syntactic Sugars
1
3
  class String
4
+ # @param [Fixnum] color_code ANSI color code
5
+ # @return [String] colored string
2
6
  def colorize(color_code)
3
7
  "\e[#{color_code}m#{self}\e[0m"
4
8
  end
5
9
 
10
+ # color the string with red color
6
11
  def red
7
12
  colorize(31)
8
13
  end
9
14
 
15
+ # color the string with green color
10
16
  def green
11
17
  colorize(32)
12
18
  end
13
-
19
+
20
+ # color the string with yellow color
14
21
  def yellow
15
22
  colorize(33)
16
23
  end
17
24
 
25
+ # color the string with blue color
18
26
  def blue
19
27
  colorize(34)
20
28
  end
@@ -1,3 +1,4 @@
1
1
  module Midori
2
- VERSION = '0.0.9.2'.freeze
2
+ # Current Version Code
3
+ VERSION = '0.0.9.3'.freeze
3
4
  end
@@ -1,13 +1,20 @@
1
1
  ##
2
2
  # This class provides methods for WebSocket connection instance.
3
+ # @attr [Array<Fixnum>, String] msg message send from client
4
+ # @attr [Fixnum] opcode operation code of WebSocket
5
+ # @attr [Hash] events response for different event
6
+ # @attr [EM::Connection] connection raw EventMachine connection
3
7
  class Midori::WebSocket
4
8
  attr_accessor :msg, :opcode, :events, :connection
5
9
 
10
+ # @param [EM::Connection] connection raw EventMachine connection
6
11
  def initialize(connection)
7
12
  @events = {}
8
13
  @connection = connection
9
14
  end
10
15
 
16
+ # Decode raw data send from client
17
+ # @param [String] data raw data
11
18
  def decode(data)
12
19
  # Fin and Opcode
13
20
  byte_tmp = data.getbyte
@@ -21,6 +28,8 @@ class Midori::WebSocket
21
28
  decode_mask(data)
22
29
  end
23
30
 
31
+ # Decode masked message send from client
32
+ # @param [String] data raw data
24
33
  def decode_mask(data)
25
34
  # Mask
26
35
  byte_tmp = data.getbyte
@@ -38,10 +47,21 @@ class Midori::WebSocket
38
47
  # data.bytes {|byte| puts byte.to_s(16)}
39
48
  end
40
49
 
50
+ # API definition for events
51
+ # @param [Symbol] event event name(open, message, close, ping, pong)
52
+ # @yield what to do after event matched
53
+ # @example
54
+ # websocket '/websocket' do |ws|
55
+ # ws.on :message do |msg|
56
+ # puts msg
57
+ # end
58
+ # end
41
59
  def on(event, &block) # open, message, close, ping, pong
42
60
  @events[event] = block
43
61
  end
44
62
 
63
+ # Send data
64
+ # @param [Array<Fixnum>, String] msg data to send
45
65
  def send(msg)
46
66
  output = []
47
67
  if msg.is_a?String
@@ -56,19 +76,27 @@ class Midori::WebSocket
56
76
  end
57
77
  end
58
78
 
79
+ # Send a Ping request
80
+ # @param [String] str string to send
59
81
  def ping(str)
60
82
  heartbeat(0b10001001, str)
61
83
  end
62
84
 
85
+ # Send a Pong request
86
+ # @param [String] str string to send
63
87
  def pong(str)
64
88
  heartbeat(0b10001010, str)
65
89
  end
66
90
 
91
+ # Ancestor of ping pong
92
+ # @param [Fixnum] method opcode
93
+ # @param [String] str string to send
67
94
  def heartbeat(method, str)
68
95
  raise Midori::Error::PingPongSizeTooLarge if str.size > 125
69
96
  @connection.send_data [method, str.size, str].pack("CCA#{str.size}")
70
97
  end
71
98
 
99
+ # Close a websocket connection
72
100
  def close
73
101
  raise Midori::Error::FrameEnd
74
102
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-midori
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9.2
4
+ version: 0.0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - HeckPsi Lab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-21 00:00:00.000000000 Z
11
+ date: 2016-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eventmachine